最近的主要就是在寫rest api,不少地方是多表關聯的外鍵,而後api傳遞給你的就只是另外一張表裏面記錄的id,而後你再去查詢,判斷記錄是否存在,而後處理,這樣以爲很麻煩。代碼大體是這樣的python
#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是這樣的api
class CreateBlogSerializer(serializers.Serializer): #author id author = serializers.IntegerField() content = serializers.TextField()
這樣的話,進入views,post
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
看了看rest framework的文檔,例子都是很簡單的邏輯構成的,沒有什麼外鍵或者多對多的關係,這個固然好寫。code
最後發現本身能夠去繼承WritableField
自定義一個serializer,可是裏面有兩個方法to_native
和from_native
這個到如今沒搞懂是怎麼個執行順序,連rest framework源代碼都看了一點,也沒有搞懂,算了,反正能工做就行。blog
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。文檔