如何解决如何在 Django 中使用函子而不是函数?
我有一个名为 Story 的模型:
from django.db import models
from api import settings
from core.functions import UploadImage
from .settings import STORY_UPLOAD_PATH
get_story_upload_path = UploadImage(STORY_UPLOAD_PATH)
class Story(models.Model):
user = models.ForeignKey(settings.AUTH_USER_MODEL,on_delete=models.CASCADE)
image = models.ImageField(upload_to=get_story_upload_path)
caption = models.TextField()
expiration_date = models.DateTimeField()
import datetime
import uuid
import os
上传照片的行为对于多个模型是相同的,因此我决定制作一个函子来保存上传路径并将其传递给具有共同行为的模型。
函子:
import datetime
import uuid
import os
class UploadImage:
def __init__(self,upload_path):
self.upload_path = upload_path
def __call__(self,instance,filename):
filename = f'{datetime.datetime.now()}_{uuid.uuid4()}_{filename}'
return os.path.join(self.upload_path,instance.username,filename)
序列化器类:
from rest_framework import serializers
from models import Story,ViewedStory
class StorySerializer(serializers.ModelSerializer):
class Meta:
model = Story
fields = ('id','user','image','caption')
read_only_fields = ('id',)
当我尝试进行迁移时,出现此错误:
Migrations for 'stories':
stories/migrations/0001_initial.py
- Create model Story
- Create model ViewedStory
Traceback (most recent call last):
File "manage.py",line 22,in <module>
main()
File "manage.py",line 18,in main
execute_from_command_line(sys.argv)
File "/usr/local/lib/python3.8/dist-packages/django/core/management/__init__.py",line 419,in execute_from_command_line
utility.execute()
File "/usr/local/lib/python3.8/dist-packages/django/core/management/__init__.py",line 413,in execute
self.fetch_command(subcommand).run_from_argv(self.argv)
File "/usr/local/lib/python3.8/dist-packages/django/core/management/base.py",line 354,in run_from_argv
self.execute(*args,**cmd_options)
File "/usr/local/lib/python3.8/dist-packages/django/core/management/base.py",line 398,in execute
output = self.handle(*args,**options)
File "/usr/local/lib/python3.8/dist-packages/django/core/management/base.py",line 89,in wrapped
res = handle_func(*args,**kwargs)
File "/usr/local/lib/python3.8/dist-packages/django/core/management/commands/makemigrations.py",line 190,in handle
self.write_migration_files(changes)
File "/usr/local/lib/python3.8/dist-packages/django/core/management/commands/makemigrations.py",line 227,in write_migration_files
migration_string = writer.as_string()
File "/usr/local/lib/python3.8/dist-packages/django/db/migrations/writer.py",line 141,in as_string
operation_string,operation_imports = OperationWriter(operation).serialize()
File "/usr/local/lib/python3.8/dist-packages/django/db/migrations/writer.py",line 99,in serialize
_write(arg_name,arg_value)
File "/usr/local/lib/python3.8/dist-packages/django/db/migrations/writer.py",line 51,in _write
arg_string,arg_imports = MigrationWriter.serialize(item)
File "/usr/local/lib/python3.8/dist-packages/django/db/migrations/writer.py",line 271,in serialize
return serializer_factory(value).serialize()
File "/usr/local/lib/python3.8/dist-packages/django/db/migrations/serializer.py",line 39,in serialize
item_string,item_imports = serializer_factory(item).serialize()
File "/usr/local/lib/python3.8/dist-packages/django/db/migrations/serializer.py",line 201,in serialize
return self.serialize_deconstructed(path,args,kwargs)
File "/usr/local/lib/python3.8/dist-packages/django/db/migrations/serializer.py",line 88,in serialize_deconstructed
arg_string,arg_imports = serializer_factory(arg).serialize()
File "/usr/local/lib/python3.8/dist-packages/django/db/migrations/serializer.py",line 353,in serializer_factory
raise ValueError(
ValueError: Cannot serialize: <core.functions.UploadImage object at 0x7f369fbb27f0>
There are some values Django cannot serialize into migration files.
For more,see https://docs.djangoproject.com/en/3.2/topics/migrations/#migration-serializing
为什么会发生这种情况,我该如何解决?
解决方法
迁移是包含旧定义的 Python 文件 模型 - 因此,要编写它们,Django 必须获取当前状态 您的模型并将它们序列化到一个文件中。
这意味着 Django 需要序列化模型中使用的所有东西。由于 get_story_upload_path
是 UploadImage
的实例,因此您自己为 Django 编写的类显然不知道如何序列化它。
文档中也提到了解决这个问题的方法是 Add a deconstruct() method。如果类本身的构造函数的所有参数都是可序列化的,我们可以简单地使用 deconstructible
装饰器代替。此外,我们还需要添加一个 __eq__
方法,以便迁移系统可以知道何时需要进行新的迁移。因此,您可以按如下方式更改类 UploadImage
,以便它可以被序列化:
from django.utils.deconstruct import deconstructible
@deconstructible
class UploadImage:
def __init__(self,upload_path):
self.upload_path = upload_path
def __call__(self,instance,filename):
filename = f'{datetime.datetime.now()}_{uuid.uuid4()}_{filename}'
return os.path.join(self.upload_path,instance.username,filename)
def __eq__(self,other):
return isinstance(other,self.__class__) and self.upload_path == other.upload_path
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。