# Django Rest_Framework(二)序列化器Serializer

作用:

1.序列化,序列化器會把模型對象轉(zhuǎn)換成字典,經(jīng)過response以后變成Json字符串

  1. 反序列化,序列化器會把客戶端發(fā)送過來的數(shù)據(jù)两入,經(jīng)過request以后變成字典,把字典轉(zhuǎn)化成模型

  2. 完成數(shù)據(jù)校驗(yàn)功能敲才。

一裹纳、定義序列化器

Django REST Framework中的Serializer使用類來定義择葡,繼承自rest_framework.serializers.Serializer

舉個(gè)例子:

1.創(chuàng)建一個(gè)新的子應(yīng)用sers
$ python manage.py startapp sers
2.建一個(gè)模型類,這里我們沿用上一篇中的模型類students/Student 參考上一篇的鏈接:http://www.reibang.com/p/d082f7e5b5cb
from django.db import models

# Create your models here.
class Student(models.Model):
    # 模型字段
    name = models.CharField(max_length=100,verbose_name="姓名",help_text="提示文本:賬號不能為空剃氧!")
    sex = models.BooleanField(default=True,verbose_name="性別")
    age = models.IntegerField(verbose_name="年齡")
    class_null = models.CharField(max_length=5,verbose_name="班級編號")
    description = models.TextField(verbose_name="個(gè)性簽名")

    class Meta:
        db_table="tb_student"
        verbose_name = "學(xué)生"
        verbose_name_plural = verbose_name
3.為上面這個(gè)模型類提供一個(gè)序列化器敏储,可以定義如下:
from rest_framework import serializers

# 聲明序列化器,所有的序列化器都要直接或者間接繼承于 Serializer
# 其中朋鞍,ModelSerializer是Serializer的子類已添,ModelSerializer在Serializer的基礎(chǔ)上進(jìn)行了代碼簡化
class StudentSerializer(serializers.Serializer):
    """學(xué)生信息序列化器"""
    # 1. 需要進(jìn)行數(shù)據(jù)轉(zhuǎn)換的字段
    id = serializers.IntegerField()
    name = serializers.CharField()
    age = serializers.IntegerField()
    sex = serializers.BooleanField()
    description = serializers.CharField()

    # 2. 如果序列化器集成的是ModelSerializer,則需要聲明調(diào)用的模型信息

    # 3. 驗(yàn)證代碼

    # 4. 編寫添加和更新模型的代碼

注意:serializer不僅僅只能夠?yàn)閿?shù)據(jù)庫模型類定義滥酥,也可以為非數(shù)據(jù)庫模型類的數(shù)據(jù)定義更舞。serializer是獨(dú)立于數(shù)據(jù)庫之外的存在。
常用字段類型

字段 字段構(gòu)造方式
BooleanField BooleanField()
NullBooleanField NullBooleanField()
CharField CharField(max_length=None, min_length=None, allow_blank=False, trim_whitespace=True)
EmailField EmailField(max_length=None, min_length=None, allow_blank=False)
RegexField RegexField(regex, max_length=None, min_length=None, allow_blank=False)
SlugField SlugField(maxlength=50, min_length=None, allow_blank=False) 正則字段坎吻,驗(yàn)證正則模式 [a-zA-Z0-9-]+
URLField URLField(max_length=200, min_length=None, allow_blank=False)
UUIDField UUIDField(format='hex_verbose') format: 1) 'hex_verbose'"5ce0e9a5-5ffa-654b-cee0-1238041fb31a" 2) 'hex'"5ce0e9a55ffa654bcee01238041fb31a" 3)'int' - 如: "123456789012312313134124512351145145114" 4)'urn' 如: "urn:uuid:5ce0e9a5-5ffa-654b-cee0-1238041fb31a"
IPAddressField IPAddressField(protocol='both', unpack_ipv4=False, **options)
IntegerField IntegerField(max_value=None, min_value=None)
FloatField FloatField(max_value=None, min_value=None)
DecimalField DecimalField(max_digits, decimal_places, coerce_to_string=None, max_value=None, min_value=None) max_digits: 最多位數(shù) decimal_palces: 小數(shù)點(diǎn)位置
DateTimeField DateTimeField(format=api_settings.DATETIME_FORMAT, input_formats=None)
DateField DateField(format=api_settings.DATE_FORMAT, input_formats=None)
TimeField TimeField(format=api_settings.TIME_FORMAT, input_formats=None)
DurationField DurationField()
ChoiceField ChoiceField(choices) choices與Django的用法相同
MultipleChoiceField MultipleChoiceField(choices)
FileField FileField(max_length=None, allow_empty_file=False, use_url=UPLOADED_FILES_USE_URL)
ImageField ImageField(max_length=None, allow_empty_file=False, use_url=UPLOADED_FILES_USE_URL)
ListField ListField(child=, min_length=None, max_length=None)
DictField DictField(child=)

