Serializers翻譯

Serializers

序列化器允許將諸如查詢集和模型實(shí)例之類的復(fù)雜數(shù)據(jù)轉(zhuǎn)換為原生 Python 數(shù)據(jù)類型,然后可以將它們輕松地呈現(xiàn)為 JSONXML 或其他內(nèi)容類型。序列化器還提供反序列化,在首次驗(yàn)證傳入數(shù)據(jù)之后,可以將解析的數(shù)據(jù)轉(zhuǎn)換回復(fù)雜類型。

REST framework 中的序列化類與 Django 的 FormModelForm 類非常相似。我們提供了一個(gè) Serializer 類,它提供了一種強(qiáng)大的通用方法來(lái)控制響應(yīng)的輸出,以及一個(gè) ModelSerializer 類,它為創(chuàng)建處理模型實(shí)例和查詢集的序列化提供了有效的快捷方式。

申明序列化類

首先創(chuàng)建一個(gè)簡(jiǎn)單的對(duì)象用于示例:

from datetime import datetime

class Comment(object):
    def __init__(self, email, content, created=None):
        self.email = email
        self.content = content
        self.created = created or datetime.now()

comment = Comment(email='leila@example.com', content='foo bar')

聲明一個(gè)序列化類,使用它來(lái)序列化和反序列化與 Comment 對(duì)象相對(duì)應(yīng)的數(shù)據(jù)。

聲明一個(gè)序列化類看起來(lái)非常類似于聲明一個(gè)表單:

from rest_framework import serializers

class CommentSerializer(serializers.Serializer):
    email = serializers.EmailField()
    content = serializers.CharField(max_length=200)
    created = serializers.DateTimeField()

序列化對(duì)象

現(xiàn)在可以使用 CommentSerializer 來(lái)序列化評(píng)論或評(píng)論列表。同樣,使用 Serializer 類看起來(lái)很像使用 Form 類。

serializer = CommentSerializer(comment)
serializer.data
# {'email': 'leila@example.com', 'content': 'foo bar', 'created': '2016-01-27T15:17:10.375877'}

此時(shí)已經(jīng)將模型實(shí)例轉(zhuǎn)換為 Python 原生數(shù)據(jù)類型。為了完成序列化過(guò)程,將數(shù)據(jù)渲染為 json

from rest_framework.renderers import JSONRenderer

json = JSONRenderer().render(serializer.data)
json
# b'{"email":"leila@example.com","content":"foo bar","created":"2016-01-27T15:17:10.375877"}'

反序列化對(duì)象

反序列化是相似的。首先我們將一個(gè)流解析為 Python 原生數(shù)據(jù)類型...

from django.utils.six import BytesIO
from rest_framework.parsers import JSONParser

stream = BytesIO(json)
data = JSONParser().parse(stream)

...然后我們將這些原生數(shù)據(jù)類型恢復(fù)成通過(guò)驗(yàn)證的數(shù)據(jù)字典。

serializer = CommentSerializer(data=data)
serializer.is_valid()
# True
serializer.validated_data
# {'content': 'foo bar', 'email': 'leila@example.com', 'created': datetime.datetime(2012, 08, 22, 16, 20, 09, 822243)}

保存實(shí)例

如果希望能夠基于驗(yàn)證的數(shù)據(jù)返回完整的對(duì)象實(shí)例,則需要實(shí)現(xiàn) .create().update() 方法中的一個(gè)或兩個(gè)。例如:

class CommentSerializer(serializers.Serializer):
    email = serializers.EmailField()
    content = serializers.CharField(max_length=200)
    created = serializers.DateTimeField()

    def create(self, validated_data):
        return Comment(**validated_data)

    def update(self, instance, validated_data):
        instance.email = validated_data.get('email', instance.email)
        instance.content = validated_data.get('content', instance.content)
        instance.created = validated_data.get('created', instance.created)
        return instance

如果對(duì)象實(shí)例與 Django 模型相對(duì)應(yīng),還需要確保這些方法將對(duì)象保存到數(shù)據(jù)庫(kù)。如果 Comment 是一個(gè) Django 模型,這些方法可能如下所示:

    def create(self, validated_data):
        return Comment.objects.create(**validated_data)

    def update(self, instance, validated_data):
        instance.email = validated_data.get('email', instance.email)
        instance.content = validated_data.get('content', instance.content)
        instance.created = validated_data.get('created', instance.created)
        instance.save()
        return instance

現(xiàn)在,當(dāng)反序列化數(shù)據(jù)時(shí),我們可以調(diào)用 .save() 根據(jù)驗(yàn)證的數(shù)據(jù)返回一個(gè)對(duì)象實(shí)例。

comment = serializer.save()

調(diào)用 .save() 將創(chuàng)建一個(gè)新實(shí)例或更新現(xiàn)有實(shí)例,具體取決于在實(shí)例化序列化類時(shí)是否傳遞了現(xiàn)有實(shí)例:

# .save() will create a new instance.
serializer = CommentSerializer(data=data)

# .save() will update the existing `comment` instance.
serializer = CommentSerializer(comment, data=data)

.create().update() 方法都是可選的。您可以都不實(shí)現(xiàn),或者實(shí)現(xiàn)其中的一個(gè)或兩個(gè),具體取決于你的序列化類的用例。

將附加屬性傳遞給 .save()

有時(shí)你會(huì)希望你的視圖代碼能夠在保存實(shí)例的時(shí)候注入額外的數(shù)據(jù)。這些附加數(shù)據(jù)可能包含當(dāng)前用戶,當(dāng)前時(shí)間或其他任何不屬于請(qǐng)求數(shù)據(jù)的信息。

serializer.save(owner=request.user)

調(diào)用 .create().update() 時(shí),任何其他關(guān)鍵字參數(shù)都將包含在 validated_data 參數(shù)中。

直接覆蓋 .save()

在某些情況下,.create().update() 方法名稱可能沒(méi)有意義。例如,在 “聯(lián)系人表單” 中,我們可能不會(huì)創(chuàng)建新實(shí)例,而是發(fā)送電子郵件或其他消息。

在這些情況下,可以選擇直接覆蓋 .save(),因?yàn)樗呖勺x性和有意義性。

舉個(gè)栗子:

class ContactForm(serializers.Serializer):
    email = serializers.EmailField()
    message = serializers.CharField()

    def save(self):
        email = self.validated_data['email']
        message = self.validated_data['message']
        send_email(from=email, message=message)

請(qǐng)注意,在上面的情況下,必須直接訪問(wèn) serializer .validated_data 屬性。

驗(yàn)證

