1

最近的主要就是在写rest api,很多地方是多表关联的外键,然后api传递给你的就只是另一张表里面记录的id,然后你再去查询,判断记录是否存在,然后处理,这样觉得很麻烦。代码大致是这样的

#models.py
class People(models.Model):
    name = models.CharField(max_length=20)
    sex = models.CharField(max_length=3)

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

在创建Blog的时候,我们post的数据大致是这样的

{
    "author": 1, 
    "content": "Hello world"
}

然后我的serializer是这样的

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

这样的话,进入views,

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"])

因为这样的情况很多,每次在views里面这样查询是很麻烦的,我就想把这个验证的工作放到serializer里面完成,然后返回给我一个ValidationError或者这个model的instance。这样就能省略很多的代码了。

看了看rest framework的文档,例子都是很简单的逻辑构成的,没有什么外键或者多对多的关系,这个当然好写。

最后发现自己可以去继承WritableField自定义一个serializer,但是里面有两个方法to_nativefrom_native这个到现在没搞懂是怎么个执行顺序,连rest framework源代码都看了一点,也没有搞懂,算了,反正能工作就行。

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

然后我们的views就这样干净利索了

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

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

PS
其实在上面写的这种简单情况的时候,我们可以使用ModelSerializerPrimaryKeyRelatedField,但是数据库结构一复杂就会导致ModelSerializer没法用了,只能自己去写serializer。


virusdefender
216 声望7 粉丝

引用和评论

0 条评论