選項(xiàng)參數(shù):

參數(shù)名稱 作用
max_length 最大長度
min_lenght 最小長度
allow_blank 是否允許為空
trim_whitespace 是否截?cái)嗫瞻鬃址?/td>
max_value 最小值
min_value 最大值

通用參數(shù):

參數(shù)名稱 說明
read_only 表明該字段僅用于序列化輸出缆蝉,默認(rèn)False
write_only 表明該字段僅用于反序列化輸入,默認(rèn)False
required 表明該字段在反序列化時(shí)必須輸入瘦真,默認(rèn)True
default 反序列化時(shí)使用的默認(rèn)值
allow_null 表明該字段是否允許傳入None刊头,默認(rèn)False
validators 該字段使用的驗(yàn)證器
error_messages 包含錯(cuò)誤編號與錯(cuò)誤信息的字典
label 用于HTML展示API頁面時(shí),顯示的字段名稱
help_text 用于HTML展示API頁面時(shí)吗氏,顯示的字段幫助提示信息
4.創(chuàng)建Serializer對象

定義好Serializer類之后芽偏,就可以創(chuàng)建Serializer對象了雷逆。
Serializer的構(gòu)造方法:

Serializer(instance=None, data=empty, **kwarg)

說明:
1. 用于序列化時(shí)弦讽,將模型類對象傳入instance參數(shù)
2. 用于反序列化時(shí),將要被反序列化的數(shù)據(jù)傳入data參數(shù)
3. 除了instancedata參數(shù)外膀哲,在構(gòu)造Serializer對象時(shí)往产,還可以通過context參數(shù)額外添加數(shù)據(jù),如:

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

通過context參數(shù)附加的數(shù)據(jù)某宪,可以通過Serializer對象的context屬性獲取仿村。

使用序列化器時(shí)要注意的幾個(gè)關(guān)鍵點(diǎn):

1. 序列化器聲明以后,不會自動執(zhí)行兴喂,需要我們在視圖中進(jìn)行調(diào)用蔼囊。
2. 序列化器無法直接接收數(shù)據(jù),需要我們在視圖中創(chuàng)建序列化器對象時(shí)把使用的數(shù)據(jù)傳遞過來衣迷。
3. 序列化器的字段聲明類似于我們前面使用過的表單系統(tǒng)畏鼓。
4. 開發(fā)restful api時(shí),序列化器會幫我們把模型數(shù)據(jù)轉(zhuǎn)換成字典壶谒。
5. DRF提供的視圖會幫助我們把字典轉(zhuǎn)換成json云矫,或者把客戶端發(fā)送過來的數(shù)據(jù)轉(zhuǎn)成字典。
5.使用序列化器

序列化器的使用分為兩個(gè)階段:
1. 在客戶端請求時(shí)汗菜,使用序列化器可以完成對數(shù)據(jù)的反序列化让禀。
2. 在服務(wù)器響應(yīng)時(shí)挑社,使用序列化器可以萬彩城對數(shù)據(jù)的序列化。

5.1序列化的基本使用(仍然以Student模型類為例)

第一步:"找對象"
查詢出一個(gè)學(xué)生對象(需要序列化的任意對象)

from students.models import Student
student = Studnent.objects.get(id=3)

第二步:"搞對象"
把學(xué)生對象傳到序列化器類里面巡揍,構(gòu)造出序列化器對象

from .serializers import StudentSerializer

serializer = StudentSerializer(instance=student)

第三步:"開花結(jié)果"
通過序列化器對象的data屬性可以獲取序列化后的數(shù)據(jù)

serializer.data
# {'id': 4, 'name': 'Gavin', 'age': 18, 'sex': True, 'description': '享受知識(姿勢)帶來的樂趣'}

完整的視圖代碼(單個(gè)模型數(shù)據(jù))

from django.views import View
from students.models import Student
from .serializers import StudentSerializer
from django.http.response import JsonResponse
class StudentView(View):
    """使用序列化器序列化轉(zhuǎn)換單個(gè)模型數(shù)據(jù)"""
    def get(self,request,pk):
        # 獲取模型類對象
        student = Student.objects.get(pk=pk)
        #構(gòu)造序列化器對象痛阻,所有的結(jié)果都在data里面了[序列化過程]
        serializer = StudentSerializer(instance=student)
        print(serializer.data)
        # 響應(yīng)數(shù)據(jù)
        return JsonResponse(serializer.data)