在反序列化數(shù)據(jù)時(shí),你總是需要在嘗試訪問(wèn)驗(yàn)證數(shù)據(jù)之前調(diào)用 is_valid(),或者保存對(duì)象實(shí)例。如果發(fā)生任何驗(yàn)證錯(cuò)誤,那么 .errors 屬性將包含一個(gè)代表錯(cuò)誤消息的字典。例如:

serializer = CommentSerializer(data={'email': 'foobar', 'content': 'baz'})
serializer.is_valid()
# False
serializer.errors
# {'email': [u'Enter a valid e-mail address.'], 'created': [u'This field is required.']}

字典中的每個(gè)鍵都是字段名稱,值是與該字段相對(duì)應(yīng)的錯(cuò)誤消息(字符串列表)。non_field_errors 鍵也可能存在,并會(huì)列出任何常規(guī)驗(yàn)證錯(cuò)誤。可以使用 NON_FIELD_ERRORS_KEY (在 settings 文件中設(shè)置)來(lái)定制 non_field_errors 關(guān)鍵字的名稱。

反序列化 item 列表時(shí),錯(cuò)誤將作為代表每個(gè)反序列化 item 的字典列表返回。

數(shù)據(jù)驗(yàn)證時(shí)拋出異常

.is_valid() 方法帶有一個(gè)可選的 raise_exception 標(biāo)志,如果存在驗(yàn)證錯(cuò)誤,將導(dǎo)致它引發(fā) serializers.ValidationError 異常。

這些異常由 REST framework 提供的默認(rèn)異常處理程序自動(dòng)處理,并且默認(rèn)情況下將返回 HTTP 400 Bad Request

# Return a 400 response if the data was invalid.
serializer.is_valid(raise_exception=True)

字段級(jí)驗(yàn)證

你可以通過(guò)向 Serializer 子類添加 .validate_<field_name> 方法來(lái)指定自定義字段級(jí)驗(yàn)證。這些與 Django 表單上的 .clean_<field_name> 方法類似。

這些方法只有一個(gè)參數(shù),就是需要驗(yàn)證的字段值。

您的 validate_<field_name> 方法應(yīng)返回驗(yàn)證值或引發(fā) serializers.ValidationError

例如:

from rest_framework import serializers

class BlogPostSerializer(serializers.Serializer):
    title = serializers.CharField(max_length=100)
    content = serializers.CharField()

    def validate_title(self, value):
        """
        Check that the blog post is about Django.
        """
        if 'django' not in value.lower():
            raise serializers.ValidationError("Blog post is not about Django")
        return value

注意:如果你的序列化程序中聲明的 <field_name> 參數(shù)為 required = False ,那么如果未包含該字段,則不會(huì)執(zhí)行此驗(yàn)證步驟。

對(duì)象級(jí)驗(yàn)證

如果要對(duì)多個(gè)字段進(jìn)行其他的驗(yàn)證,請(qǐng)將一個(gè)名為 .validate() 的方法添加到您的 Serializer 子類中。這個(gè)方法只有一個(gè)參數(shù),它是一個(gè)字段值(field-value)的字典。如果有必要,它應(yīng)該引發(fā)一個(gè) ValidationError,或者只是返回驗(yàn)證的值。例如:

from rest_framework import serializers

class EventSerializer(serializers.Serializer):
    description = serializers.CharField(max_length=100)
    start = serializers.DateTimeField()
    finish = serializers.DateTimeField()

    def validate(self, data):
        """
        Check that the start is before the stop.
        """
        if data['start'] > data['finish']:
            raise serializers.ValidationError("finish must occur after start")
        return data

驗(yàn)證器

序列化器上的各個(gè)字段可以包含驗(yàn)證器,方法是在字段實(shí)例上聲明它們,例如:

def multiple_of_ten(value):
    if value % 10 != 0:
        raise serializers.ValidationError('Not a multiple of ten')

class GameRecord(serializers.Serializer):
    score = IntegerField(validators=[multiple_of_ten])
    ...

序列化類還可以包含應(yīng)用于整個(gè)字段數(shù)據(jù)集的可重用驗(yàn)證器。這些驗(yàn)證器是通過(guò)在內(nèi)部的 Meta 類中聲明它們來(lái)包含的,如下所示:

class EventSerializer(serializers.Serializer):
    name = serializers.CharField()
    room_number = serializers.IntegerField(choices=[101, 102, 103, 201])
    date = serializers.DateField()

    class Meta:
        # Each room only has one event per day.
        validators = UniqueTogetherValidator(
            queryset=Event.objects.all(),
            fields=['room_number', 'date']
        )

看不懂沒(méi)關(guān)系哦,更多關(guān)于驗(yàn)證的內(nèi)容,以后還會(huì)說(shuō)到。

訪問(wèn)初始數(shù)據(jù)和實(shí)例

將初始對(duì)象或查詢集傳遞給序列化類實(shí)例時(shí),該對(duì)象將作為 .instance 提供。如果沒(méi)有傳遞初始對(duì)象,則 .instance 屬性將為 None

將數(shù)據(jù)傳遞給序列化類實(shí)例時(shí),未修改的數(shù)據(jù)將作為 .initial_data 提供。如果 data 關(guān)鍵字參數(shù)未被傳遞,那么 .initial_data 屬性將不存在。

部分更新

默認(rèn)情況下,序列化程序必須為所有必填字段傳遞值,否則會(huì)引發(fā)驗(yàn)證錯(cuò)誤。您可以使用 partial 參數(shù)以允許部分更新。

# Update `comment` with partial data
serializer = CommentSerializer(comment, data={'content': u'foo bar'}, partial=True)

處理嵌套對(duì)象

前面的例子適用于處理只具有簡(jiǎn)單數(shù)據(jù)類型的對(duì)象,但有時(shí)還需要能夠表示更復(fù)雜的對(duì)象,其中對(duì)象的某些屬性可能不是簡(jiǎn)單的數(shù)據(jù)類型,如字符串,日期或整數(shù)。

Serializer 類本身就是一種 Field,可以用來(lái)表示一個(gè)對(duì)象類型嵌套在另一個(gè)對(duì)象類型中的關(guān)系。

class UserSerializer(serializers.Serializer):
    email = serializers.EmailField()
    username = serializers.CharField(max_length=100)

class CommentSerializer(serializers.Serializer):
    user = UserSerializer()
    content = serializers.CharField(max_length=200)
    created = serializers.DateTimeField()

如果嵌套對(duì)象可以是 None 值,則應(yīng)將 required = False 標(biāo)志傳遞給嵌套的序列化類。

