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
相关文章
相关标签/搜索