完整的視圖代碼(多個(gè)模型數(shù)據(jù))

from django.views import View
from students.models import Student
from .serializers import StudentSerializer
from django.http.response import JsonResponse
class StudentView(View):
    """使用序列化器序列化轉(zhuǎn)換多個(gè)模型數(shù)據(jù)"""
    def get(self,request):
        # 獲取模型類對象
        student_list = Student.objects.all()

        # 構(gòu)造序列化器對象,所有的結(jié)果都在data里面了[序列化過程]
        # 如果轉(zhuǎn)換多個(gè)模型對象數(shù)據(jù)腮敌,則需要加上many=True
        serializer = StudentSerializer(instance=student_list,many=True)
        print( serializer.data ) # 序列化器轉(zhuǎn)換后的數(shù)據(jù)

        # 響應(yīng)數(shù)據(jù)給客戶端
        # 返回的json數(shù)據(jù)录平,如果是列表,則需要聲明safe=False
        return JsonResponse(serializer.data,safe=False)
    
    
    # 訪問結(jié)果:
    # [OrderedDict([('id', 1), ('name', 'Gaivin'), ('age', 18), ('sex', True), ('description', '測試')]), OrderedDict([('id', 2), ('name', 'Carrie'), ('age', 16), ('sex', False), ('description', '后面來的測試')]), OrderedDict([('id', 4), ('name', '小張'), ('age', 18), ('sex', True), ('description', '猴賽雷')])]
5.2數(shù)據(jù)驗(yàn)證

使用序列化器進(jìn)行反序列化時(shí)缀皱,需要對數(shù)據(jù)進(jìn)行驗(yàn)證后斗这,才能獲取驗(yàn)證成功的數(shù)據(jù)或保存成模型類對象。
在獲取反序列化數(shù)據(jù)前啤斗,必須調(diào)用is_valid()方法進(jìn)行驗(yàn)證表箭,驗(yàn)證成功返回Ture,否則返回False钮莲。
驗(yàn)證失敗免钻,可以通過序列化器對象的errors屬性獲取錯(cuò)誤信息,返回字典崔拥,包含了字段和字段的錯(cuò)誤极舔。如果是非字段錯(cuò)誤,可以通過修改REST framework配置中的NON_FILED_ERRORS_KEY來控制錯(cuò)誤自電腦中的鍵名链瓦。
驗(yàn)證成功拆魏,可以通過序列化器對象的
validated_data**屬性獲取數(shù)據(jù)。
在定義序列化器時(shí)慈俯,指明每個(gè)字段的序列化類型和選項(xiàng)參數(shù)渤刃,這本身就是一種驗(yàn)證行為。
舉個(gè)例子:我們定義一個(gè)BookInfoSerializer

from rest_framework import serializers
from .serializers import StudentSerializer
class BookInfoSerializer(serializers.Serializer):
    """圖書數(shù)據(jù)序列化器"""
    id = serializers.IntegerField(label='ID', read_only=True)
    btitle = serializers.CharField(label='名稱', max_length=20)
    bpub_date = serializers.DateField(label='發(fā)布日期', required=False)
    bread = serializers.IntegerField(label='閱讀量', required=False)
    bcomment = serializers.IntegerField(label='評論量', required=False)
    image = serializers.ImageField(label='圖片', required=False)

通過構(gòu)造序列化器對象贴膘,并將要反序列化的數(shù)據(jù)傳遞給data構(gòu)造參數(shù)卖子,進(jìn)而進(jìn)行驗(yàn)證

from booktest.serializers import BookInfoSerializer
data = {'bpub_date': 123}
serializer = BookInfoSerializer(data=data)
serializer.is_valid()  # 返回False
serializer.errors
# {'btitle': [ErrorDetail(string='This field is required.', code='required')], 'bpub_date': [ErrorDetail(string='Date has wrong format. Use one of these formats instead: YYYY[-MM[-DD]].', code='invalid')]}
serializer.validated_data  # {}

data = {'btitle': 'python'}
serializer = BookInfoSerializer(data=data)
serializer.is_valid()  # True
serializer.errors  # {}
serializer.validated_data  #  OrderedDict([('btitle', 'python')])

is_valid()方法還可以在驗(yàn)證失敗時(shí)拋出異常serializers.ValidationError,可以通過傳遞raise_exception=True參數(shù)開啟刑峡,REST framework接收此異常洋闽,會向前端返回HTTP 400 Bad Request響應(yīng)。

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

如果覺得這些還不夠突梦,需要在補(bǔ)充驗(yàn)證行為诫舅,可以使用以下三種方法:

