本身hack了一個django rest framework的ForeignKeyField

最近的主要就是在寫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_nativefrom_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
其實在上面寫的這種簡單狀況的時候,咱們可使用ModelSerializerPrimaryKeyRelatedField,可是數據庫結構一複雜就會致使ModelSerializer無法用了,只能本身去寫serializer。文檔

相關文章
相關標籤/搜索