模型类
from django.db import models
# Create your models here.
class Category(models.Model):
name = models.CharField(verbose_name='名字', max_length=100)
def __str__(self):
return self.name
class Article(models.Model):
title = models.CharField(verbose_name='标题', max_length=100)
vnum = models.IntegerField(verbose_name='浏览量')
content = models.TextField(verbose_name='内容')
category = models.ForeignKey(to=Category, on_delete=models.CASCADE, related_name='articles') # related_name 反向查找
def __str__(self):
return self.title
路由
from django.contrib import admin
from django.urls import path, include
from . import views
urlpatterns = [
path('articles/', views.article_list), # 获取或创建
path('articles/<int:id>/', views.article_detail), # 查找、更新、删除
]
视图
from django.http import HttpResponse
from django.views.decorators.csrf import csrf_exempt
from rest_framework.renderers import JSONRenderer
from rest_framework.parsers import JSONParser
from .models import Article
from .serializers import ArticleSerializer
class JSONResponse(HttpResponse):
"""
An HttpResponse that renders its content into JSON.
"""
def __init__(self, data, **kwargs):
content = JSONRenderer().render(data)
kwargs['content_type'] = 'application/json'
super(JSONResponse, self).__init__(content, **kwargs)
@csrf_exempt
def article_list(request):
if request.method == 'GET':
articles = Article.objects.all()
serializer = ArticleSerializer(articles, many=True)
return JSONResponse(serializer.data)
elif request.method == 'POST':
data = JSONParser().parse(request)
serializer = ArticleSerializer(data=data)
if serializer.is_valid():
serializer.save()
return JSONResponse(serializer.data, status=201)
return JSONResponse(serializer.errors, status=400)
@csrf_exempt
def article_detail(request, id):
try:
article = Article.objects.get(id=id)
except Article.DoesNotExist:
return HttpResponse(status=404)
if request.method == 'GET':
serializer = ArticleSerializer(article)
return JSONResponse(serializer.data)
elif request.method == 'PUT':
data = JSONParser().parse(request)
serializer = ArticleSerializer(article, data=data)
if serializer.is_valid():
serializer.save()
return JSONResponse(serializer.data)
return JSONResponse(serializer.errors, status=400)
elif request.method == 'DELETE':
article.delete()
return HttpResponse(status=204)
StringRelatedField
StringRelatedField 将返回一个对应关系 model 的 unicode() 方法的字符串。
文章—>分类
from rest_framework import serializers
from .models import Article
class ArticleSerializer(serializers.ModelSerializer):
category = serializers.StringRelatedField()
class Meta:
model = Article
# fields = ('id', 'title', 'vnum', 'content', 'category')
fields = '__all__'
分类—->文章
路由
urlpatterns = [
path('categorys/', views.category_list), # 查找、更新、删除
path('categorys/<int:id>/', views.category_detail), # 查找、更新、删除
]
视图
@csrf_exempt
def category_list(request):
if request.method == 'GET':
categorys = Category.objects.all()
serializer = CategorySerializer(categorys, many=True)
return JSONResponse(serializer.data)
elif request.method == 'POST':
data = JSONParser().parse(request)
serializer = CategorySerializer(data=data)
if serializer.is_valid():
serializer.save()
return JSONResponse(serializer.data, status=201)
return JSONResponse(serializer.errors, status=400)
@csrf_exempt
def category_detail(request, id):
try:
category = Category.objects.get(id=id)
except Category.DoesNotExist:
return HttpResponse(status=404)
if request.method == 'GET':
serializer = CategorySerializer(category)
return JSONResponse(serializer.data)
elif request.method == 'PUT':
data = JSONParser().parse(request)
serializer = CategorySerializer(category, data=data)
if serializer.is_valid():
serializer.save()
return JSONResponse(serializer.data)
return JSONResponse(serializer.errors, status=400)
elif request.method == 'DELETE':
category.delete()
return HttpResponse(status=204)
序列化
class CategorySerializer(serializers.ModelSerializer):
articles = serializers.StringRelatedField(many=True)
class Meta:
model = Category
fields = '__all__'
PrimaryKeyRelatedField
使用 PrimaryKeyRelatedField 将返回一个对应关系 model 的主键。
参数:
- queryset 用于在验证字段输入时模型实例查找。 关系必须明确设置 queryset,或设置 read_only = True
- many 如果是对应多个的关系,就设置为 True
- allow_null 如果设置为 True,则该字段将接受 None 的值或为空的关系的空字符串。默认为 False
- pk_field 设置为一个字段以控制主键值的序列化/反序列化。例如,pk_field = UUIDField(format =’hex’) 将UUID主键序列化为紧凑的十六进制表示。
序列化
class CategorySerializer(serializers.ModelSerializer):
articles = serializers.PrimaryKeyRelatedField(many=True, read_only=True)
class Meta:
model = Category
fields = '__all__'
HyperlinkedRelatedField
使用 HyperlinkedRelatedField 将返回一个超链接,该链接指向对应关系 model 的详细数据,view-name 是必选参数,为对应的视图生成超链接。
参数:
- view_name 用作关系目标的视图名称。如果使用的是标准路由器类,那么它的格式为 <modelname>-detail 的字符串
- queryset 验证字段输入时用于模型实例查询的查询器。关系必须明确设置 queryset,或设置 read_only = True
- many 如果应用于多对多关系,则应将此参数设置为 True
- allow_null 如果设置为 True,则该字段将接受 None 的值或为空的关系的空字符串。默认为 False
- lookup_field 应该用于查找的目标上的字段。应该对应于引用视图上的 URL 关键字参数。默认值为 pk
- lookup_url_kwarg 与查找字段对应的 URL conf 中定义的关键字参数的名称。默认使用与 lookup_field 相同的值
- format 如果使用 format 后缀,超链接字段将对目标使用相同的 format 后缀,除非使用 format 参数进行覆盖。
class CategorySerializer(serializers.ModelSerializer):
articles = serializers.HyperlinkedRelatedField(
many=True,
read_only=True,
view_name='article_detail', # 路由的别名
lookup_field='id', # 数据库字段的名字
lookup_url_kwarg="id" # 路由中参数的名字
)
class Meta:
model = Category
fields = '__all_
错误解决
`HyperlinkedRelatedField` requires the request in the serializer context. Add `context={'request': request}` when instantiating the serializer.
在所有使用CategorySerializerde的地方加上context={‘request’: request}
serializer = CategorySerializer(categorys, many=True, context={'request': request})
SlugRelatedField
使用 SlugRelatedField 将返回一个指定对应关系 model 中的字段,需要参数 slug_field 中指定字段名称。
参数:
- slug_field 应该用于表示目标的字段。这应该是唯一标识任何给定实例的字段。例如 username 。这是必选参数
- queryset 验证字段输入时用于模型实例查询的查询器。 关系必须明确设置 queryset,或设置 read_only = True
- many 如果应用于多对多关系,则应将此参数设置为 True
- allow_null 如果设置为 True,则该字段将接受 None 的值或为空的关系的空字符串。默认为 False
class CategorySerializer(serializers.ModelSerializer):
articles = serializers.SlugRelatedField(
many=True,
read_only=True,
slug_field='title'
)
class Meta:
model = Category
fields = '__all__'
HyperlinkedIdentityField
使用 HyperlinkedIdentityField 将返回指定 view-name 的超链接的字段。
参数:
- view_name 应该用作关系目标的视图名称。如果您使用的是标准路由器类,则它将是格式为 <model_name>-detail的字符串。必选参数
- lookup_field 应该用于查找的目标上的字段。应该对应于引用视图上的 URL 关键字参数。默认值为 pk
- lookup_url_kwarg 与查找字段对应的 URL conf 中定义的关键字参数的名称。默认使用与 lookup_field 相同的值
- format 如果使用 format 后缀,超链接字段将对目标使用相同的 format 后缀,除非使用 format 参数进行覆盖
class ArticleSerializer(serializers.ModelSerializer):
category = serializers.HyperlinkedIdentityField(view_name="app03:category-detail", lookup_field='id')
class Meta:
model = Article
fields = '__all__'
class CategorySerializer(serializers.ModelSerializer):
articles = serializers.HyperlinkedIdentityField(view_name="app03:article-detail", lookup_field='id', many=True)
class Meta:
model = Category
fields = '__all__'
HyperlinkedModelSerializer
HyperlinkedModelSerializer
类与 ModelSerializer
类相似,只不过它使用超链接来表示关系而不是主键。
class ArticleSerializer(serializers.HyperlinkedModelSerializer):
class Meta:
model = Article
fields = '__all__'
extra_kwargs = {
'url': {'view_name': 'app04:article-detail', 'lookup_field': 'id'},
'category': {'view_name': 'app04:category-detail', 'lookup_field': 'id'},
}
class CategorySerializer(serializers.HyperlinkedModelSerializer):
class Meta:
model = Category
fields = ('id', 'name', 'articles')
extra_kwargs = {
'url': {'view_name': 'app04:category-detail', 'lookup_field': 'id'},
'articles': {'view_name': 'app04:article-detail', 'lookup_field': 'id'},
}
'''
使用extra_kwargs参数为ModelSerializer添加或修改原有的选项参数---字典格式
extra_kwargs = {
'vnum': {'min_value': 0, 'required': True},
}
'''
嵌套序列化关系模型
顾名思义就是序列化里面有另一个序列化类
class ArticleSerializer(serializers.ModelSerializer):
class Meta:
model = Article
fields = '__all__'
class CategorySerializer(serializers.ModelSerializer):
articles = ArticleSerializer(many=True)
class Meta:
model = Category
fields = '__all__'
depth
这个字段可以用来深度遍历
#注意是ModelSerializer
class CategorySerializer(serializers.ModelSerializer):
articles = ArticleSerializer(many=True)
class Meta:
model = Category
fields = '__all__'
depth = 2
SerializerMethodField
通过这个属性我们可以自定义一些属性。
class CategorySerializer(serializers.ModelSerializer):
articles = ArticleSerializer(many=True)
count = serializers.SerializerMethodField()
class Meta:
model = Category
fields = '__all__'
depth = 2
def get_count(self, obj):
return Category.objects.count()
source
序列化的时候指定数据源
class ArticleSerializer(serializers.ModelSerializer):
category = serializers.CharField(source='category.name')
class Meta:
model = Article
fields = '__all__'
class MyCharField(serializers.CharField):
def to_representation(self, value):
data_list = []
for row in value:
data_list.append({'title': row.title, 'content': row.content})
return data_list
class CategorySerializer(serializers.ModelSerializer):
arts = MyCharField(source='articles.all')
# arts = serializers.CharField(source='articles.all')
class Meta:
model = Category
fields = ('id', 'name', 'arts')
利用source实现可读可写
from collections import OrderedDict
class ChoiceDisplayField(serializers.Field):
"""Custom ChoiceField serializer field."""
def __init__(self, choices, **kwargs):
"""init."""
self._choices = OrderedDict(choices)
super(ChoiceDisplayField, self).__init__(**kwargs)
# 返回可读性良好的字符串而不是 1,-1 这样的数字
def to_representation(self, obj):
"""Used while retrieving value for the field."""
return self._choices[obj]
def to_internal_value(self, data):
"""Used while storing value for the field."""
for i in self._choices:
# 这样无论用户POST上来但是CHOICES的 Key 还是Value 都能被接受
if i == data or self._choices[i] == data:
return i
raise serializers.ValidationError("Acceptable values are {0}.".format(list(self._choices.values())))
to_representation方法
序列化器的每个字段实际都是由该字段类型的to_representation方法决定格式的,可以通过重写该方法来决定格式。
class ArticleSerializer(serializers.ModelSerializer):
class Meta:
model = Article
fields = '__all__'
def to_representation(self, instance):
representation = super(ArticleSerializer, self).to_representation(instance)
representation['category'] = CategorySerializer(instance.category).data
representation['tags'] = TagSerializer(instance.tags, many=True).data
return representation