class CommentSerializer(serializers.Serializer):
    user = UserSerializer(required=False)  # May be an anonymous user.
    content = serializers.CharField(max_length=200)
    created = serializers.DateTimeField()

同樣,如果嵌套對(duì)象是一個(gè)列表,則應(yīng)將 many = True 標(biāo)志傳遞給嵌套的序列化類。

class CommentSerializer(serializers.Serializer):
    user = UserSerializer(required=False)
    edits = EditItemSerializer(many=True)  # A nested list of 'edit' items.
    content = serializers.CharField(max_length=200)
    created = serializers.DateTimeField()

可寫嵌套表示

在處理支持反序列化數(shù)據(jù)的嵌套表示時(shí),嵌套對(duì)象的任何錯(cuò)誤都將嵌套在嵌套對(duì)象的字段名稱下。

serializer = CommentSerializer(data={'user': {'email': 'foobar', 'username': 'doe'}, 'content': 'baz'})
serializer.is_valid()
# False
serializer.errors
# {'user': {'email': [u'Enter a valid e-mail address.']}, 'created': [u'This field is required.']}

同樣,.validated_data 屬性將包含嵌套的數(shù)據(jù)結(jié)構(gòu)。

為嵌套表示書寫 .create() 方法

如果你支持可寫嵌套表示,則需要編寫處理保存多個(gè)對(duì)象的 .create().update() 方法。

以下示例演示如何處理使用嵌套配置文件對(duì)象創(chuàng)建用戶。

class UserSerializer(serializers.ModelSerializer):
    profile = ProfileSerializer()

    class Meta:
        model = User
        fields = ('username', 'email', 'profile')

    def create(self, validated_data):
        profile_data = validated_data.pop('profile')
        user = User.objects.create(**validated_data)
        Profile.objects.create(user=user, **profile_data)
        return user

為嵌套表示書寫 .update() 方法

對(duì)于更新,您需要仔細(xì)考慮如何處理關(guān)系更新。例如,如果關(guān)系的數(shù)據(jù)是 None 或沒(méi)有提供,則應(yīng)發(fā)生以下哪種情況?

  • 在數(shù)據(jù)庫(kù)中將關(guān)系設(shè)置為 NULL
  • 刪除關(guān)聯(lián)的實(shí)例。
  • 忽略數(shù)據(jù)并保持原樣。
  • 引發(fā)驗(yàn)證錯(cuò)誤。

以下是我們以前的 UserSerializer 類中的 .update() 方法的示例。

    def update(self, instance, validated_data):
        profile_data = validated_data.pop('profile')
        # Unless the application properly enforces that this field is
        # always set, the follow could raise a `DoesNotExist`, which
        # would need to be handled.
        profile = instance.profile

        instance.username = validated_data.get('username', instance.username)
        instance.email = validated_data.get('email', instance.email)
        instance.save()

        profile.is_premium_member = profile_data.get(
            'is_premium_member',
            profile.is_premium_member
        )
        profile.has_support_contract = profile_data.get(
            'has_support_contract',
            profile.has_support_contract
         )
        profile.save()

        return instance

因?yàn)榍短讋?chuàng)建和更新的行為可能不明確,并且可能需要相關(guān)模型之間的復(fù)雜依賴關(guān)系,所以 REST framework 3 要求你始終明確寫入這些方法。默認(rèn)的 ModelSerializer.create().update() 方法不包括對(duì)可寫嵌套表示的支持。

不過(guò),有第三方軟件包可用,如支持自動(dòng)可寫嵌套表示的 DRF Writable Nested

在模型管理器類中保存相關(guān)的實(shí)例

在序列化類中保存多個(gè)相關(guān)實(shí)例的另一種方法是編寫自定義模型管理器類。

例如,假設(shè)我們希望確保 User 實(shí)例和 Profile 實(shí)例始終作為一對(duì)創(chuàng)建。我們可能會(huì)編寫一個(gè)類似下面的自定義管理器類:

class UserManager(models.Manager):
    ...

    def create(self, username, email, is_premium_member=False, has_support_contract=False):
        user = User(username=username, email=email)
        user.save()
        profile = Profile(
            user=user,
            is_premium_member=is_premium_member,
            has_support_contract=has_support_contract
        )
        profile.save()
        return user

此管理器類現(xiàn)在更好地封裝了用戶實(shí)例和配置文件實(shí)例始終在同一時(shí)間創(chuàng)建。現(xiàn)在可以重新編寫序列化類上的 .create()方法,以使用新的管理類方法。

def create(self, validated_data):
    return User.objects.create(
        username=validated_data['username'],
        email=validated_data['email']
        is_premium_member=validated_data['profile']['is_premium_member']
        has_support_contract=validated_data['profile']['has_support_contract']
    )

處理多個(gè)對(duì)象

Serializer 類還可以處理序列化或反序列化對(duì)象列表。

序列化多個(gè)對(duì)象

要序列化查詢集或?qū)ο罅斜矶皇菃蝹€(gè)對(duì)象實(shí)例,在實(shí)例化序列化類時(shí),應(yīng)該傳遞 many=True 標(biāo)志。然后,您可以傳遞要序列化的查詢集或?qū)ο罅斜怼?/p>

queryset = Book.objects.all()
serializer = BookSerializer(queryset, many=True)
serializer.data
# [
#     {'id': 0, 'title': 'The electric kool-aid acid test', 'author': 'Tom Wolfe'},
#     {'id': 1, 'title': 'If this is a man', 'author': 'Primo Levi'},
#     {'id': 2, 'title': 'The wind-up bird chronicle', 'author': 'Haruki Murakami'}
# ]

反序列化多個(gè)對(duì)象

反序列化多個(gè)對(duì)象的默認(rèn)行為是支持多個(gè)對(duì)象創(chuàng)建,但不支持多個(gè)對(duì)象更新。

包含額外的上下文

除了被序列化的對(duì)象外,還有一些情況需要為序列化類提供額外的上下文。一種常見(jiàn)的情況是,如果你使用的是包含超鏈接關(guān)系的序列化類,則需要序列化類訪問(wèn)當(dāng)前請(qǐng)求,以便它可以正確生成完全限定的URL。

在實(shí)例化序列化對(duì)象時(shí),你可以通過(guò)傳遞上下文參數(shù)來(lái)提供任意附加上下文。例如:

serializer = AccountSerializer(account, context={'request': request})
serializer.data
# {'id': 6, 'owner': u'denvercoder9', 'created': datetime.datetime(2013, 2, 12, 09, 44, 56, 678870), 'details': 'http://example.com/accounts/6/details'}

