Django REST Framework API Guide 05

本節大綱html

  一、Serializer fieldspython

  二、Serializer relationsshell

 

Serializer fields 

1、serializer 字段定義在fields.py文件內
二、導入from rest_framework import serializers
三、引用serializers.<FieldName>

核心參數

read_only django

# 默認是False,True的時候在序列化顯示的時候展現,在反序列化實例進行建立或者更新的時候不被使用。

write_onlyapi

# 默認是false,True的時候能夠用來更新或者建立實例,在序列化呈現的時候不顯示

requiredapp

# 默認是True,False的時候能夠遺漏此字段,若是不存在,就不會顯示

defaultide

# 提供一個默認值

allow_null測試

# 默認是false

sourceui

# 默認指向字段名;EmailField(source='user.email');URLField(source='get_absolute_url')
# source='*' 有一個特殊的含義,要用來顯示整個對象,在嵌套展現的時候頗有用

validatorurl

# 驗證器,經過返回數據,不經過引起報錯,Django內置的serializers.ValidationError

error_messages

# 錯誤信息的字典

label

# 標籤,能夠用來當HTML標籤的表單字段

help_text

# 幫助提示

initial

# 預填充字段值
import datetime
from rest_framework import serializers
class ExampleSerializer(serializers.Serializer):
    day = serializers.DateField(initial=datetime.date.today)

style

# 用來控制字段的渲染
# Use <input type="password"> for the input.
password = serializers.CharField(
    style={'input_type': 'password'}
)

# Use a radio input instead of a select input.
color_channel = serializers.ChoiceField(
    choices=['red', 'green', 'blue'],
    style={'base_template': 'radio.html'}
)

 

主要仍是由於相關的字段太多,樓主以爲不必一次性看好,有需求的時候查找可能會更好一點。

http://www.django-rest-framework.org/api-guide/fields/

 

 

Serializer relations

關係字段,顧名思義,用來表示模型之間的關係,能夠用ForeignKey, ManyToManyField和OneToOneField來表示關係,客製化關係能夠用GenericForeignKey

關係字段是在relations.py文件內申明的,可是你應該從serializers模塊導入,使用from rest_framework import serializers而後serializers.<FieldName>

Inspecting relationships

打開pycharm的python console或者在terminal啓動python3 manage.py shell輸入

from app01.serializers import PersonModelSerializer
serializer = PersonModelSerializer()
print(repr(serializer))
PersonModelSerializer(): id = IntegerField(label='ID', read_only=True)
    name = CharField(max_length=128)
    age = IntegerField()
    get_gender = ReadOnlyField()
    get_job = ReadOnlyField()
    modify_time = DateTimeField(read_only=True)

 

API Reference

爲了解釋不一樣類型的關係字段,咱們將使用簡單的模型做爲示例。

class Album(models.Model):
    album_name = models.CharField(max_length=100)
    artist = models.CharField(max_length=100)

class Track(models.Model):
    album = models.ForeignKey(Album, related_name='tracks', on_delete=models.CASCADE)
    order = models.IntegerField()
    title = models.CharField(max_length=100)
    duration = models.IntegerField()

    class Meta:
        unique_together = ('album', 'order')
        ordering = ['order']

    def __unicode__(self):
        return '%d: %s' % (self.order, self.title)

 

StringRelatedField

StringRelatedField能夠被用來展現目的關係使用它的__str__方法(這裏官網上給的是__unicode__方法,但樓主測試下來並非)

class AlbumSerializer(serializers.ModelSerializer):
    tracks = serializers.StringRelatedField(many=True)

    class Meta:
        model = Album
        fields = ('album_name', 'artist', 'tracks')

將會被序列化成下面的樣子

{'album_name': 'reputation', 'artist': 'Taylor Swift', 'tracks': ['reputation: Look What you make me do', 'reputation: Delicate']}

字段只讀,若是對應多個關係,須要添加many=True

PrimaryKetRelatedField

PrimaryKeyRelatedField可使用主鍵來表示目的關係

class AlbumSerializer(serializers.ModelSerializer):
    tracks = serializers.PrimaryKeyRelatedField(many=True, read_only=True)

    class Meta:
        model = Album
        fields = ('album_name', 'artist', 'tracks')

結果以下