1. validate_<field_name>

對<field_name>字段進(jìn)行驗(yàn)證:

from rest_framework import serializers
class BookInfoSerializer(serializers.Serializer):
    """圖書數(shù)據(jù)序列化器"""
    ...

    def validate_btitle(self, value):
        if 'django' not in value.lower():
            raise serializers.ValidationError("圖書不是關(guān)于Django的")
        return value

運(yùn)行,看一下結(jié)果

from booktest.serializers import BookInfoSerializer
data = {'btitle': 'python'}
serializer = BookInfoSerializer(data=data)
serializer.is_valid()  # False   
serializer.errors
#  {'btitle': [ErrorDetail(string='圖書不是關(guān)于Django的', code='invalid')]}
2.validate方法

在序列化器中需要同時(shí)對多個(gè)字段進(jìn)行比較驗(yàn)證時(shí)阳似,可以定義validate方法來驗(yàn)證骚勘,例如:

class BookInfoSerializer(serializers.Serializer):
    """圖書數(shù)據(jù)序列化器"""
    ...

    def validate(self, attrs):
        bread = attrs['bread']
        bcomment = attrs['bcomment']
        if bread < bcomment:
            raise serializers.ValidationError('閱讀量小于評論量')
        return attrs

運(yùn)行,看一下結(jié)果

from booktest.serializers import BookInfoSerializer
data = {'btitle': 'about django', 'bread': 10, 'bcomment': 20}
s = BookInfoSerializer(data=data)
s.is_valid()  # False
s.errors
#  {'non_field_errors': [ErrorDetail(string='閱讀量小于評論量', code='invalid')]}
3.validators

在字段中添加validators選項(xiàng)參數(shù),衣蛾可以補(bǔ)充驗(yàn)證行為俏讹,例如:

def about_django(value):
    if 'django' not in value.lower():
        raise serializers.ValidationError("圖書不是關(guān)于Django的")

class BookInfoSerializer(serializers.Serializer):
    """圖書數(shù)據(jù)序列化器"""
    id = serializers.IntegerField(label='ID', read_only=True)
    btitle = serializers.CharField(label='名稱', max_length=20, validators=[about_django])
    bpub_date = serializers.DateField(label='發(fā)布日期', required=False)
    bread = serializers.IntegerField(label='閱讀量', required=False)
    bcomment = serializers.IntegerField(label='評論量', required=False)
    image = serializers.ImageField(label='圖片', required=False)

運(yùn)行当宴,看一下結(jié)果

from booktest.serializers import BookInfoSerializer
data = {'btitle': 'python'}
serializer = BookInfoSerializer(data=data)
serializer.is_valid()  # False   
serializer.errors
#  {'btitle': [ErrorDetail(string='圖書不是關(guān)于Django的', code='invalid')]}
5.3反序列化的使用

前面的驗(yàn)證數(shù)據(jù)成功后,我們可以使用序列化器來完成數(shù)據(jù)反序列化的過程泽疆。這個(gè)過程可以把數(shù)據(jù)轉(zhuǎn)換成模型類對象户矢。
可以通過實(shí)現(xiàn)create()和update()兩個(gè)方法來實(shí)現(xiàn)。

class BookInfoSerializer(serializers.Serializer):
    """圖書數(shù)據(jù)序列化器"""
    ...

    def create(self, validated_data):
        """新建"""
        return BookInfo(**validated_data)

    def update(self, instance, validated_data):
        """更新殉疼,instance為要更新的對象實(shí)例"""
        instance.btitle = validated_data.get('btitle', instance.btitle)
        instance.bpub_date = validated_data.get('bpub_date', instance.bpub_date)
        instance.bread = validated_data.get('bread', instance.bread)
        instance.bcomment = validated_data.get('bcomment', instance.bcomment)
        return instance

如果需要在返回?cái)?shù)據(jù)對象的時(shí)候梯浪,也將數(shù)據(jù)保存到數(shù)據(jù)庫中,則可以進(jìn)行如下修改:

class BookInfoSerializer(serializers.Serializer):
    """圖書數(shù)據(jù)序列化器"""
    ...

    def create(self, validated_data):
        """新建"""
        return BookInfo.objects.create(**validated_data)

    def update(self, instance, validated_data):
        """更新瓢娜,instance為要更新的對象實(shí)例"""
        instance.btitle = validated_data.get('btitle', instance.btitle)
        instance.bpub_date = validated_data.get('bpub_date', instance.bpub_date)
        instance.bread = validated_data.get('bread', instance.bread)
        instance.bcomment = validated_data.get('bcomment', instance.bcomment)
        instance.save()
        return instance

