gpt4 book ai didi

python - Django Rest Framework - TaggableManager 字段的反序列化

转载 作者:太空宇宙 更新时间:2023-11-03 19:41:28 26 4
gpt4 key购买 nike

我用了django-taggit向我的模型添加标签。 Django版本:2.2.10,Python版本:3.8.1

现在我正在尝试将标签与 django Rest-framework 集成,例如创建/更新/删除带/不带标签的模型实例。

我的问题:我无法(通过rest api)使用标签创建模型的新实例。我可以毫无问题地获取模型实例。

我的模型.py:

from taggit.managers import TaggableManager

class Task(models.Model):
name = models.CharField(max_length=100, blank=False)
...
tags = TaggableManager(blank=True)

def get_tags(self):
""" names() is a django-taggit method, returning a ValuesListQuerySet
(basically just an iterable) containing the name of each tag as a string
"""
return self.tags.names()

def __str__(self):
return self.title

我的序列化器.py:

class TagsField(serializers.Field):
""" custom field to serialize/deserialize TaggableManager instances.
"""
def to_representation(self, value):
""" in drf this method is called to convert a custom datatype into a primitive,
serializable datatype.

In this context, value is a plain django queryset containing a list of strings.
This queryset is obtained thanks to get_tags() method on the Task model.

Drf is able to serialize a queryset, hence we simply return it without doing nothing.
"""
return value

def to_internal_value(self, data):
""" this method is called to restore a primitive datatype into its internal
python representation.

This method should raise a serializers.ValidationError if the data is invalid.
"""
return data

class TaskSerializer(serializers.ModelSerializer):

# tags field in Task model is implemented via TaggableManager class from django-taggit.
# By default, drf is not able to serialize TaggableManager to json.
# get_tags() is a method of the Task model class, which returns a Queryset containing
# the list of tags as strings. This Queryset can be serialized without issues.
tags = TagsField(source="get_tags")

class Meta:
model = Task
fields = [
"name",
...,
"tags",
]

每当我尝试通过 POST api 创建任务模型的新实例时,都会收到以下错误:

TypeError at /taskdrop/v1/task/
Got a `TypeError` when calling `Task.objects.create()`. This may be because you have a writable field on the serializer class that is not a valid argument to `Task.objects.create()`. You may need to make the field read-only, or override the TaskSerializer.create() method to handle this correctly.
Original exception was:
Traceback (most recent call last):
File "/home/daniele/prj/ea/TaskDrop/venv/lib/python3.8/site-packages/rest_framework/serializers.py", line 948, in create
instance = ModelClass._default_manager.create(**validated_data)
File "/home/daniele/prj/ea/TaskDrop/venv/lib/python3.8/site-packages/django/db/models/manager.py", line 82, in manager_method
return getattr(self.get_queryset(), name)(*args, **kwargs)
File "/home/daniele/prj/ea/TaskDrop/venv/lib/python3.8/site-packages/django/db/models/query.py", line 420, in create
obj = self.model(**kwargs)
File "/home/daniele/prj/ea/TaskDrop/venv/lib/python3.8/site-packages/django/db/models/base.py", line 501, in __init__
raise TypeError("%s() got an unexpected keyword argument '%s'" % (cls.__name__, kwarg))
TypeError: Task() got an unexpected keyword argument 'get_tags'

我现在有点卡住了......该字段绝对不是只读的,并且关于覆盖 TaskSerializer.create() 方法,我不知 Prop 体该怎么做。

另外,我对 TagsField(serializers.Field) 与 .create() 方法重写有点困惑。根据我的理解,如果我创建自定义序列化器字段,则不需要额外重写 .create()。

最后,我尝试使用django-taggit-serializer不成功:模型已创建,但传递的标签丢失。

我该如何解决这个问题?谢谢。

最佳答案

好的,我成功了。

将解决方案留给其他人:

我得到的原因 TypeError: Task() got an Unexpected keywords argument 'get_tags' 是因为 drf 试图使用 to_internal_value() 的返回值来填充 'get_tags' 字段我的模型。

现在,“get_tags”只是我的模型任务类的方法名称,而不是真正的字段,因此会出现错误。当我在序列化器中使用 tags = TagsField(source="get_tags") 时,Drf 了解到“get_tags”作为字段名称。

我通过重写序列化器的 create() 方法解决了这个问题,方法如下:

class TaskSerializer(serializers.ModelSerializer):

# tags field in Task model is implemented via TaggableManager class from django-taggit.
# By default, drf is not able to serialize TaggableManager to json.
# get_tags() is a method of the Task model class, which returns a Queryset containing
# the list of tags as strings. This Queryset can be serialized without issues.
tags = TagsField(source="get_tags")
# variables = VariableSerializer()

def create(self, validated_data):
# using "source=get_tags" drf "thinks" get_tags is a real field name, so the
# return value of to_internal_value() is used a the value of a key called "get_tags" inside validated_data dict. We need to remove it and handle the tags manually.
tags = validated_data.pop("get_tags")
task = Task.objects.create(**validated_data)
task.tags.add(*tags)

return task

class Meta:
model = Task
# we exclude all those fields we simply receive from Socialminer
# whenever we get a task or its status
fields = [
"name",
...
"tags",
]

关于python - Django Rest Framework - TaggableManager 字段的反序列化,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/60400513/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com