{'album_name': 'reputation', 'artist': 'Taylor Swift', 'tracks': [2, 3]}

默認這個字段可讀寫,你能夠改變這個行爲經過使用read_only標誌

參數

queryset, many,allow_null,pk_field...(pk_field=UUIDField(format='hex'))

HyperlinkedRelatedField

HyperlinkedRelatedField能夠經過超連接來顯示目的關係

class AlbumSerializer(serializers.ModelSerializer):
    tracks = serializers.HyperlinkedRelatedField(
        many=True,
        read_only=True,
        view_name='track-detail'
    )

    class Meta:
        model = Album
        fields = ('album_name', 'artist', 'tracks')

結果

{
    'album_name': 'Graceland',
    'artist': 'Paul Simon',
    'tracks': [
        'http://www.example.com/api/tracks/45/',
        'http://www.example.com/api/tracks/46/',
        'http://www.example.com/api/tracks/47/',
        ...
    ]
}

這邊就不細講這個具體實現了,能夠查看serializer章節,經過連接http://www.javashuo.com/article/p-ysrmjzmz-d.html 並查找HyperlinkedModelSerializer關鍵字搜索標題 

參數

view_name
queryset
many
allow_null
lookup_field
look_url_kwarg
format

SlugRelatedField

SlugRelatedField能夠用來用目的對象的一個字段來表示關係。

class AlbumSerializer(serializers.ModelSerializer):
    tracks = serializers.SlugRelatedField(
        many=True,
        read_only=True,
        slug_field='title'
     )

    class Meta:
        model = Album
        fields = ('album_name', 'artist', 'tracks')

序列化呈現

{'album_name': 'reputation', 'artist': 'Taylor Swift', 'tracks': ['Look What you make me do', 'Delicate']}

一樣SlugRelatedField是一個可讀寫的字段,你能夠經過read_only來修改行爲。當使用SlugRelatedField做爲一個可讀寫的字段,你一般想確保SlugRelatedField對應model裏面unique=True的一個字段。

參數

slug_field,queryset,many,allow_null

HyperlinkedIdentityField

這個應該也不須要說了,有問題看下面的仍是上面的連接http://www.javashuo.com/article/p-ysrmjzmz-d.html 

 

Nested relationships

嵌套關係能夠經過使用serializers做爲字段來描述。

class TrackSerializer(serializers.ModelSerializer):
    class Meta:
        model = Track
        fields = ('order', 'title', 'duration')

class AlbumSerializer(serializers.ModelSerializer):
    tracks = TrackSerializer(many=True, read_only=True)

    class Meta:
        model = Album
        fields = ('album_name', 'artist', 'tracks')

結果呈現

{
    'album_name': 'reputation', 
    'artist': 'Taylor Swift', 
    'tracks': [
        OrderedDict([('order', 2), ('title', 'Look What you make me do'), ('duration', 2)]), 
        OrderedDict([('order', 3), ('title', 'Delicate'), ('duration', 4)])
    ]
}

Writable nested serializers

默認嵌套的serializers是隻讀的,若是你想要對嵌套的serializer字段支持寫操做,就須要建立create()或者update()方法來清楚的定義如何保存子關係。

class TrackSerializer(serializers.ModelSerializer):
    class Meta:
        model = Track
        fields = ('order', 'title', 'duration')

class AlbumSerializer(serializers.ModelSerializer):
    tracks = TrackSerializer(many=True)

    class Meta:
        model = Album
        fields = ('album_name', 'artist', 'tracks')

    def create(self, validated_data):
        tracks_data = validated_data.pop('tracks')
        album = Album.objects.create(**validated_data)
        for track_data in tracks_data:
            Track.objects.create(album=album, **track_data)
        return album

>>> data = {
    'album_name': 'The Grey Album',
    'artist': 'Danger Mouse',
    'tracks': [
        {'order': 1, 'title': 'Public Service Announcement', 'duration': 245},
        {'order': 2, 'title': 'What More Can I Say', 'duration': 264},
        {'order': 3, 'title': 'Encore', 'duration': 159},
    ],
}
>>> serializer = AlbumSerializer(data=data)
>>> serializer.is_valid()
True
>>> serializer.save()
<Album: Album object>

自定義create裏面咱們pop出來了tracks的數據而後單獨對它進行了建立。

Custom relationnal fields

