ValueError: Please move the function into main module body to use migrations

Posted

技术标签:

【中文标题】ValueError: Please move the function into main module body to use migrations【英文标题】:ValueError: Please move the function into the main module body to use migrations 【发布时间】:2019-09-29 05:30:41 【问题描述】:

我正在尝试修复的错误

ValueError:在posts.models 中找不到函数func。 请注意,由于 Python 2 的限制,您不能序列化未绑定的方法函数(例如,在同一类主体中声明和使用的方法)。请将该功能移动到主模块主体中以使用迁移。 有关详细信息,请参阅 https: //docs.djangoproject.com/en/1.11/topics/migrations/#serializing-values

简介:我正在使用 Django==1.11.20 和 Ubuntu 18.04。我的 python 版本是 3.6.7 当我在我的 Django 项目中做

(venv)some_path$ python --version
Python 3.6.7

但是,当我在我的 Ubuntu 终端中执行相同操作时,我得到了

marco@VB:~$ python --version
Python 2.7.15rc1

marco@VB:~$ python3 --version
Python 3.6.7

关于我的项目:我有以下模型

def upload_name (user_fld='user', prefix=None):
    def func(instance, fname):
        #return os.path.join(prefix, fname) if prefix else fname
        attrs = user_fld.split('.')
        user = instance
        print ("Getattr %s %s" % (attrs, user))
        try:
            for attr in attrs:
                user = getattr(user, attr)
        except:
            username = 'anon'
        else:
            username = user.username

        print ("Upload name** %s, %s" % (instance.pk, username))
        # Extract the raw fname
        fparts = fname.split('.')
        base = fparts[0]
        try:
            atoms = base.split("_")
            ts = datetime.strptime('_'.join(atoms[-7:]), "%Y_%m_%d_%H_%M_%S_%f")
            ousername = atoms[-8]
            base = '_'.join(atoms[:-8])
        except:
            # Any exception in handling this means it wasn't already equipped with our
            # extension so add it on
            pass

        ts = datetime.now()
        fname = '%s_%s_%s%s' % (base, username, ts.strftime("%Y_%m_%d_%H_%M_%S_%f"),
                                ('.%s' % '.'.join(fparts[1:])) if len(fparts) > 1 else '')
        return os.path.join(prefix, fname) if prefix else fname

    return func

class Post(models.Model):
    user = models.ForeignKey(User, related_name='posts')
    title = models.CharField(max_length=250, unique=True)
    slug = models.SlugField(allow_unicode=True, unique=True, max_length=500)
    post_image = models.ImageField(null=True, blank=True, upload_to=upload_name())

class Prep (models.Model): #(Images)
    post = models.ForeignKey(Post, on_delete=models.CASCADE, related_name='post_prep')
    image = models.ImageField(upload_to=upload_name('post.user', 'images/'), blank=True, null=True, default='')
    image_title = models.CharField(max_length=100, default='')

试图弄清楚如何添加 deconstruct() 方法

https://docs.djangoproject.com/en/1.11/topics/migrations/#adding-a-deconstruct-method

尝试@RaydelMiranda 解决方案

def upload_name_factory(instance, fname, user_fld='user', prefix=None):
    attrs = user_fld.split('.')
    user = instance
    print("Getattr %s %s" % (attrs, user))
    try:
        for attr in attrs:
            user = getattr(user, attr)
    except:
        username = 'anon'
    else:
        username = user.username

    print("Upload name** %s, %s" % (instance.pk, username))
    # Extract the raw fname
    fparts = fname.split('.')
    base = fparts[0]
    try:
        atoms = base.split("_")
        ts = datetime.strptime('_'.join(atoms[-7:]), "%Y_%m_%d_%H_%M_%S_%f")
        ousername = atoms[-8]
        base = '_'.join(atoms[:-8])
    except:
        # Any exception in handling this means it wasn't already equipped with our
        # extension so add it on
        pass

    ts = datetime.now()
    fname = '%s_%s_%s%s' % (base, username, ts.strftime("%Y_%m_%d_%H_%M_%S_%f"),
                            ('.%s' % '.'.join(fparts[1:])) if len(fparts) > 1 else '')
    return os.path.join(prefix, fname) if prefix else fname


upload_name = partial(upload_name_factory, user_fld='user', prefix=None)

【问题讨论】:

问题是 Django 使用 reference,因此你不能使用这样的包装方法。 @PatrickArtner 我没有混合它们。 Ubuntu 18.04 默认使用 Python 2.7。我的项目正在使用 3.6 我不认为这应该是一个问题,因为我的项目显示 3.6。我不知道为什么 2.7 会参与进来 @WillemVanOnsem 有什么我可以解决的问题。我曾经用 image_name_admin_2019_04_28_02_08_32_204448.jpg 之类的名称保存我的图像 @PatrickArtner 我在上面添加了一张图片。我相信它使用的是3.6。加上pycharm终端也说3.6 【参考方案1】:

我明白你想要做什么,你希望能够重用传递给 upload_to 的函数,能够自定义 user_fldprefix 参数。

所以,您已经知道必须将函数移至主模块主体。如何做到这一点并保持您对可重用性的想法?

部分函数。

from django.db import models
from functools import partial

def upload_name_factory(instance, filename, user_fld='user', prefix=None):
    attrs = user_fld.split('.')
    user = instance
    # ...

upload_name = partial(upload_name_factory, user_fld='user', prefix="/some/prefix/")

class Foo(models.Model):
    f = models.FileField(upload_to=upload_name)  

阅读有关部分的更多信息here。

【讨论】:

我已经在顶部尝试了您的解决方案。我做对了吗 不,只要把func的主体变成upload_name_factory的主体,用这个解决方案你就不需要内部函数了 我已经编辑了答案以便给你一个更好的主意 我已经编辑了我的代码,也见上面的问题。现在我收到以下错误TypeError: upload_name_factory() missing 2 required positional arguments: 'instance' and 'fname' what about: def upload_name(instance, filename): return upload_name_factory(instance, filename, user_fld='user', prefix="/some/prefix/")

以上是关于ValueError: Please move the function into main module body to use migrations的主要内容,如果未能解决你的问题,请参考以下文章