通過(guò)訪問(wèn) self.context 屬性,可以在任何序列化對(duì)象字段邏輯中使用上下文字典,例如自定義的 .to_representation() 方法。

ModelSerializer

通常你會(huì)想要序列化類緊密地映射到 Django 模型定義上。

ModelSerializer 類提供了一個(gè)快捷方式,可讓你自動(dòng)創(chuàng)建一個(gè) Serializer 類,其中的字段與模型類字段對(duì)應(yīng)。

ModelSerializer 類與常規(guī) Serializer 類相同,不同之處在于:

  • 它會(huì)根據(jù)模型自動(dòng)生成一組字段。
  • 它會(huì)自動(dòng)為序列化類生成驗(yàn)證器,例如 unique_together 驗(yàn)證器。
  • 它包含 .create().update() 的簡(jiǎn)單默認(rèn)實(shí)現(xiàn)。

聲明ModelSerializer如下所示:

class AccountSerializer(serializers.ModelSerializer):
    class Meta:
        model = Account
        fields = ('id', 'account_name', 'users', 'created')

默認(rèn)情況下,該類中的所有模型類字段將被映射為相應(yīng)的序列化類字段。

任何關(guān)系(如模型上的外鍵)都將映射到 PrimaryKeyRelatedField 。除非在序列化關(guān)系文檔中指定,否則默認(rèn)不包括反向關(guān)系。

檢查 ModelSerializer

序列化類能夠生成一個(gè)表示字符串,可以讓你充分檢查其字段的狀態(tài)。在使用 ModelSerializer 進(jìn)行工作時(shí),這是特別有用的,你需要確定它為你自動(dòng)創(chuàng)建了哪些字段和驗(yàn)證器。

為此,使用 python manage.py shell 進(jìn)入 Django shell,然后導(dǎo)入序列化類,實(shí)例化它并打印對(duì)象表示形式...

>>> from myapp.serializers import AccountSerializer
>>> serializer = AccountSerializer()
>>> print(repr(serializer))
AccountSerializer():
    id = IntegerField(label='ID', read_only=True)
    name = CharField(allow_blank=True, max_length=100, required=False)
    owner = PrimaryKeyRelatedField(queryset=User.objects.all())

指定要包含的字段

如果你只希望在模型序列化程序中使用默認(rèn)字段的子集,則可以使用 fieldsexclude 選項(xiàng)來(lái)完成此操作,就像使用 ModelForm 一樣。強(qiáng)烈建議你顯式使用 fields 屬性序列化的所有字段。這將使你不太可能在模型更改時(shí)無(wú)意中暴露數(shù)據(jù)。

舉個(gè)栗子:

class AccountSerializer(serializers.ModelSerializer):
    class Meta:
        model = Account
        fields = ('id', 'account_name', 'users', 'created')

你還可以將 fields 屬性設(shè)置為特殊值 '__all__',以指示應(yīng)該使用模型中的所有字段。

class AccountSerializer(serializers.ModelSerializer):
    class Meta:
        model = Account
        fields = '__all__'

你可以將 exclude 屬性設(shè)置為從序列化程序中排除的字段列表。

class AccountSerializer(serializers.ModelSerializer):
    class Meta:
        model = Account
        exclude = ('users',)

在上面的示例中,如果 Account 模型有3個(gè)字段 account_nameuserscreated,則會(huì)導(dǎo)致字段 account_namecreated 被序列化。

fieldsexclude 屬性中的名稱通常映射到模型類的模型字段。

或者fields選項(xiàng)中的名稱可以映射成屬性或方法。而不會(huì)變成模型類中的參數(shù)。

從版本 3.3.0 開始,必須提供其中一個(gè)屬性 fieldsexclude

指定嵌套序列化

默認(rèn)的 ModelSerializer 使用主鍵進(jìn)行關(guān)聯(lián),但你也可以使用 depth 選項(xiàng)輕松生成嵌套表示(自關(guān)聯(lián)):

class AccountSerializer(serializers.ModelSerializer):
    class Meta:
        model = Account
        fields = ('id', 'account_name', 'users', 'created')
        depth = 1

depth 選項(xiàng)應(yīng)設(shè)置為一個(gè)整數(shù)值,該值指示在還原為平面表示之前應(yīng)該遍歷的關(guān)聯(lián)的深度。

如果你想自定義序列化的方式,你需要自己定義字段。

顯式指定字段

你可以將額外的字段添加到 ModelSerializer,或者通過(guò)在類上聲明字段來(lái)覆蓋默認(rèn)字段,就像你對(duì) Serializer 類所做的那樣。

class AccountSerializer(serializers.ModelSerializer):
    url = serializers.CharField(source='get_absolute_url', read_only=True)
    groups = serializers.PrimaryKeyRelatedField(many=True)

    class Meta:
        model = Account

額外的字段可以對(duì)應(yīng)于模型上的任何屬性或可調(diào)用的字段。

指定只讀字段

你可能希望將多個(gè)字段指定為只讀。不要顯式給每個(gè)字段添加 read_only = True屬性,你可以使用快捷方式 Meta 選項(xiàng) read_only_fields

該選項(xiàng)應(yīng)該是字段名稱的列表或元組,聲明如下:

class AccountSerializer(serializers.ModelSerializer):
    class Meta:
        model = Account
        fields = ('id', 'account_name', 'users', 'created')
        read_only_fields = ('account_name',)

含有 editable = False的模型字段,AutoField 字段默認(rèn)設(shè)置為只讀,并且不需要添加到 read_only_fields 選項(xiàng)。

注意: 有一種特殊情況,只讀字段是模型級(jí)別的 unique_together 約束的一部分。在這種情況下,序列化類需要驗(yàn)證約束該字段,但也不能由用戶編輯。

處理這個(gè)問(wèn)題的正確方法是在序列化類中明確指定字段,同時(shí)提供 read_only = Truedefault = ... 關(guān)鍵字參數(shù)。

其中一個(gè)例子是與當(dāng)前認(rèn)證 User 的只讀關(guān)系,它與另一個(gè)標(biāo)識(shí)符是 unique_together 。在這種情況下,你會(huì)像這樣聲明用戶字段:

user = serializers.PrimaryKeyRelatedField(read_only=True, default=serializers.CurrentUserDefault())

關(guān)于驗(yàn)證以后還會(huì)再說(shuō)

其他關(guān)鍵字參數(shù)

還有一個(gè)快捷方式允許你使用 extra_kwargs 選項(xiàng)在字段上指定任意附加關(guān)鍵字參數(shù)。與 read_only_fields 的情況一樣,這意味著你不需要在序列化類中顯式聲明該字段。