在少數案例裏面沒有現存的關係格式知足你想要的表現形式,你能夠構造一個完整的客製化的關係字段用來描述從模型實例生產的準確的輸出形式。要構建一個客製化的關係字段,你應該重寫RelatedField和構建.to_representation(self, value). 這個方法會把目的字段的值做爲value參數,並返回此對象序列化的表現。這個value參數一般將會是一個模型(model)實例.

想要基於context提供一個動態的queryset,你也能夠重寫.get_queryset(self)代替在類上標註.queryset或者當初始化字段時

import time

class TrackListingField(serializers.RelatedField):
    def to_representation(self, value):
        duration = time.strftime('%M:%S', time.gmtime(value.duration))
        return 'Track %d: %s (%s)' % (value.order, value.name, duration)

class AlbumSerializer(serializers.ModelSerializer):
    tracks = TrackListingField(many=True)

    class Meta:
        model = Album
        fields = ('album_name', 'artist', 'tracks')

結果:

{
    'album_name': 'Sometimes I Wish We Were an Eagle',
    'artist': 'Bill Callahan',
    'tracks': [
        'Track 1: Jim Cain (04:39)',
        'Track 2: Eid Ma Clack Shaw (04:19)',
        'Track 3: The Wind and the Dove (04:34)',
        ...
    ]
}

Custom hyperlinked fields

在一些案例裏面,你可能須要客製化一個hyperlinked字典的行爲,爲了呈現URLs,可能須要不止一個查找字段。

你能夠經過重寫HyperlinkedRelatedField獲取。有兩個你能夠重寫的方法

get_url(self, obj, view_name, request, format)  # 被用來映射對象實例到url呈現;能夠引起NoReverseMatch若是view_namelookup_field屬性沒有被正確的配置匹配url設置。
get_object()self, queryset, view_name, view_args, view_kwargs)  # 實現可寫的hyperlinked field,爲了映射將傳入的URLs到他們所表明的對象。只讀的不必重寫。這個方法的返回值應該是對應匹配的url設置參數的對應的對象。能夠引起ObjectDoesNotExist錯誤

咱們有一個客製化對象的url,裏面有2個關鍵字參數

/api/<organization_slug>/customers/<customer_pk>/

這種用默認的執行不能被展現,由於只接受一個單獨的查找字段。這個示例裏面,咱們須要重寫HyperlinkedRelatedField來得到咱們須要的行爲:

from rest_framework import serializers
from rest_framework.reverse import reverse

class CustomerHyperlink(serializers.HyperlinkedRelatedField):
    # We define these as class attributes, so we don't need to pass them as arguments.
    view_name = 'customer-detail'
    queryset = Customer.objects.all()

    def get_url(self, obj, view_name, request, format):
        url_kwargs = {
            'organization_slug': obj.organization.slug,
            'customer_pk': obj.pk
        }
        return reverse(view_name, kwargs=url_kwargs, request=request, format=format)

    def get_object(self, view_name, view_args, view_kwargs):
        lookup_kwargs = {
           'organization__slug': view_kwargs['organization_slug'],
           'pk': view_kwargs['customer_pk']
        }
        return self.get_queryset().get(**lookup_kwargs)

源碼以下

 1     def get_object(self, view_name, view_args, view_kwargs):
 2         """
 3         Return the object corresponding to a matched URL.
 4 
 5         Takes the matched URL conf arguments, and should return an
 6         object instance, or raise an `ObjectDoesNotExist` exception.
 7         """
 8         lookup_value = view_kwargs[self.lookup_url_kwarg]
 9         lookup_kwargs = {self.lookup_field: lookup_value}
10         return self.get_queryset().get(**lookup_kwargs)
11 
12     def get_url(self, obj, view_name, request, format):
13         """
14         Given an object, return the URL that hyperlinks to the object.
15 
16         May raise a `NoReverseMatch` if the `view_name` and `lookup_field`
17         attributes are not configured to correctly match the URL conf.
18         """
19         # Unsaved objects will not yet have a valid URL.
20         if hasattr(obj, 'pk') and obj.pk in (None, ''):
21             return None
22 
23         lookup_value = getattr(obj, self.lookup_field)
24         kwargs = {self.lookup_url_kwarg: lookup_value}
25         return self.reverse(view_name, kwargs=kwargs, request=request, format=format)
View Code