實(shí)現(xiàn)了上述兩個(gè)方法后挂洛,在反序列化的時(shí)候,就可以通過save()方法返回一個(gè)數(shù)據(jù)對象實(shí)例了

book = serializer.save()

如果創(chuàng)建序列化器對象的時(shí)候眠砾,沒有傳遞instance實(shí)例虏劲,則調(diào)用save()方法的時(shí)候,create()被調(diào)用褒颈,相反柒巫,如果傳遞了instance實(shí)例,則調(diào)用save()方法的時(shí)候谷丸,update()被調(diào)用堡掏。

from db.serializers import BookInfoSerializer
data = {'btitle': '封神演義'}
serializer = BookInfoSerializer(data=data)
serializer.is_valid()  # True
serializer.save()  # <BookInfo: 封神演義>

from db.models import BookInfo
book = BookInfo.objects.get(id=2)
data = {'btitle': '倚天劍'}
serializer = BookInfoSerializer(book, data=data)
serializer.is_valid()  # True
serializer.save()  # <BookInfo: 倚天劍>
book.btitle  # '倚天劍'

知識點(diǎn)補(bǔ)充:
1. 在對序列化器進(jìn)行save()保存時(shí),可以額外傳遞數(shù)據(jù)刨疼,這些數(shù)據(jù)可以再create()和update()中的validated_data參數(shù)獲取到

# request.user 是django中記錄當(dāng)前登錄用戶的模型對象
serializer.save(owner=request.user)
  1. 默認(rèn)序列化器必須傳遞所有的required字段泉唁,否則會拋出驗(yàn)證異常。但是我們可以使用partial參數(shù)來允許部分字段更新
# Update `comment` with partial data
serializer = CommentSerializer(comment, data={'content': u'foo bar'}, partial=True)
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末币狠,一起剝皮案震驚了整個(gè)濱河市游两,隨后出現(xiàn)的幾起案子砾层,更是在濱河造成了極大的恐慌漩绵,老刑警劉巖,帶你破解...
    沈念sama閱讀 218,284評論 6 506
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件肛炮,死亡現(xiàn)場離奇詭異止吐,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)侨糟,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,115評論 3 395
  • 文/潘曉璐 我一進(jìn)店門碍扔,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人秕重,你說我怎么就攤上這事不同。” “怎么了?”我有些...
    開封第一講書人閱讀 164,614評論 0 354
  • 文/不壞的土叔 我叫張陵二拐,是天一觀的道長服鹅。 經(jīng)常有香客問我,道長百新,這世上最難降的妖魔是什么企软? 我笑而不...
    開封第一講書人閱讀 58,671評論 1 293
  • 正文 為了忘掉前任,我火速辦了婚禮饭望,結(jié)果婚禮上仗哨,老公的妹妹穿的比我還像新娘。我一直安慰自己铅辞,他們只是感情好厌漂,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,699評論 6 392
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著斟珊,像睡著了一般桩卵。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上倍宾,一...
    開封第一講書人閱讀 51,562評論 1 305
  • 那天雏节,我揣著相機(jī)與錄音,去河邊找鬼高职。 笑死钩乍,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的怔锌。 我是一名探鬼主播寥粹,決...
    沈念sama閱讀 40,309評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼埃元!你這毒婦竟也來了涝涤?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,223評論 0 276
  • 序言:老撾萬榮一對情侶失蹤岛杀,失蹤者是張志新(化名)和其女友劉穎阔拳,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體类嗤,經(jīng)...
    沈念sama閱讀 45,668評論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡糊肠,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,859評論 3 336
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了遗锣。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片货裹。...
    茶點(diǎn)故事閱讀 39,981評論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖精偿,靈堂內(nèi)的尸體忽然破棺而出弧圆,到底是詐尸還是另有隱情赋兵,我是刑警寧澤,帶...
    沈念sama閱讀 35,705評論 5 347
  • 正文 年R本政府宣布搔预,位于F島的核電站毡惜,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏斯撮。R本人自食惡果不足惜经伙,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,310評論 3 330
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望勿锅。 院中可真熱鬧帕膜,春花似錦、人聲如沸溢十。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,904評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽张弛。三九已至荒典,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間吞鸭,已是汗流浹背寺董。 一陣腳步聲響...
    開封第一講書人閱讀 33,023評論 1 270
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留刻剥,地道東北人遮咖。 一個(gè)月前我還...
    沈念sama閱讀 48,146評論 3 370
  • 正文 我出身青樓,卻偏偏與公主長得像造虏,于是被迫代替她去往敵國和親御吞。 傳聞我的和親對象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,933評論 2 355

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