該選項(xiàng)是一個(gè)字典,將字段名稱映射到關(guān)鍵字參數(shù)字典。例如:

class CreateUserSerializer(serializers.ModelSerializer):
    class Meta:
        model = User
        fields = ('email', 'username', 'password')
        extra_kwargs = {'password': {'write_only': True}}

    def create(self, validated_data):
        user = User(
            email=validated_data['email'],
            username=validated_data['username']
        )
        user.set_password(validated_data['password'])
        user.save()
        return user

關(guān)系字段

序列化模型實(shí)例時(shí),可以選擇多種不同的方式來(lái)表示關(guān)系。ModelSerializer 的默認(rèn)表示是使用相關(guān)實(shí)例的主鍵。

其他表示形式包括使用超鏈接序列化,序列化完整嵌套表示形式或使用自定義表示形式序列化。

自定義字段映射

ModelSerializer 類還公開了一個(gè)可以覆蓋的 API,以便在實(shí)例化序列化對(duì)象時(shí)更改序列化對(duì)象的字段。

通常,如果 ModelSerializer 沒(méi)辦法生成默認(rèn)需要的字段,那么你應(yīng)該將它們明確地添加到類中,或者直接使用常規(guī)的Serializer 類。但是,在某些情況下,你可能需要?jiǎng)?chuàng)建一個(gè)新的基類,以定義如何為給定模型創(chuàng)建序列化對(duì)象的字段。

.serializer_field_mapping

Django 模型類到 REST framework 序列化類的映射。你可以重寫此映射來(lái)更改應(yīng)該用于每個(gè)模型類的默認(rèn)序列化類。

.serializer_related_field

該屬性應(yīng)該是序列化器字段類,默認(rèn)情況下用于關(guān)系字段。

對(duì)于 ModelSerializer,它默認(rèn)為 PrimaryKeyRelatedField

對(duì)于 HyperlinkedModelSerializer,它默認(rèn)為 serializers.HyperlinkedRelatedField

serializer_url_field

序列化器字段類,應(yīng)該用于序列化類中的任何 url 字段。

默認(rèn)是 serializers.HyperlinkedIdentityField

serializer_choice_field

序列化器字段類,應(yīng)該用于序列化程序中的任何選擇字段。

默認(rèn)是 serializers.ChoiceField

field_class 和 field_kwargs API

調(diào)用以下方法來(lái)確定應(yīng)該自動(dòng)包含在序列化程序中的每個(gè)字段的類和關(guān)鍵字參數(shù)。這些方法都應(yīng)返回兩個(gè)元組 (field_class, field_kwargs)

.build_standard_field(self, field_name, model_field)

調(diào)用以生成映射到標(biāo)準(zhǔn)模型字段的序列化器字段。

默認(rèn)實(shí)現(xiàn)基于 serializer_field_mapping 屬性返回序列化類。

.build_relational_field(self, field_name, relation_info)

調(diào)用以生成映射到關(guān)系模型字段的序列化器字段。

默認(rèn)實(shí)現(xiàn)基于 serializer_relational_field 屬性返回一個(gè)序列化類。

relation_info 參數(shù)是一個(gè)命名元組,它包含 model_fieldrelated_modelto_manyhas_through_model 屬性。

.build_nested_field(self, field_name, relation_info, nested_depth)

當(dāng) depth 選項(xiàng)已設(shè)置時(shí),調(diào)用以生成映射到關(guān)系模型字段的序列化程序字段。

默認(rèn)實(shí)現(xiàn)動(dòng)態(tài)創(chuàng)建一個(gè)基于 ModelSerializerHyperlinkedModelSerializer 的嵌套序列化類。

nested_depth 將是 depth 選項(xiàng)的值減 1。

relation_info 參數(shù)是一個(gè)命名元組,它包含 model_fieldrelated_modelto_manyhas_through_model 屬性。

.build_property_field(self, field_name, model_class)

調(diào)用以生成映射到模型類上的屬性或零參數(shù)方法的序列化器字段。

默認(rèn)實(shí)現(xiàn)返回一個(gè) ReadOnlyField 類。

.build_url_field(self, field_name, model_class)

被調(diào)用來(lái)為序列化器自己的 url 字段生成一個(gè)序列化器字段。

默認(rèn)實(shí)現(xiàn)返回一個(gè) HyperlinkedIdentityField 類。

.build_unknown_field(self, field_name, model_class)

當(dāng)字段名稱未映射到任何模型字段或模型屬性時(shí)調(diào)用。默認(rèn)實(shí)現(xiàn)會(huì)引發(fā)錯(cuò)誤。但是子類可以自定義這種行為。

HyperlinkedModelSerializer

HyperlinkedModelSerializer 類與 ModelSerializer 類相似,只不過(guò)它使用超鏈接來(lái)表示關(guān)系而不是主鍵。

默認(rèn)情況下,序列化器將包含一個(gè) url 字段而不是主鍵字段。

url 字段將使用 HyperlinkedIdentityField 序列化器字段來(lái)表示,并且模型上的任何關(guān)系都將使用 HyperlinkedRelatedField 序列化器字段來(lái)表示。

你可以通過(guò)將主鍵添加到 fields 選項(xiàng)來(lái)明確包含主鍵,例如:

class AccountSerializer(serializers.HyperlinkedModelSerializer):
    class Meta:
        model = Account
        fields = ('url', 'id', 'account_name', 'users', 'created')

絕對(duì)和相對(duì) URL

在實(shí)例化 HyperlinkedModelSerializer 時(shí),必須在序列化上下文中包含當(dāng)前請(qǐng)求,例如:

serializer = AccountSerializer(queryset, context={'request': request})

這樣做將確保超鏈接可以包含適當(dāng)?shù)闹鳈C(jī)名,以便生成完全限定的 URL,例如:

http://api.example.com/accounts/1/

而不是相對(duì)的 URL,例如:

/accounts/1/

如果你確實(shí)想要使用相對(duì) URL,則應(yīng)該在序列化上下文中顯式傳遞 {'request':None}

如何確定超鏈接視圖

需要確定哪些視圖應(yīng)該用于超鏈接到模型實(shí)例。

默認(rèn)情況下,超鏈接預(yù)期對(duì)應(yīng)于與樣式 '{model_name}-detail' 匹配的視圖名稱,并通過(guò) pk 關(guān)鍵字參數(shù)查找實(shí)例。

您可以使用 extra_kwargs 設(shè)置中的 view_namelookup_field 選項(xiàng)覆蓋 URL 字段視圖名稱和查找字段,如下所示:

class AccountSerializer(serializers.HyperlinkedModelSerializer):
    class Meta:
        model = Account
        fields = ('account_url', 'account_name', 'users', 'created')
        extra_kwargs = {
            'url': {'view_name': 'accounts', 'lookup_field': 'account_name'},
            'users': {'lookup_field': 'username'}
        }

或者,可以顯式設(shè)置序列化類中的字段。例如:

class AccountSerializer(serializers.HyperlinkedModelSerializer):
    url = serializers.HyperlinkedIdentityField(
        view_name='accounts',
        lookup_field='slug'
    )
    users = serializers.HyperlinkedRelatedField(
        view_name='user-detail',
        lookup_field='username',
        many=True,
        read_only=True
    )

    class Meta:
        model = Account
        fields = ('url', 'account_name', 'users', 'created')

提示:正確地匹配超鏈接和 URL conf 有時(shí)可能有點(diǎn)困難。打印 HyperlinkedModelSerializer 實(shí)例的 repr 是一種特別有用的方法,可以準(zhǔn)確檢查這些關(guān)系預(yù)期映射的 view name 和 lookup field。

更改 URL 字段名稱

URL 字段的名稱默認(rèn)為 'url'。可以使用 URL_FIELD_NAME (在 settings 文件)全局覆蓋此設(shè)置。

ListSerializer

ListSerializer 類提供了一次序列化和驗(yàn)證多個(gè)對(duì)象的行為。你通常不需要直接使用 ListSerializer,而應(yīng)該在實(shí)例化序列化類時(shí)簡(jiǎn)單地傳遞 many=True

當(dāng)一個(gè)序列化類被實(shí)例化并且 many = True 被傳遞時(shí),一個(gè) ListSerializer 實(shí)例將被創(chuàng)建。序列化類成為父級(jí) ListSerializer 的子級(jí)

以下參數(shù)也可以傳遞給 ListSerializer 字段或傳遞了 many = True 的序列化類:

allow_empty

默認(rèn)情況下為 True,但如果要禁止將空列表作為有效輸入,則可將其設(shè)置為 False

自定義 ListSerializer 行為

有幾種情況可能需要自定義 ListSerializer 行為。例如:

  • 希望提供對(duì)列表的特定驗(yàn)證,例如檢查一個(gè)元素是否與列表中的另一個(gè)元素不沖突。
  • 想要自定義多個(gè)對(duì)象的創(chuàng)建或更新行為。

對(duì)于這些情況,可以通過(guò)使用序列化類的 Meta 類中的 list_serializer_class 選項(xiàng)來(lái)修改傳遞了 many=True 時(shí)使用的類。

class CustomListSerializer(serializers.ListSerializer):
    ...

class CustomSerializer(serializers.Serializer):
    ...
    class Meta:
        list_serializer_class = CustomListSerializer

自定義多個(gè)對(duì)象的創(chuàng)建

創(chuàng)建多個(gè)對(duì)象的默認(rèn)實(shí)現(xiàn)是簡(jiǎn)單地為列表中的每個(gè) item 調(diào)用 .create()。如果要自定義此行為,則需要在傳遞 many=True時(shí)自定義 ListSerializer 類上的 .create()方法。

class BookListSerializer(serializers.ListSerializer):
    def create(self, validated_data):
        books = [Book(**item) for item in validated_data]
        return Book.objects.bulk_create(books)

class BookSerializer(serializers.Serializer):
    ...
    class Meta:
        list_serializer_class = BookListSerializer

自定義多個(gè)對(duì)象的更新

默認(rèn)情況下,ListSerializer 類不支持多對(duì)象更新。這是因?yàn)椴迦牒蛣h除預(yù)期的行為是不明確的。

為了支持多對(duì)象更新,你需要重寫 update 方法。在編寫你的多對(duì)象更新代碼時(shí),一定要記住以下幾點(diǎn):

  • 如何確定應(yīng)該為數(shù)據(jù)列表中的每個(gè) item 更新哪個(gè)實(shí)例?
  • 插入應(yīng)該如何處理?它們是無(wú)效的,還是創(chuàng)建新對(duì)象?
  • 應(yīng)該如何處理刪除?它們是否暗示了對(duì)象刪除,或者刪除了一段關(guān)系?它們應(yīng)該被忽略,還是無(wú)效?
  • 如何處理排序?改變兩個(gè) item 的位置是否意味著狀態(tài)的改變或者被忽略?

你需要為實(shí)例序列化類添加一個(gè)顯式 id 字段。默認(rèn)的隱式生成的 id 字段被標(biāo)記為 read_only。這會(huì)導(dǎo)致它在更新時(shí)被刪除。一旦你明確聲明它,它將在列表序列化類的更新方法中可用。

下面是你如何選擇實(shí)現(xiàn)多對(duì)象更新的示例:

class BookListSerializer(serializers.ListSerializer):
    def update(self, instance, validated_data):
        # Maps for id->instance and id->data item.
        book_mapping = {book.id: book for book in instance}
        data_mapping = {item['id']: item for item in validated_data}

        # Perform creations and updates.
        ret = []
        for book_id, data in data_mapping.items():
            book = book_mapping.get(book_id, None)
            if book is None:
                ret.append(self.child.create(data))
            else:
                ret.append(self.child.update(book, data))

        # Perform deletions.
        for book_id, book in book_mapping.items():
            if book_id not in data_mapping:
                book.delete()

        return ret

class BookSerializer(serializers.Serializer):
    # We need to identify elements in the list using their primary key,
    # so use a writable field here, rather than the default which would be read-only.
    id = serializers.IntegerField()
    ...

    class Meta:
        list_serializer_class = BookListSerializer

自定義 ListSerializer 初始化

當(dāng)具有 many=True的序列化類實(shí)例化時(shí),我們需要確定哪些參數(shù)和關(guān)鍵字參數(shù)應(yīng)該傳遞給子級(jí) Serializer類和父級(jí) ListSerializer 類的 .__ init __() 方法。

默認(rèn)的實(shí)現(xiàn)是將所有參數(shù)傳遞給兩個(gè)類,除了 validators 和任何自定義關(guān)鍵字參數(shù),這兩個(gè)參數(shù)都假定用于子序列化類。

有時(shí)你可能需要明確指定在傳遞 many=True 時(shí)如何實(shí)例化子類和父類。您可以使用 many_init 類方法來(lái)完成此操作。

    @classmethod
    def many_init(cls, *args, **kwargs):
        # Instantiate the child serializer.
        kwargs['child'] = cls()
        # Instantiate the parent list serializer.
        return CustomListSerializer(*args, **kwargs)