上面的列至關於繼承HyperlinkedRelatedField,並重寫了裏面的方法。

 

Customizing the HTML display

模型的內置__str__方法將用於生成用於填充choices屬性的對象的字符串表示。這些choices被用來填充可瀏覽API的選擇HTML輸入。

爲了對於這些輸入提供客製化的表現,能夠重寫RelatedFIeld子類的display_value()方法。這個方法將會接收一個模型對象,並應該返回一個合適的字符串來展現。

class TrackPrimaryKeyRelatedField(serializers.PrimaryKeyRelatedField):
    def display_value(self, instance):
        return 'Track: %s' % (instance.title)

Select field cutoffs

可瀏覽的API默認只展現最多1000條選中的對象。2個關鍵字參數能夠用來控制這個行爲

html_cutoff
設置這個,HTML選擇下拉將顯示的最大選擇數。設置爲None全部限制失效。默認1000

html_vutoff_text
若是在HTML選擇下拉中截斷了最大數量的項目,則將顯示文本指示符。默認'More than {count} items...'

你也能夠控制這些經過設定全局參數HTML_SELECT_CUTOFFHTML_SELECT_CUTOFF_TEXT

在強制執行中斷的狀況下,您可能但願使用HTML表單中的普通輸入字段。您可使用style關鍵字參數。例如:

assigned_to = serializers.SlugRelatedField(
   queryset=User.objects.all(),
   slug_field='username',
   style={'base_template': 'input.html'}
)

 

Reverse relations

注意,反轉管理沒有自動的被包括在ModelSerializer和HyperlinkedModelSerializer類裏。爲了能實現,你必須清楚的添加它到字段列表裏。

class AlbumSerializer(serializers.ModelSerializer):
    class Meta:
        fields = ('tracks', ...)

你一般想確保已經設置了一個合適的related_name參數在關係上,你可使用它做爲字段名。

class Track(models.Model):
    album = models.ForeignKey(Album, related_name='tracks', on_delete=models.CASCADE)
    ...

若是沒有設置related_name在反轉關係上,你須要使用自動生成的關聯名稱在fields參數內

class AlbumSerializer(serializers.ModelSerializer):
    class Meta:
        fields = ('track_set', ...)

 

Generic relationships

若是你先要序列化一個通用的外間,你須要定義一個自定義字段,清楚的決定你想要目的關係怎麼序列化

class TaggedItem(models.Model):
    """
    Tags arbitrary model instances using a generic relation.

    See: https://docs.djangoproject.com/en/stable/ref/contrib/contenttypes/
    """
    tag_name = models.SlugField()
    content_type = models.ForeignKey(ContentType, on_delete=models.CASCADE)
    object_id = models.PositiveIntegerField()
    tagged_object = GenericForeignKey('content_type', 'object_id')

    def __unicode__(self):
        return self.tag_name

下面2個模型類有關聯:

class Bookmark(models.Model):
    """
    A bookmark consists of a URL, and 0 or more descriptive tags.
    """
    url = models.URLField()
    tags = GenericRelation(TaggedItem)


class Note(models.Model):
    """
    A note consists of some text, and 0 or more descriptive tags.
    """
    text = models.CharField(max_length=1000)
    tags = GenericRelation(TaggedItem)

咱們能夠自定義一個字段用來序列化目的示例

class TaggedObjectRelatedField(serializers.RelatedField):
    """
    A custom field to use for the `tagged_object` generic relationship.
    """

    def to_representation(self, value):
        """
        Serialize tagged objects to a simple textual representation.
        """
        if isinstance(value, Bookmark):
            return 'Bookmark: ' + value.url
        elif isinstance(value, Note):
            return 'Note: ' + value.text
        raise Exception('Unexpected type of tagged object')

若是須要目的關係有一個嵌套的表示,你可使用須要的serializer在.to_representation()方法內

 def to_representation(self, value):
        """
        Serialize bookmark instances using a bookmark serializer,
        and note instances using a note serializer.
        """
        if isinstance(value, Bookmark):
            serializer = BookmarkSerializer(value)
        elif isinstance(value, Note):
            serializer = NoteSerializer(value)
        else:
            raise Exception('Unexpected type of tagged object')

        return serializer.data
相關文章
相關標籤/搜索