https://api.example.com/v1/
?limit=10:指定返回記錄的數量 ?offset=10:指定返回記錄的開始位置。 ?page=2&per_page=100:指定第幾頁,以及每頁的記錄數。 ?sortby=name&order=asc:指定返回結果按照哪一個屬性排序,以及排序順序。 ?animal_type_id=1:指定篩選條件
知乎連接html
Python的多重繼承正如文檔所言是深度優先從左至右不重複 在Python裏,當你新構造一個對象時,有兩個步驟:首先是自底向上,從左至右調用__new__,而後再依照遞歸棧依次調用__init__
單個視圖使用: class 類中指定: versioning_class = QueryParameterVersioning 全局使用:python
settings中配置生效,全局使用 REST_FRAMEWORK = { "DEFAULT_VERSIONING_CLASS":"rest_framework.versioning.URLPathVersioning", "DEFAULT_VERSION":'v1', "ALLOWED_VERSIONS":['v1','v2'], "VERSION_PARAM":'version', "DEFAULT_PARSER_CLASSES":['rest_framework.parsers.JSONParser','rest_framework.parsers.FormParser'] }
E:\space_env\env_for_blog\Lib\site-packages\rest_framework\versioning.py 一個基類,5個版本控制類:數據庫
BaseVersioning QueryParameterVersioning(BaseVersioning) URLPathVersioning(BaseVersioning) AcceptHeaderVersioning(BaseVersioning) HostNameVersioning(BaseVersioning) NamespaceVersioning(BaseVersioning)django
BaseVersioning 中有三個函數 def determine_version 返回值是 version 子類覆寫的鉤子 def reverse 反向生成url,每一個子類生成的方式不同 def is_allowed_version 給後邊子類提供可支持的版本號啊json
class URLPathVersioning(BaseVersioning): # 版本錯誤信息 invalid_version_message = _('Invalid version in URL path.') def determine_version() ··· return version def reverse(): return父類的reverse方法
探究後端
APIView -- dispatch -- self.initial(request, *args, **kwargs) # Determine the API version, if versioning is in use. version, scheme = self.determine_version(request, *args, **kwargs) request.version, request.versioning_scheme = version, scheme def determine_version(self, request, *args, **kwargs): """ 返回元組: (version, versioning_scheme) """ if self.versioning_class is None: return (None, None) scheme = self.versioning_class() return (scheme.determine_version(request, *args, **kwargs), scheme) self.initial傳入的是新request 在APIView - def determine_version裏邊:獲取了version版本, versioning_scheme版本類對象 而後把這倆值封裝到request參數裏邊 # 獲取版本 print(request.version) # 獲取處理版本的對象 print(request.versioning_scheme)
reverse 利用restful - reverseapi
# 反向生成URL(rest framework) u1 = request.versioning_scheme.reverse(viewname='uuu',request=request) print(u1)
利用django自帶的reverse服務器
# 反向生成URL u2 = reverse(viewname='uuu',kwargs={'version':2}) print(u2) 這個須要本身指定kwargs
對應的類是:versioning_class = QueryParameterVersioning http://127.0.0.1:8000/api/users/?version=v2restful
對應類:URLPathVersioning(BaseVersioning) url(r'^(?P<version>[v1|v2]+)/users/$', views.UsersView.as_view(),name='uuu'), http://127.0.0.1:8000/api/users/?version=v2網絡
【注意】 配置或測試URL時,須要保證所輸入的URL符合規則 也就是說,變量得是那個v1/v2 才能順利匹配版本/返回invalid_version_message 若是連URL開頭都沒匹配上的話,那隻能404了,壓根走不到版本控制的代碼處
後端要想成功的解析出數據,有兩點要求: 1. 請求頭要寫對,好比 Content-Type: application/x-www-form-urlencoded 2. 數據格式要與請求頭標識的一致
form提交時:Content-Type: application/x-www-form-urlencoded 後端:request.POST從中取值 application/x-www-form-urlencoded 或 multipart/form-data時,request.POST中才有值 其他狀況,須要request.body取值
rest_framework 解析器,對請求體數據進行解析
BaseParser 基類 沒卵用 JSONParser media_type = 'application/json' FormParser media_type = 'application/x-www-form-urlencoded' MultiPartParser media_type = 'multipart/form-data' Parser for multipart form data, which may include file data. 文件傳輸,也用這個解析 FileUploadParser media_type = '/' 這個貌似是上傳數據用的,用到再看
class ParserView(APIView): parser_classes = [JSONParser,FormParser,] """ JSONParser:表示只能解析content-type:application/json頭 JSONParser:表示只能解析content-type:application/x-www-form-urlencoded頭 """ def post(self,request,*args,**kwargs): print(request.data) return HttpResponse('ParserView返回')
封裝參數 dispatch - self.initialize_request - parsers=self.get_parsers() request.data Request() 類 >>> def data()方法 >>> _load_data_and_files is_form_media_type 直接copy 或者 self._parse() media_type = self.content_type - 獲取content_type stream = self.stream - 調用Request/stream()獲取body數據 parser = self.negotiator.select_parser(self, self.parsers) - 獲取設置的序列化類
parsed = parser.parse(stream, media_type, self.parser_context) - 序列化 try: return (parsed.data, parsed.files) except AttributeError: empty_files = MultiValueDict() return (parsed, empty_files)
【概念】:序列化就是一種用來處理對象流的機制,所謂對象流也就是將對象的內容進行流化,流的概念這裏不用多說(就是I/O), 咱們能夠對流化後的對象進行讀寫操做,也可將流化後的對象傳輸於網絡之間(注:要想將對象傳輸於網絡必須進行流化)! 在對對象流進行讀寫操做時會引起一些問題,而序列化機制正是用來解決這些問題的!
序列化器容許將諸如查詢集和模型實例之類的複雜數據轉換爲原生 Python 數據類型,而後能夠將它們輕鬆地呈現爲 JSON,XML 或其餘內容類型。 序列化器還提供反序列化,在首次驗證傳入數據以後,能夠將解析的數據轉換回複雜類型(並作驗證)。
REST framework 中的序列化類與 Django 的 Form 和 ModelForm 類很是類似。 咱們提供了一個 Serializer 類,它提供了一種強大的通用方法來控制響應的輸出,以及一個 ModelSerializer 類, 它爲建立處理模型實例和查詢集的序列化提供了有效的快捷方式。
序列化在django-rest-framework中的典型應用就是:
從數據庫中取數據,而後將其序列化爲支持網絡傳輸的表述(如json)
驗證,對請求發來的數據進行驗證.對發來的json串解析爲Serializer對應的字段 ser.is_valid()驗證,而後ser.validated_data取數據進行操做,或者ser.errors提取錯誤信息
咱們能夠經過聲明序列來完成,這些序列與Django的表單(forms)工做類似。 forms是DB(後端)與HTML的橋樑,serializers是DB(後端)與傳輸的轉換器 二者在設計思路和使用方式上有不少雷同,源碼流程也很類似
def get(self,request,*args,**kwargs): roles = models.Role.objects.all().values('id','title') roles = list(roles) ret = json.dumps(roles,ensure_ascii=False) return HttpResponse(ret)
【注意】ensure_ascii=False 表示不轉碼,就按照數據庫原始數據形式來發
class RolesSerializer(serializers.Serializer): # 字段名與數據庫名稱一致 id = serializers.IntegerField() title = serializers.CharField() class RolesView(APIView): def get(self,request,*args,**kwargs): roles = models.Role.objects.all() ser = RolesSerializer(instance=roles,many=True) ret = json.dumps(ser.data, ensure_ascii=False) # 對於單個對象,many=False role = models.Role.objects.all().first() ser = RolesSerializer(instance=role, many=False) # ser.data 已是轉換完成的結果 ret = json.dumps(ser.data, ensure_ascii=False) return HttpResponse(ret)
print(ser.data,type(ser.data)) {'title': '開發', 'id': 1} <class 'rest_framework.utils.serializer_helpers.ReturnDict'> ser.data 是字典(有序字典)
user_type = serializers.CharField() 等價於 xxxxx = serializers.CharField(source="user_type") 轉換完的字段名 user_type 變爲 xxxxx
因此能夠這樣寫: user_type = serializers.CharField(source="user_type") 顯示存儲的代號 user_type = serializers.CharField(source="get_user_type_display") 顯示對應的名稱
外鍵關聯時: gp = serializers.CharField(source="group.title") 內部能夠根據 . 來split,一直向後取值
內部: 源碼會判斷傳入的值是否callable,若是可調用,自動加()執行 source="user_type" >>> row.user_type source="get_user_type_display" >>> row.get_user_type_display()
def fun(arg): if callable(arg): ret = arg() else: ret = arg print(ret) def add(a,b): return a + b fun('測試') fun(add(2,6))
真正的自定義顯示,鉤子
rls = serializers.SerializerMethodField() # 自定義顯示 def get_rls(self,row): role_obj_list = row.roles.all() ret = [] for item in role_obj_list: ret.append({'id':item.id,'title':item.title}) return ret # my_field = serializer.SerializerMethodField(method_name='get_my_field') # default_method_name = 'get_{field_name}'.format(field_name=field_name)
自定義filed
class MyField(serializers.CharField): def to_representation(self, value): print(value) return "真正的返回值" 使用: class UserInfoSerializer(serializers.Serializer): my_field = MyField(source='username') 返回時,顯示的就是return內容
也能夠支持自定義字段。
指定字段時能省點事,僅此而已
class UserInfoSerializer(serializers.ModelSerializer): oooo = serializers.CharField(source="get_user_type_display") rls = serializers.SerializerMethodField() # 自定義顯示鉤子 gp = serializers.CharField(source="group.title") def get_rls(self,row): return ({'name':'jinshen'}) class Meta: model = models.UserInfo # fields = "__all__" fields = ['id','username','password','group','roles'] class UserInfoView2(APIView): def get(self, request, *args, **kwargs): users = models.UserInfo.objects.all() ser = UserInfoSerializer2(instance=users, many=True, context={'request': request}) ret = json.dumps(ser.data, ensure_ascii=False) return HttpResponse(ret)
class UserInfoSerializer(serializers.ModelSerializer): class Meta: model = models.UserInfo # fields = "__all__" fields = ['id','username','password','group','roles'] depth = 1 # 0 ~ 10
serializers.HyperlinkedIdentityField
# group字段對應生成url連接 - "group": "http://127.0.0.1:8000/api/v1/group/1", class UserInfoSerializer3(serializers.ModelSerializer): group = serializers.HyperlinkedIdentityField(view_name='gp',lookup_field='group_id',lookup_url_kwarg='pk') ''' view_name='gp' url別名 lookup_field='group_id' 對應的字段列,默認pk lookup_url_kwarg='pk' url中的分組名,能夠本身改 沒有source參數! ''' class Meta: model = models.UserInfo fields = ['id','username','password','group','roles'] depth = 0 # 0 ~ 10 class UserInfoView3(APIView): def get(self, request, *args, **kwargs): users = models.UserInfo.objects.all() '''若是要生成連接,必須加上context參數''' ser = UserInfoSerializer3(instance=users, many=True, context={'request': request}) ret = json.dumps(ser.data, ensure_ascii=False) return HttpResponse(ret)
__new__ 比 __init__要早執行
__new__和__init__
__new__和__init__
kwargs.pop('many', False) 取many值,缺省默認False, def __new__(cls, *args, **kwargs): # We override this method in order to automagically create # `ListSerializer` classes instead when `many=True` is set. if kwargs.pop('many', False): # many = True時執行,對queryset進行處理 return cls.many_init(*args, **kwargs) # many缺省或爲False時執行,對obj進行處理 return super(BaseSerializer, cls).__new__(cls, *args, **kwargs) def __init__(): pass 一坨賦值語句封裝參數
分析
many = False
return super(BaseSerializer, cls).__new__(cls, *args, **kwargs)
返回的是本身,啥都沒作。new就完事了 ,接下來執行init方法去了 many = True 執行 many_init() 方法 這個方法作了一件事 把處理序列化的類指定爲 ListSerializer,並返回
小結 ser = RolesSerializer(instance=role, many=False) 類實例化作的事:作區分 對象, Serializer類處理; self.to_representation QuerySet,ListSerializer類處理; self.to_representation
Serializer - data方法
@property def data(self): ret = super(Serializer, self).data #調用父類data方法 return ReturnDict(ret, serializer=self)
BaseSerializer - data方法
if not hasattr(self, '_data'): if self.instance is not None and not getattr(self, '_errors', None): self._data = self.to_representation(self.instance) elif hasattr(self, '_validated_data') and not getattr(self, '_errors', None): self._data = self.to_representation(self.validated_data) else: self._data = self.get_initial() return self._data
to_representation方法, 依然是從下往上找,Serializer和BaseSerializer裏都有此方法 可是Serializer-to_representation 離得更近,它會執行
def to_representation(self, instance): """ Object instance -> Dict of primitive datatypes. """ ret = OrderedDict() #這就是最後返回給咱們的那個有序字典實例 fields = self._readable_fields for field in fields: try: attribute = field.get_attribute(instance) except SkipField: continue ···
field 是咱們在自定義序列化類時指定的 Charfiled IntegerField 這些字段對象 Charfiled 等,裏邊沒有get_attribute() 方法 Charfiled繼承自Filed class Filed() - get_attribute()
def get_attribute(self, instance): """ Given the *outgoing* object instance, return the primitive value that should be used for this field. """ try: return get_attribute(instance, self.source_attrs)
instance 是傳入的對象 self.source_attrs就是參數source, 在類的init裏能夠看到它的封裝 在Filed類下的bind()方法,能夠看到split . 取值 source_attrs 能夠是:group.title get_user_type_display roles.all等等 經過後邊的一系列騷操做,無論它是什麼,都能從裏邊拿出想要的東西
上來就跳了,返回單獨的get_attribute()方法 把兩個重要的參數傳入
def get_attribute(instance, attrs): for attr in attrs: # 循環全部的attr(source參數) try: if isinstance(instance, collections.Mapping): instance = instance[attr] else: instance = getattr(instance, attr) except ObjectDoesNotExist: return None if is_simple_callable(instance): try: instance = instance() except (AttributeError, KeyError) as exc: # If we raised an Attribute or KeyError here it'd get treated # as an omitted field in `Field.get_attribute()`. Instead we # raise a ValueError to ensure the exception is not masked. raise ValueError('Exception raised in callable attribute "{0}"; original exception was: {1}'.format(attr, exc)) return instance
經過在這個函數裏遍歷,根據source取出各層的instance實例並逐層返回
serializers.py 文件在開頭引入包的時候,就引入了fields.py的全部字段 example_field = serializers.CharField(...) 用的實際上是fileds裏邊的Charfiled class CharField(Field): 繼承自 class Field(object): 咱們看看Field支持哪些參數:
class Field(object): default_error_messages = { 'required': _('This field is required.'), 'null': _('This field may not be null.') } default_validators = [] def __init__(self, read_only=False, write_only=False, required=None, default=empty, initial=empty, source=None, label=None, help_text=None, style=None, error_messages=None, validators=None, allow_null=False):
default_error_messages 兩條默認的錯誤提示 分別對應的參數是:required和allow_null
validators參數對應的就是驗證方法(基於類),默認空列表
class MultipleOf(object): def __init__(self, base): self.base = base def __call__(self, value): # __call__()方法可以讓類的實例對象,像函數同樣被調用; # XXValidator(12)(34) 第一個()實例化,第二個()內的34會被識別爲參數 if value % self.base != 0: message = 'This field must be a multiple of %d.' % self.base raise serializers.ValidationError(message) 使用: title = serializers.CharField(error_messages={'required': '標題不能爲空'}, validators=[MultipleOf('老男人'), ])
上邊這種方法,實現了對單個字段的驗證。哪一個須要驗,就在哪寫validators=[這個類]
【小總結】 自定義validator類,與form裏邊自定義validator類用法徹底一致 這個validator是filed參數,也就是隻能做爲參數對單個字段進行驗證 具體調用的地方在···\rest_framework\fields.py - class Field() - def run_validators()
try: validator(value) except ValidationError as exc: pass
【小總結over】
另外,還能夠經過自定義字段的方法實現驗證。 django-form中 全部字段對象都繼承自class Field ,在這個類裏邊留了一些鉤子方法 如:to_python() validate() 自定義一個字段類,覆寫以上方法
當調用表單的 is_valid() 方法時, is_valid()>>> self.errors>>>self.full_clean()>>>self._clean_fields()>>>value = field.clean(value) 調用自定義字段的clean()
def clean(self, value): """ Validates the given value and returns its "cleaned" value as an appropriate Python object. Raises ValidationError for any errors. """ value = self.to_python(value) # 字段裏自定義to_python,返回value self.validate(value) # 字段裏自定義validate,返回對象 self.run_validators(value) # 自定義validator類 return value
restful-serializer中 字段繼承自 ···\rest_framework\fields.py class Field() 沒留那麼多鉤子,可是能夠經過覆寫to_representation方法實現 須要注意的是,每一個Filed的這個方法作的事情不同
class MyField(serializers.CharField): # 自定義filed def to_representation(self, value): 驗證或者其它操做 return str(value)
這個沒應用過,但原理是通的。
找鉤子函數,定義序列化類時,將鉤子函數寫進去 這個鉤子方法寫在序列化類,而非某個字段。
Serializer 爲例: Serializer內部能夠找到如下3個方法,不用去父類找 is_valid >>> run_validation >>> to_internal_value
for field in fields: validate_method = getattr(self, 'validate_' + field.field_name, None) ... if validate_method is not None: validated_value = validate_method(validated_value) ...
因此鉤子方法就是 validate_ + 字段名 + () 傳入的是value,return的也是value,中間怎麼搞本身發揮
整個鉤子方法都在try語句裏邊,後邊有except ValidationError跟着 因此不經過,直接raise ValidationError就好了
【類比form】 也是form級調用is_valid方法時: is_valid()調用self.is_bound 和 se lf.errors self.errors >>> self.full_clean() >>> ① self.clean_fields() ② self.clean_form() >>> clean()#純鉤子 ③ self.post_clean() #純鉤子 2和3是純鉤子,不作討論 clean_fields() 下 for循環內部 hasattr(self, 'clean%s' % name):#這裏的name形參其實就是form的字段名 value = getattr(self, 'clean%s' % name)() self.cleaned_data[name] = value 鉤子方法:clean + 字段名 + ()
validate_title() clean_title() 二者都是在驗證器/表單級別的類裏邊,提供了針對具體字段驗證的鉤子方法
就是這麼簡單的事情,官方文檔的解釋也太草率了,還給了個不知所云的even_number
驗證器能夠是任何可調用對象,在失敗時引起 serializers.ValidationError。 def even_number(value): if value % 2 != 0: raise serializers.ValidationError('This field must be an even number.') 你能夠經過向 Serializer 子類添加 .validate_<field_name>方法來指定自定義字段級驗證。
from rest_framework.pagination import PageNumberPagination,LimitOffsetPagination,CursorPagination
分頁相關的類:···\rest_framework\pagination.py BasePagination 基類 PageNumberPagination 普通分頁 LimitOffsetPagination 按照Limit、Offset分頁,此時page參數失效 CursorPagination 遊標/加密分頁
分頁裏邊惟一的亮點:在於遊標分頁,大幅度提高性能,但必定程度上限制了用戶的查詢便利性。
class MytestSerialiser(serializers.ModelSerializer): class Meta: model = models.Role fields = "__all__" class MyPageNumberPagination(PageNumberPagination): # 默認每頁顯示的數據條數 page_size = 4 # 獲取URL參數中設置的每頁顯示數據條數 page_size_query_param = 'page_size' # 獲取URL參數中傳入的頁碼key page_query_param = 'page' # 最大支持的每頁顯示的數據條數 max_page_size = 10 class MyLimitOffsetPagination(LimitOffsetPagination): # 默認每頁顯示的數據條數 default_limit = 5 # URL中傳入的顯示數據條數的參數 limit_query_param = 'limit' # URL中傳入的數據位置的參數 offset_query_param = 'offset' #第幾條 # 最大每頁顯得條數 max_limit = None class MyCursorPagination(CursorPagination): # URL傳入的遊標參數 cursor_query_param = 'cursor' # 默認每頁顯示的數據條數 page_size = 2 # URL傳入的每頁顯示條數的參數 page_size_query_param = 'page_size' # 每頁顯示數據最大條數 max_page_size = 500 # 根據ID從大到小排列 ordering = "id" class PagerView2(APIView): ''' http://127.0.0.1:8000/api/v1/page/02/ 獲取數據 http://127.0.0.1:8000/api/v1/page/02/?page=2 獲取具體頁碼數據 http://127.0.0.1:8000/api/v1/page/02/?page=2&page_size=3 用戶還能本身指定每頁條數 ''' def get(self, request, *args, **kwargs): roles = models.Role.objects.all() # 實例化分頁對象,獲取數據庫中的分頁數據 paginator = MyPageNumberPagination() page_user_list = paginator.paginate_queryset(roles, self.request, view=self) # 分頁的方法 # 序列化分頁後的對象 serializer = MytestSerialiser(page_user_list, many=True) # 生成分頁和數據 response = paginator.get_paginated_response(serializer.data) # 內部執行Response方法 return response
以GenericAPIView爲例,繼承自APIView。與django的GenericView思路及其類似(雞肋) 我的認爲類通用視圖比較雞肋,並且耦合性太強,能不用就不用 可是在使用視圖集時,這東西就必須用了
class View1View(GenericAPIView): # APIView queryset = models.Role.objects.all() serializer_class = PagerSerialiser pagination_class = PageNumberPagination def get(self,request,*args,**kwargs): # 獲取數據 roles = self.get_queryset() # models.Role.objects.all() # [1, 1000,] [1,10] pager_roles = self.paginate_queryset(roles) # 序列化 ser = self.get_serializer(instance=pager_roles,many=True) return Response(ser.data)
Django REST framework 容許將一組相關視圖的邏輯組合到一個稱爲 ViewSet 的類中 ViewSet 類只是一種基於類的 View,它不提供任何處理方法,如 .get() 或 .post(),而是提供諸如 .list() 和 .create() 之類的操做。 ViewSet 只在用 .as_view() 方法綁定到最終化視圖時作一些相應操做。 一般,不是在 urlconf 中的視圖集中明確註冊視圖,而是使用路由器類註冊視圖集,這會自動爲您肯定 urlconf。
映射關係須要本身寫在urlpatterns裏:
'get': 'retrieve', 'get': 'list', 'post':'create' 'delete': 'destroy', 'put': 'update', 'patch': 'partial_update',
最全的類繼承,就是繼承ModelViewSet,包含則增刪改查全部的方法
class ModelViewSet(mixins.CreateModelMixin, mixins.RetrieveModelMixin, mixins.UpdateModelMixin, mixins.DestroyModelMixin, mixins.ListModelMixin, GenericViewSet): """ A viewset that provides default `create()`, `retrieve()`, `update()`, `partial_update()`, `destroy()` and `list()` actions. """ pass
增刪改查全繼承: class View2View(ModelViewSet): 少來點: class View3View(ListModelMixin,CreateModelMixin,GenericViewSet):
對應路由的寫法:
# 若是不使用router ,get的映射要本身寫兩遍,不帶pk參數映射list 帶pk映射retrieve # 由於視圖集把get方法拆開了,在視圖集裏對應兩個類 url(r'^(?P<version>[v1|v2]+)/viewset/$', views.View2View.as_view({'get': 'list','post':'create'})), url(r'^(?P<version>[v1|v2]+)/viewset/(?P<pk>\d+)/$', views.View2View.as_view({'get': 'retrieve', 'delete': 'destroy', 'put': 'update', 'patch': 'partial_update', })), url(r'^(?P<version>[v1|v2]+)/viewset3/$', views.View3View.as_view({'get': 'list','post':'create'})),
genericviewset的第一個父類 ViewSetMixin 改寫了as_view方法 路由規則改變了,因此要本身在url後邊加{'get','xxx'}參數
Modelviewset,它繼承6個類,功能最全
【小結】 使用的時候 APIView - Genericviewset - modelviewset 功能愈來愈全,代碼愈來愈少,耦合愈來愈強
Genericviewset 與增刪改查 聯合做爲父類 也行,靈活應用
補充了一個更細粒度的權限管理,以前是全局權限,引入這個以後能夠作對象級別的權限管理
Genericviewset惟一的好處:獲取列表/單個對象 作出了區分
這倆東西是摻和在一塊的
urlpatterns = [ url(r'^test/$', views.TestView.as_view()), url(r'^test/(?P<pk>[^/.]+)/$', views.TestView.as_view()), url(r'^test\.(?P<format>[a-z0-9]+)$', views.TestView.as_view()), url(r'^test/(?P<pk>[^/.]+)\.(?P<format>[a-z0-9]+)$', views.TestView.as_view()) ]
前邊兩個是 爲列表/對象查詢作的區分 後邊兩個引入的那個format / pk+format 純粹是爲了支持渲染器寫的 若是公司項目僅適用json,那渲染器就沒什麼用了。
urlpatterns = [ url(r'^test/$', views.UserViewSet.as_view({'get': 'list', 'post': 'create'})), url(r'^test/(?P<pk>\d+)/$', views.UserViewSet.as_view( {'get': 'retrieve', 'put': 'update', 'patch': 'partial_update', 'delete': 'destroy'})), ]
from django.conf.urls import url, include from rest_framework import routers from api import views router = routers.DefaultRouter() router.register(r'users', views.UserViewSet) urlpatterns = [ url(r'^', include(router.urls)),
視圖函數中:
from rest_framework.viewsets import ModelViewSet from rest_framework import serializers from .. import models class UserSerializer(serializers.ModelSerializer): class Meta: model = models.UserInfo fields = "__all__" class UserViewSet(ModelViewSet): queryset = models.UserInfo.objects.all() serializer_class = UserSerializer
include(router.urls) 一句幫咱們生成對應的4種url,省點事
這基本就是restful官網教程的quickstart了,寫的是爽了,但在生產環境中徹底沒意義。
from rest_framework.renderers import JSONRenderer,BrowsableAPIRenderer
···\site-packages\rest_framework\settings.py 默認的渲染器
'DEFAULT_RENDERER_CLASSES': ( 'rest_framework.renderers.JSONRenderer', 'rest_framework.renderers.TemplateHTMLRenderer', )
自定義: 全局settings裏設置RENDERER_CLASSES 值 或者 視圖裏本身指定 renderer_classes = [JSONRenderer,BrowsableAPIRenderer]
默認就有json啊:這三種方式都能訪問
http://127.0.0.1:8000/test/?format=json http://127.0.0.1:8000/test.json http://127.0.0.1:8000/test/
JSONRenderer 對應的 media_type = 'application/json' format = 'json'
BrowsableAPIRenderer 對應的 media_type = 'text/html' format = 'api'
一共有10來種渲染器,每種對應的format字段名稱都不同
路由和渲染器從根上說是兩碼事, 引入渲染器會致使url書寫變得很蛋疼,那就再引入個路由器,表面上掩蓋一下。
恩,就這樣