最近的主要就是在写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_native
和from_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
其实在上面写的这种简单情况的时候,我们可以使用ModelSerializer
的PrimaryKeyRelatedField
,但是数据库结构一复杂就会导致ModelSerializer
没法用了,只能自己去写serializer。
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。