Serenity
Serenity

Reputation: 4054

ValueError: Cannot serialize function: lambda while using makemigrations

When I do python manage.py makemigrations, i get above error and I am unsure where the error is happening. I saw some post regarding this issue but i find mainly in DateTimeField() where the function was passed but in my case I have used auto_now attribute instead of some datetime related function.

However, I have used lambda function in the class method as follow.

@classmethod
    def get_content_models(cls):
        """
        Return all Package subclasses.
        """
        is_content_model = lambda m: m is not Package and issubclass(m, Package)


def set_helpers(self, context):
    current_package_id = getattr(current_package, "id", None)
    current_parent_id = getattr(current_package, "parent_id", None)
    self.is_current_child = self.parent_id == current_package_id
    self.is_child = self.is_current_child

    def is_c_or_a(package_id):
        parent_id = context.get("_parent_package_ids", {}).get(package_id)
        return self.id == package_id or (parent_id and is_c_or_a(parent_id))
    self.is_current_or_ascendant = lambda: bool(is_c_or_a(current_package_id))

I am not clear on this issue, So i have posted for understanding the cause. Is above code creating that issue? If it is the cause, what should be done instead?

I don't know where exactly this issue lies in the models so here is the detail of models.py of package app in gist because the code is a bit huge . It is not reached to booking models so I am only putting the code of package app and here it is

https://gist.github.com/SanskarSans/51d2f287309a97163e680cc38abd3e06

UPDATE

In my Package models, I have used the custom field and in that field there was the use of lambda instead of callable function and that was creating an issue. Due to the long file of models, I did not paste it here, I apologize for that.

Here what I had done

in_menus = MenusField(_("Show in menus"), blank=True, null=True)

class MenusField(MultiChoiceField):
    """
    ``MultiChoiceField`` for specifying which menus a package should
    appear in.
    """

    def __init__(self, *args, **kwargs):
        choices = [t[:2] for t in getattr(settings, "PAGE_MENU_TEMPLATES", [])]
        default = getattr(settings, "PAGE_MENU_TEMPLATES_DEFAULT", None)
        if default is None:
            default = [t[0] for t in choices]
        elif not default:
            default = None
        if isinstance(default, (tuple, list)):
            d = tuple(default)
            # this lambda should be avoided
            # default = lambda:d 
            default = default_value(d)
        defaults = {"max_length": 100, "choices": choices, "default": default}
        defaults.update(kwargs)
        super(MenusField, self).__init__(*args, **defaults)

Upvotes: 8

Views: 2707

Answers (3)

caot
caot

Reputation: 3318

The follows might be helpful to others in the future.

It worked to change the lambda expression into a function.

The following square_root and square_root_lambda worked the same:

def square_root(x):
    return math.sqrt(x)

square_root_lambda = lambda x: math.sqrt(x)


print(square_root(4))
print(square_root_lambda(4))

Upvotes: 0

jmunsch
jmunsch

Reputation: 24089

An example replacing the lambda with a function.

Borken version:

class SomeModel(ParentModel):
    thing_to_export = ArrayField(models.CharField(max_length=50), 
                                 default=lambda: ['Default thing'])

Working version:

def default_thing():
    return ['THIS IS A DEFAULT']

class SomeModel(ParentModel):
    thing_to_export = ArrayField(models.CharField(max_length=50), 
                                 default=default_thing)

Upvotes: 2

Paul Cornelius
Paul Cornelius

Reputation: 10906

I assume you are using the pickle module for serialization.

You cannot pickle the class in which set_helpers is defined. That method sets self.is_current_or_ascendant to a lambda function, and those are on the list of things that cannot be pickled (see 12.1.4 in https://docs.python.org/3/library/pickle.html).

The class method cannot be a problem since it only defines one local variable, is_content_model, which immediately goes out of scope and gets deleted. In fact that method, as you presented it here, does nothing at all.

Upvotes: 0

Related Questions