python - 创建对象时自动创建Tag对象,Django REST Framework

标签 python django rest django-rest-framework

我有任务模型:

class Task(models.Model):
    name = models.CharField(max_length=200, blank=True)
    description = models.TextField(max_length=1000, blank=True)
    completed = models.BooleanField(default=False)
    date_created = models.DateField(auto_now_add=True)
    due_date = models.DateField(null=True, blank=True)
    date_modified = models.DateField(auto_now=True)
    tasklist = models.ForeignKey(Tasklist, null=True, related_name='tasks', on_delete=models.CASCADE)
    tags = models.ManyToManyField(TaskType, related_name='tasks')

以及 TaskType 类(换句话说,标签):

class TaskType(models.Model):
    name = models.CharField(max_length=200)

我还有 TaskSerializer:

class TaskSerializer(serializers.ModelSerializer):
    tags = serializers.SlugRelatedField(many=True, slug_field='name', queryset=TaskType.objects.all())

    class Meta:
        model = Task
        fields = '__all__'
        read_only_fields = ('date_created', 'date_modified', 'tasklist')

当我创建任务时,要添加一些标签,我需要首先在适当的 View 中创建它们,但我希望它们能够动态创建。 因此,在编辑任务时,我添加了 update 方法:

def update(self, request, *args, **kwargs):
    instance = self.get_object()
    tag_names = request.data.get('tags', [])
    for tag_name in tag_names:
        tag, created = TaskType.objects.get_or_create(name=tag_name)
        instance.tags.add(tag)

    serializer = self.serializer_class(instance=instance, data=request.data)
    serializer.is_valid(raise_exception=True)
    serializer.save()
    return Response(serializer.data)

它工作正常,但是当我在创建新任务时添加新标签时,它失败了(400 错误请求):

{
    "tags": [
        "Object with name=%new_tag% does not exist."
    ]
}

我发现在使用标签对象创建任务之前创建适当的标签对象是一个好方法,因此我添加了 perform_create 方法:

def perform_create(self, serializer):
    print('debug')
    tag_names = self.request.data.get('tags', [])
    for tag_name in tag_names:
        tag, created = TaskType.objects.get_or_create(name=tag_name)

    list_id = self.kwargs.get('list_id', None)
    try:
        tasklist = Tasklist.objects.get(pk=list_id)
    except Tasklist.DoesNotExist:
        raise NotFound()
    serializer.save(tasklist=tasklist)

这对我没有帮助,实际上我不确定是否至少调用了 Perform_create 方法,因为我在控制台中没有看到 print('debug') (当我使用现有标签创建任务时,我看到它)。 所以问题是如何更改perform_create方法以便能够创建新的任务而无需先创建标签。

最佳答案

首先,您不需要在 View 方法中手动添加标记。序列化器将为您完成此操作。

其次,当您更新模型时,会使用update方法。当创建时,您需要重写create方法,perform_create可以工作,但发生得太晚了:

def create(self, request, *args, **kwargs):
    tag_names = request.data.get('tags', [])
    for tag_name in tag_names:
        TaskType.objects.get_or_create(name=tag_name)

    serializer = self.serializer_class(data=request.data)
    serializer.is_valid(raise_exception=True)
    serializer.save()
    return Response(serializer.data)

第三,创建新标签后,调用 super().*method* 并让框架为您完成工作:

def update(self, request, *args, **kwargs):
    tag_names = request.data.get('tags', [])
    for tag_name in tag_names:
        TaskType.objects.get_or_create(name=tag_name)

    return super().update(request, *args, **kwargs)

def create(self, request, *args, **kwargs):
    tag_names = request.data.get('tags', [])
    for tag_name in tag_names:
        TaskType.objects.get_or_create(name=tag_name)

    return super().create(request, *args, **kwargs)

如果您计划使用 PATCH 方法,还需要添加 partial_update 方法,因此您最好覆盖序列化器的 to_internal_value 方法,而不是每个方法那些:

class TaskSerializer(serializers.ModelSerializer):
    tags = serializers.SlugRelatedField(
        many=True, slug_field='name', queryset=TaskType.objects.all())

    class Meta:
        model = Task
        fields = '__all__'
        read_only_fields = ('date_created', 'date_modified', 'tasklist')

    def to_internal_value(self, data):
        for tag_name in data.get('tags', []):
            TaskType.objects.get_or_create(name=tag_name)
        return super().to_internal_value(data)

关于python - 创建对象时自动创建Tag对象,Django REST Framework,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/44205914/

相关文章:

来自 fileconfig 的 Python 自定义日志处理程序

mysql - 在django中使用多个数据库并获取表不存在错误

python - Django 分页适用于第一页,不适用于第二页

ios - Swift:REST JSON Get 请求带身份验证

java - 没有类型转换器可用于从类型 : <<pojo>> to the required type: java. io.InputStream 转换为值

python - x 轴上时间戳的格式

python - 在 matplotlib 子图中只绘制图例

django - 如何强制 Django 创建具有特定排序规则的测试数据库?

c# - REST Web 服务 - 获取和创建的不同类型

python - Pandas 的年化返回率