BaseSerializer

BaseSerializer 類可以用來(lái)方便地支持其他序列化和反序列化風(fēng)格。

這個(gè)類實(shí)現(xiàn)了與 Serializer 類相同的基本 API:

  • .data - 返回傳出的原始表示。
  • .is_valid() - 反序列化并驗(yàn)證傳入的數(shù)據(jù)。
  • .validated_data - 返回驗(yàn)證的傳入數(shù)據(jù)。
  • .errors - 在驗(yàn)證期間返回錯(cuò)誤。
  • .save() - 將驗(yàn)證的數(shù)據(jù)保存到對(duì)象實(shí)例中。

有四種方法可以被覆蓋,這取決于你希望序列化類支持的功能:

  • .to_representation() - 重寫此操作以支持序列化,用于讀取操作。
  • .to_internal_value() - 重寫此操作以支持反序列化,以用于寫入操作。
  • .create() 和 .update() - 覆蓋其中一個(gè)或兩個(gè)以支持保存實(shí)例。

因?yàn)檫@個(gè)類提供了與 Serializer 類相同的接口,所以你可以像現(xiàn)有的常規(guī) SerializerModelSerializer 一樣,將它與基于類的通用視圖一起使用。

唯一不同的是,BaseSerializer 類不會(huì)在可瀏覽的 API 中生成 HTML 表單。這是因?yàn)樗鼈兎祷氐臄?shù)據(jù)不包含所有的字段信息,這些字段信息允許將每個(gè)字段渲染為合適的 HTML 輸入。

Read-only BaseSerializer

要使用 BaseSerializer 類實(shí)現(xiàn)只讀序列化類,我們只需重寫 .to_representation() 方法。讓我們來(lái)看一個(gè)使用簡(jiǎn)單的 Django 模型的示例:

class HighScore(models.Model):
    created = models.DateTimeField(auto_now_add=True)
    player_name = models.CharField(max_length=10)
    score = models.IntegerField()

創(chuàng)建用于將 HighScore 實(shí)例轉(zhuǎn)換為基本數(shù)據(jù)類型的只讀序列化類非常簡(jiǎn)單。

class HighScoreSerializer(serializers.BaseSerializer):
    def to_representation(self, obj):
        return {
            'score': obj.score,
            'player_name': obj.player_name
        }

我們現(xiàn)在可以使用這個(gè)類來(lái)序列化單個(gè) HighScore 實(shí)例:

@api_view(['GET'])
def high_score(request, pk):
    instance = HighScore.objects.get(pk=pk)
    serializer = HighScoreSerializer(instance)
    return Response(serializer.data)

或者用它來(lái)序列化多個(gè)實(shí)例:

@api_view(['GET'])
def all_high_scores(request):
    queryset = HighScore.objects.order_by('-score')
    serializer = HighScoreSerializer(queryset, many=True)
    return Response(serializer.data)

Read-write BaseSerializer 類

要?jiǎng)?chuàng)建一個(gè)可讀寫的序列化類,我們首先需要實(shí)現(xiàn)一個(gè) .to_internal_value() 方法。此方法返回將用于構(gòu)造對(duì)象實(shí)例的驗(yàn)證值,并且如果提供的數(shù)據(jù)格式不正確,則可能引發(fā) ValidationError

一旦實(shí)現(xiàn) .to_internal_value(),基本驗(yàn)證 API 將在序列化器中可用,并且你將能夠使用 .is_valid().validated_data.errors

如果你還想支持 .save(),則還需要實(shí)現(xiàn) .create().update()方法中的一個(gè)或兩個(gè)。

以下是我們之前的 HighScoreSerializer 的一個(gè)完整示例,該示例已更新為支持讀取和寫入操作。

class HighScoreSerializer(serializers.BaseSerializer):
    def to_internal_value(self, data):
        score = data.get('score')
        player_name = data.get('player_name')

        # Perform the data validation.
        if not score:
            raise ValidationError({
                'score': 'This field is required.'
            })
        if not player_name:
            raise ValidationError({
                'player_name': 'This field is required.'
            })
        if len(player_name) > 10:
            raise ValidationError({
                'player_name': 'May not be more than 10 characters.'
            })

        # Return the validated values. This will be available as
        # the `.validated_data` property.
        return {
            'score': int(score),
            'player_name': player_name
        }

    def to_representation(self, obj):
        return {
            'score': obj.score,
            'player_name': obj.player_name
        }

    def create(self, validated_data):
        return HighScore.objects.create(**validated_data)

創(chuàng)建新的基類

如果你希望實(shí)現(xiàn)新的泛型序列化類來(lái)處理特定的序列化風(fēng)格,或者與可選的存儲(chǔ)后端進(jìn)行集成,那么 BaseSerializer 類也很有用。

以下類是可以處理將任意對(duì)象強(qiáng)制轉(zhuǎn)換為基本表示形式的泛型序列化類的示例。

class ObjectSerializer(serializers.BaseSerializer):
    """
    A read-only serializer that coerces arbitrary complex objects
    into primitive representations.
    """
    def to_representation(self, obj):
        for attribute_name in dir(obj):
            attribute = getattr(obj, attribute_name)
            if attribute_name('_'):
                # Ignore private attributes.
                pass
            elif hasattr(attribute, '__call__'):
                # Ignore methods and other callables.
                pass
            elif isinstance(attribute, (str, int, bool, float, type(None))):
                # Primitive types can be passed through unmodified.
                output[attribute_name] = attribute
            elif isinstance(attribute, list):
                # Recursively deal with items in lists.
                output[attribute_name] = [
                    self.to_representation(item) for item in attribute
                ]
            elif isinstance(attribute, dict):
                # Recursively deal with items in dictionaries.
                output[attribute_name] = {
                    str(key): self.to_representation(value)
                    for key, value in attribute.items()
                }
            else:
                # Force anything else to its string representation.
                output[attribute_name] = str(attribute)

Serializer 使用進(jìn)階

重寫序列化和反序列化行為

如果你需要更改序列化類的序列化或反序列化行為,可以通過(guò)覆蓋 .to_representation().to_internal_value() 方法來(lái)實(shí)現(xiàn)。

以下原因可能需要重寫這兩個(gè)方法...

  • 為新的序列化基類添加新行為。
  • 稍微修改現(xiàn)有類的行為。
  • 提高經(jīng)常訪問(wèn)的 API 端點(diǎn)的序列化性能,以便返回大量數(shù)據(jù)。

這些方法的簽名如下:

.to_representation(self, obj)

