【问题标题】:How to deserialize foreignkey with django rest framework?如何使用 django rest 框架反序列化外键?
【发布时间】:2014-09-16 19:30:39
【问题描述】:

例如

class People(models.Model):
    name = models.CharField(max_length=20)

class Blog(models.Model):
    author = models.ForeignKeyField(People)
    content = models.TextField()

然后,

class CreateBlogSerializer(serializers.Serializer):
    #author id
    author = serializers.IntegerField()
    content = serializers.TextField()

在视图中,我需要获取 author_id ,检查 id 是否存在并获取作者实例,这样做很麻烦。

serializer = CreateBlogSerializer(data=request.DATA)
if serializer.is_valid():
    try:
        author = Author.objects.get(pk=serializer.data["author"])
    except Author.DoesNotExist:
        return Response(data={"author does not exist"})
    blog = Blog.objects.create(author=author, content=serializer.data["content"])

是否有 ForeignKeyField 用于反序列化和验证主键数据,然后返回一个实例。

class CreateBlogSerializer(serializers.Serializer):
    author = serializers.ForeignKeyField(Author)
    content = serializers.TextField()

serializer = CreateBlogSerializer(data=request.DATA)
if serializer.is_valid():
    #after deserialization , the author id becomes author model instance
    blog = Blog.objects.create(author=serializer.data["author"], content=serializer.data["content"])
else:
    #the author id does not exist will cause serializer.is_valid=Flase

PS

我知道ModelSerializer中的PrimaryKeyRelatedField,但是这里不能使用ModelSerializer,模型结构复杂,以上只是例子。

我的第一个想法是写一个客户字段。

【问题讨论】:

  • 这篇文章中途您是否将People 切换为Author
  • 在创建Blog 之前,您是否只想检查对于任何给定的Blog 数据库中是否存在Author/People 值?
  • @isomarcte 是的,我想在序列化程序中这样做,然后序列化程序给我一个模型实例。它可以减少重复代码。

标签: django django-rest-framework


【解决方案1】:
class ForeignKeyField(WritableField):

    def __init__(self, model_name, *args, **kwargs):
        super(ForeignKeyField, self).__init__(*args, **kwargs)
        self.model_name = model_name
        self.model_instance = None

    def from_native(self, pk):
        if not isinstance(pk, int):
            raise ValidationError("pk must be int")
        try:
            self.model_instance = self.model_name.objects.get(pk=pk)
            return self.model_instance
        except self.model_name.DoesNotExist:
            raise ValidationError('object does not exist')

    def to_native(self, obj):
        return self.model_instance

我破解了它,但我不知道它为什么会起作用。

用法: 有一点区别

class t_serializer(serializers.Serializer):
    author = ForeignKeyField(Author)

@api_view(["POST"])
def func(request):
    serializer = t_serializer(data=request.DATA)
    if serializer.is_valid():
        print isinstance(serializer.data["author"], Author)
        #print True
    else:
        print serializer.errors

【讨论】:

  • 你在修改 Django 源码吗?
  • @isomarcte 不,我写了 ForeignKeyField。
  • 我明白了。我认为在 Django 源代码中有一个同名的类。
【解决方案2】:

看来你想要的是自定义验证码。

对于这个特定的实例,您可以编写以下内容。

class CreateBlogSerializer(serializers.Serializer):
    author = serializers.ForeignKeyField(Author)
    content = serializers.TextField()

    def validate_author(self, attrs, source):
        """
        Verify that the author exists.
        """
        author = attrs[source]
        if Author.objects.filter(pk=author).exists():
            return attrs
        raise serializers.ValidationError("Specified Author does not exist!")

现在,当您致电 serializer.is_valid() 时,将进行此检查。

因此您可以在代码的其他地方执行此操作,

if serializer.is_valid():
     blog = Blog.objects.create(author=serializer.data["author"], content=serializer.data["content"])

并确保如果创建了给定的blog,则数据库中已经存在对应的Author

详细说明

所以 Django Rest Framework 提供了一种向序列化程序添加自定义验证的方法。这可以通过在序列化程序类validate_<field name> 中提供以下格式的方法来完成。这些方法会将source 值设置为给定字段的名称,在我们的示例中为author,然后可以与attrs 变量一起使用以获取字段的当前值(attrs 包含所有值传递给序列化程序)。

这些验证方法都被调用,然后serializer.is_valid() 方法被调用。如果给定的测试通过,他们应该只返回attrs,否则提出ValidationError

它们可能会有些复杂,因此最好阅读此处的完整文档,http://www.django-rest-framework.org/api-guide/serializers#validation

【讨论】:

  • 谢谢,但我想在序列化程序中进行验证,请参阅下面的答案。
  • @virusdefender 验证是在我的回答中的序列化程序中完成的。这些验证方法是序列化程序类上的方法
猜你喜欢
  • 2021-04-08
  • 1970-01-01
  • 1970-01-01
  • 2017-01-07
  • 1970-01-01
  • 2021-06-22
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多