接受需要序列化的對(duì)象實(shí)例,并返回一個(gè)原始表示。通常這意味著返回一個(gè)內(nèi)置 Python 數(shù)據(jù)類型的結(jié)構(gòu)。可以處理的確切類型取決于您為 API 配置的渲染類。

可能會(huì)被重寫以便修改表示風(fēng)格。例如:

def to_representation(self, instance):
    """Convert `username` to lowercase."""
    ret = super().to_representation(instance)
    ret['username'] = ret['username'].lower()
    return ret

.to_internal_value(self, data)

將未驗(yàn)證的傳入數(shù)據(jù)作為輸入,并應(yīng)返回將作為 serializer.validated_data 提供的驗(yàn)證數(shù)據(jù)。如果在序列化類上調(diào)用了 .save() ,則返回值也將傳遞給 .create().update() 方法。

如果驗(yàn)證失敗,則該方法會(huì)引發(fā) serializers.ValidationError(errors)errors 參數(shù)應(yīng)該是一個(gè)由字段名稱(或 settings.NON_FIELD_ERRORS_KEY)映射到錯(cuò)誤消息列表的字典。如果不需要改變反序列化行為,而是想提供對(duì)象級(jí)驗(yàn)證,則建議改為覆蓋 .validate()方法。

傳遞給此方法的 data 參數(shù)通常是 request.data 的值,因此它提供的數(shù)據(jù)類型將取決于你為 API 配置的解析器類。

繼承序列化類

與 Django 表單類似,你可以通過(guò)繼承來(lái)擴(kuò)展和重用序列化類。這使你可以在父類上聲明一組通用的字段或方法,然后可以在多個(gè)序列化類中使用它們。例如,

class MyBaseSerializer(Serializer):
    my_field = serializers.CharField()

    def validate_my_field(self):
        ...

class MySerializer(MyBaseSerializer):
    ...

與 Django 的 ModelModelForm 類一樣,序列化類中的內(nèi)部 Meta 類不會(huì)從其父類的內(nèi)部 Meta 類中隱式繼承。如果你想讓 Meta 類繼承父類,必須明確的指出。例如:

class AccountSerializer(MyBaseSerializer):
    class Meta(MyBaseSerializer.Meta):
        model = Account

通常我們建議不要在內(nèi)部的 Meta 類中使用繼承,而是顯式聲明所有選項(xiàng)。

動(dòng)態(tài)修改字段

一旦序列化類初始化完畢,就可以使用 .fields 屬性訪問(wèn)在序列化類中設(shè)置的字段字典。通過(guò)訪問(wèn)和修改這個(gè)屬性可以達(dá)到動(dòng)態(tài)地修改序列化類的目的。

直接修改 fields 參數(shù)允許你做一些有趣的事情,比如在運(yùn)行時(shí)改變序列化字段的參數(shù),而不是在聲明序列化類的時(shí)候。

舉個(gè)栗子:

例如,如果你希望能夠設(shè)置序列化類在初始化時(shí)應(yīng)使用哪些字段,你可以創(chuàng)建這樣一個(gè)序列化類,如下所示:

class DynamicFieldsModelSerializer(serializers.ModelSerializer):
    """
    A ModelSerializer that takes an additional `fields` argument that
    controls which fields should be displayed.
    """

    def __init__(self, *args, **kwargs):
        # Don't pass the 'fields' arg up to the superclass
        fields = kwargs.pop('fields', None)

        # Instantiate the superclass normally
        super(DynamicFieldsModelSerializer, self).__init__(*args, **kwargs)

        if fields is not None:
            # Drop any fields that are not specified in the `fields` argument.
            allowed = set(fields)
            existing = set(self.fields)
            for field_name in existing - allowed:
                self.fields.pop(field_name)

這將允許你執(zhí)行以下操作:

>>> class UserSerializer(DynamicFieldsModelSerializer):
>>>     class Meta:
>>>         model = User
>>>         fields = ('id', 'username', 'email')
>>>
>>> print UserSerializer(user)
{'id': 2, 'username': 'jonwatts', 'email': 'jon@example.com'}
>>>
>>> print UserSerializer(user, fields=('id', 'email'))
{'id': 2, 'email': 'jon@example.com'}
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 228,702評(píng)論 6 534
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 98,615評(píng)論 3 419
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人,你說(shuō)我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 176,606評(píng)論 0 376
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)。 經(jīng)常有香客問(wèn)我,道長(zhǎng),這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 63,044評(píng)論 1 314
  • 正文 為了忘掉前任,我火速辦了婚禮,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 71,826評(píng)論 6 410
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 55,227評(píng)論 1 324
  • 那天,我揣著相機(jī)與錄音,去河邊找鬼。 笑死,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,307評(píng)論 3 442
  • 文/蒼蘭香墨 我猛地睜開眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 42,447評(píng)論 0 289
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒(méi)想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 48,992評(píng)論 1 335
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 40,807評(píng)論 3 355
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 43,001評(píng)論 1 370
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,550評(píng)論 5 361
  • 正文 年R本政府宣布,位于F島的核電站,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 44,243評(píng)論 3 347
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 34,667評(píng)論 0 26
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 35,930評(píng)論 1 287
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 51,709評(píng)論 3 393
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 47,996評(píng)論 2 374

推薦閱讀更多精彩內(nèi)容

  • Spring Cloud為開發(fā)人員提供了快速構(gòu)建分布式系統(tǒng)中一些常見(jiàn)模式的工具(例如配置管理,服務(wù)發(fā)現(xiàn),斷路器,智...
    卡卡羅2017閱讀 134,785評(píng)論 18 139
  • 你好 Django REST Framework 在第二章,我們學(xué)習(xí)了 REST 開發(fā)的基本知識(shí),并且在沒(méi)有借助任...
    ucag閱讀 4,547評(píng)論 5 16
  • JAVA序列化機(jī)制的深入研究 對(duì)象序列化的最主要的用處就是在傳遞,和保存對(duì)象(object)的時(shí)候,保證對(duì)象的完整...
    時(shí)待吾閱讀 10,897評(píng)論 0 24
  • 時(shí)光荏苒,歲月翩躚!站在這個(gè)冬天,站在年終歲末的路口;站在忙碌生活的每一天;心中充滿無(wú)限的感慨。暮然回首,有收獲的...
    經(jīng)典明膠_江建文閱讀 2,382評(píng)論 0 0
  • 長(zhǎng)安冷 乞兒倚枯井 城下車馬無(wú)蹤影 苦等何人施舍餅 猶若一浮萍
    苦禪閱讀 256評(píng)論 0 0