drf框架day3

1.多表与基表概念

2.多表断关联关系分析

3.多表序列化组件

4.自定义序列化深度连表查询

5.多表反序列化组件

6.序列化反序列化整合(重点)

7.群增接口实现

8.单删群删接口实现

课程准备:配置settings.py

 1 INSTALLED_APPS = [
 2     # ...
 3     'rest_framework',
 4 ]
 5 
 6 DATABASES = {
 7     'default': {
 8         'ENGINE': 'django.db.backends.mysql',
 9         'NAME': 'dg_proj',
10         'USER': 'root',
11         'PASSWORD': '123',
12     }
13 }
14 """
15 任何__init__文件
16 import pymysql
17 pymysql.install_as_MySQLdb()
18 """
19 
20 LANGUAGE_CODE = 'zh-hans'
21 TIME_ZONE = 'Asia/Shanghai'
22 USE_I18N = True
23 USE_L10N = True
24 USE_TZ = False
25 
26 MEDIA_URL = '/media/'
27 MEDIA_ROOT = os.path.join(BASE_DIR, 'media')
代码

路由:

 1 #
 2 from django.conf.urls import url, include
 3 from django.contrib import admin
 4 from django.views.static import serve
 5 from django.conf import settings
 6 urlpatterns = [
 7     url(r'^admin/', admin.site.urls),
 8     url(r'^api/', include('api.urls')),
 9     url(r'^media/(?P<path>.*)', serve, {'document_root': settings.MEDIA_ROOT}),
10 ]
11 
12 #
13 from django.conf.urls import url
14 from . import views
15 urlpatterns = [
16     
17 ]
代码

一.多表与基表概念

多表设计(有哪些表):

 1 """
 2 Book表:name、price、img、authors、publish、is_delete、create_time
 3 
 4 Publish表:name、address、is_delete、create_time
 5     
 6 Author表:name、age、is_delete、create_time
 7 
 8 AuthorDetail表:mobile, author、is_delete、create_time
 9     
10 BaseModel基表
11     is_delete、create_time
12 上面四表继承基表,可以继承两个字段
13 """
代码

什么是基表:

# 基表,其他的表需要用到的就继承
class BaseModel(models.Model):
    is_delete = models.BooleanField(default=False)
    create_time = models.DateTimeField(auto_now_add=True)

    # 设置 abstract = True 来声明基表,作为基表的Model不能再数据库中形成对应的表
    class Meta:
        abstract = True

二.多表断关联关系分析

多表断关联关系所有知识点:

 1 """
 2 1、外键位置:
 3     一对多 - 外键放多的一方
 4     一对一 - 从逻辑正反向考虑,如作者表与作者详情表,作者删除级联删除详情,详情删除作者依旧存在,所以建议外键在详情表中
 5     多对多 - 外键在关系表中
 6     
 7 2、ORM正向方向连表查找:
 8     正向:通过外键字段 eg: author_detial_obj.author 
 9     反向:通过related_name的值 eg:author_obj.detail
10     注:依赖代码见下方
11     
12 3、连表操作关系:
13     1)作者删除,详情级联 - on_delete=models.CASCADE
14     2)作者删除,详情置空 - null=True, on_delete=models.SET_NULL
15     3)作者删除,详情重置 - default=0, on_delete=models.SET_DEFAULT
16     4)作者删除,详情不动 - on_delete=models.DO_NOTHING
17     注:拿作者与作者详情表举例
18     
19 4、外键关联字段的参数 - 如何实现 断关联、目前表间操作关系、方向查询字段
20     i)作者详情表中的
21     author = models.OneToOneField(
22         to='Author',
23         related_name='detail', 反向查询的时候就不用表名小写了,可以写你自定义的
24         db_constraint=False, 断关联
25         on_delete=models.CASCADE 级联
26     )
27     
28     ii)图书表中的
29     publish = models.ForeignKey(
30         to='Publish',
31         related_name='books',
32         db_constraint=False,
33         on_delete=models.DO_NOTHING,  删除一方,另一方不动
34     )
35     authors = models.ManyToManyField(
36         to='Author'
37         related_name='books',
38         db_constraint=False,
39     )
40     注:ManyToManyField不能设置on_delete,OneToOneField、ForeignKey必须设置on_delete(django1.x系统默认级联,但是django2.x必须手动明确)
41 """
知识点

model类:

  1 from django.db import models
  2 
  3 # Create your models here.
  4 
  5 
  6 # 基表,其他的表需要用到的就继承
  7 class BaseModel(models.Model):
  8     is_delete = models.BooleanField(default=False)
  9     create_time = models.DateTimeField(auto_now_add=True)
 10 
 11     # 设置 abstract = True 来声明基表,作为基表的Model不能再数据库中形成对应的表
 12     class Meta:
 13         abstract = True
 14 
 15 # 图书管理系统表:Book,Author,AuthorDetail,Publish
 16 '''
 17 Book表: name、price、img、authors、publish、is_delete、create_time
 18 Publish表: name、address、is_delete、create_time
 19 Author表: name、age、is_delete、create_time
 20 AuthorDetail表: mobile, author、is_delete、create_time
 21 '''
 22 class Book(BaseModel):
 23     name = models.CharField(max_length=64)
 24     price = models.DecimalField(max_digits=5,decimal_places=2)
 25     img = models.ImageField(upload_to='img',default='img/default.jpg')
 26     # 书籍表一对多出版社
 27     publish = models.ForeignKey(
 28         to='Publish',
 29         db_constraint=False, # 断关联
 30         related_name='books', # 反向查询字段:publish_obj.books 就能访问所有出版的书
 31         on_delete=models.DO_NOTHING,# 设置连表操作关系
 32     )
 33     # 就是一个方法属性,可以利用插拔式给前台返回数据
 34         # 序列化插拔式属性 - 完成自定义字段名完成连表查询
 35     @property
 36     def publish_name(self):
 37         return self.publish.name
 38 
 39     @property
 40     def author_list(self):
 41         return self.authors.values('name','age','detail__mobile').all()
 42 
 43 
 44 
 45 
 46     # 数据表对多对作者表
 47     authors = models.ManyToManyField(
 48         to='Author',
 49         db_constraint=False,
 50         related_name='books',
 51 
 52     )
 53     class Meta:
 54         db_table = 'book'
 55         verbose_name = '书籍'
 56         verbose_name_plural = verbose_name
 57     def __str__(self):
 58         return self.name
 59 
 60 
 61 class Publish(BaseModel):
 62     name = models.CharField(max_length=64)
 63     address = models.CharField(max_length=64)
 64 
 65     class Meta:
 66         db_table = 'publish'
 67         verbose_name = '出版社'
 68         verbose_name_plural = verbose_name
 69     def __str__(self):
 70         return self.name
 71 
 72 class Author(BaseModel):
 73     name = models.CharField(max_length=64)
 74     age = models.IntegerField()
 75 
 76     class Meta:
 77         db_table = 'author'
 78         verbose_name = '作者'
 79         verbose_name_plural = verbose_name
 80 
 81     def __str__(self):
 82         return self.name
 83 
 84 
 85 class AuthorDetail(BaseModel):
 86     mobile = models.CharField(max_length=11)
 87     # 一多一作者表
 88     author = models.OneToOneField(
 89         to='Author',
 90         db_constraint=False, # 断关联,数据库没有了联系,但是逻辑上还有
 91         # 现在反向查可以直接通过自定义的这个名字
 92         related_name='detail',
 93         on_delete=models.DO_NOTHING,
 94 
 95 
 96     )
 97 
 98     class Meta:
 99         db_table = 'author_detail'
100         verbose_name = '作者详情'
101         verbose_name_plural = verbose_name
102 
103     def __str__(self):
104         return '%s的详情'% self.author.name
model类里面的代码

三.多表序列化组件

序列化层:api/serializers.py

1 from rest_framework.serializers import ModelSerializer
2 from . import models
3 class BookModelSerializer(ModelSerializer):
4     class Meta:
5         # 需要序列化的model类,
6         model = models.Book
7         # 我要返回给前台哪些字段 也可以称为插拔式,不想反回了,就不写
8         fields = ('name','price','publish_name','author_list')
重点代码
 1 from rest_framework.serializers import ModelSerializer, SerializerMethodField
 2 from rest_framework.exceptions import ValidationError
 3 from . import models
 4 
 5 # 可以单独作为Publish接口的序列化类,也可以作为Book序列化外键publish辅助的序列化组件
 6 class PublishModelSerializer(ModelSerializer):
 7     class Meta:
 8         # 序列化类关联的model类
 9         model = models.Publish
10         # 参与序列化的字段
11         fields = ('name', 'address')
12 
13 class BookModelSerializer(ModelSerializer):
14     # 了解: 该方式设置的序列化字段,必须在fields中声明
15     # publish_address = SerializerMethodField()
16     # def get_publish_address(self, obj):
17     #     return obj.publish.address
18 
19     # 自定义连表深度 - 子序列化方式 - 该方式不能参与反序列化,使用在序列化反序列化共存时,不能书写
20     publish = PublishModelSerializer()
21 
22     class Meta:
23         # 序列化类关联的model类
24         model = models.Book
25         # 参与序列化的字段
26         fields = ('name', 'price', 'img', 'author_list', 'publish')
27 
28         # 了解知识点
29         # 所有字段
30         # fields = '__all__'
31         # 与fields不共存,exclude排除哪些字段
32         # exclude = ('id', 'is_delete', 'create_time')
33         # 自动连表深度
34         # depth = 1
详细代码,还有一些了解知识点 自定义序列化深度连表查询

视图层:api/views.py

 1 # 负责请求过来的
 2 from rest_framework.views import APIView
 3 # 负责响应的
 4 from rest_framework.response import Response
 5 # 负责模型与序列化的
 6 from . import models,serializers
 7 
 8 class Book(APIView):
 9     def get(self,request,*args,**kwargs):
10         pk = kwargs.get('pk')
11         if pk:
12             try:
13                 book_obj = models.Book.objects.get(pk=pk)
14                 book_data = serializers.BookModelSerializer(book_obj).data
15             except:
16                 return Response({
17                     'status':1,
18                     'msg':'书籍不存在',
19                 })
20         else:
21             book_query = models.Book.objects.all()                  # 因为是一个列表,有多个值
22             book_data = serializers.BookModelSerializer(book_query,many=True).data
23         return Response({
24             'status': 0,
25             'msg': 'ok',
26             'results':book_data
27         })
视图层代码

路由层:api/urls.py

 1 子路由:
 2 from django.conf.urls import url
 3 from . import views
 4 
 5 # 子路由
 6 urlpatterns = [
 7     url(r'^books/$',views.Book.as_view()),
 8     url(r'^books/(?P<pk>.*)/$',views.Book.as_view()),
 9 
10 ]
11 
12 主路由:
13 # 路由分发先导入include
14 from django.conf.urls import url,include
15 from django.contrib import admin
16 from django.conf import settings
17 from django.views.static import serve
18 
19 urlpatterns = [
20     url(r'^admin/', admin.site.urls),
21     # 路由分发
22     url(r'^api/', include('api.urls')),
23     # 把放置图片的文件接口开放
24     url(r'^media/(?P<path>.*)', serve, {'document_root': settings.MEDIA_ROOT}),
25 ]
路由层代码

五.多表反序列化组件

序列化层:api/serializers.py

注意点:  ModelSerializer类已经帮我们实现了 create 与 update 方法

     extra_kwargs 用来完成反序列化字段的 系统校验规则

 1 class BookModelDeserializer(ModelSerializer):
 2     class Meta:
 3         # 需要序列化的model类,
 4         model = models.Book
 5         # 我要返回给前台哪些字段 也可以称为插拔式,不想反回了,就不写
 6         fields = ('name', 'price','publish','authors')
 7 
 8         # extra_kwargs 用来完成反序列化字段的系统校验规则
 9         # required=True 就是代表这个字段也要校验,error_messages自定义报错信息
10         extra_kwargs = {
11             'name':{
12                 'required':True,
13                 'min_length':1,
14                 'error_messages':{
15                     'required':'必填项',
16                     'min_length':'太短',
17                 }
18             }
19         }
20 
21     #局部钩子
22     def validate_name(self,value):
23         # 书名不能包含g字符
24         if 'g' in value.lower():
25             raise ValidationError('书名不能包含g')
26         # 如果不包含g就可以出版
27         return value
28 
29     #全局钩子 同一个出版社不能出名字相同的书
30     def validate(self, attrs):
31         publish = attrs.get('publish')
32         name = attrs.get('name')
33         # 如果判断成立就抛异常
34         if models.Book.objects.filter(name=name,publish=publish):
35         # 全局的可以规定一下key和value
36             raise ValidationError({'book':'该书已存在'})
37         return attrs
序列化层代码

视图层:api/views.py

 1 class Book(APIView):
 2     def post(self, request, *args, **kwargs):
 3         request_data = request.data
 4         book_ser = serializers.BookModelDeserializer(data=request_data)
 5         # raise_exception=True:当校验失败,马上终止当前视图方法,抛异常返回给前台
 6         book_ser.is_valid(raise_exception=True)
 7         book_obj = book_ser.save()
 8         return Response({
 9             'status': 0,
10             'msg': 'ok',
11             'results': serializers.BookModelSerializer(book_obj).data
12         })
视图层代码

路由层:api/urls.py

 1 主路由:
 2 # 路由分发先导入include
 3 from django.conf.urls import url,include
 4 from django.contrib import admin
 5 from django.conf import settings
 6 from django.views.static import serve
 7 
 8 urlpatterns = [
 9     url(r'^admin/', admin.site.urls),
10     # 路由分发
11     url(r'^api/', include('api.urls')),
12     # 把放置图片的文件接口开放
13     url(r'^media/(?P<path>.*)', serve, {'document_root': settings.MEDIA_ROOT}),
14 ]
15 
16 子路由:
17 from django.conf.urls import url
18 
19 from . import views
20 
21 urlpatterns = [
22     url(r'^books/$', views.Book.as_view()),
23     url(r'^books/(?P<pk>.*)/$', views.Book.as_view()),
24 
25 ]
路由层代码

六.序列化反序列化整合(重点)里面包含了群增接口实现,单删群删接口实现

序列化层:api/serializers.py

注意点:

"""
1) fields中设置所有序列化与反序列化字段
2) extra_kwargs划分只序列化或只反序列化字段
    write_only:只反序列化
    read_only:只序列化
    自定义字段默认只序列化(read_only)
 自定义字段也可以不需要写,因为自定义的字段是只读,数据库不需要,默认就是read_only
3) 设置反序列化所需的 系统、局部钩子、全局钩子 等校验规则
"""
 1 # 序列化与反序列化整合版本
 2 class V2BookModelSerializer(ModelSerializer):
 3     class Meta:
 4         # 需要序列化的model类,
 5         model = models.Book
 6         # 我要返回给前台哪些字段 也可以称为插拔式,不想反回了,就不写
 7         # 因为现在序列化和反序列化整合在一起了,所以不管序列化数据还是反序列化数据都要写上
 8         # 但是也出现了一些问题,就是序列化的时候,反序列化的字段也出现了,这个时候就需要用到了extra_kwargs
 9         fields = ('name', 'price','img','author_list','publish_name','publish','authors')
10         extra_kwargs = {
11             'name': {
12                 'required': True,
13                 'min_length': 1,
14                 'error_messages': {
15                     'required': '必填项',
16                     'min_length': '太短',
17                 }
18             },
19             'publish':{
20                 # 只参加反序列化的字段
21                 'write_only':True
22             },
23             'author':{
24                 'write_only':True
25             },
26             # 只参加序列化的字段
27             'img':{
28                 'read_only':True
29             },
30             # 下面俩个字段也可以不需要,因为自定义的字段是只读,数据库不需要,默认就是read_only
31             'author_list': {
32                 'read_only': True
33             },
34             'publish_name': {
35                 'read_only': True
36             }
37 
38         }
39         # 局部钩子
40 
41     def validate_name(self, value):
42         # 书名不能包含g字符
43         if 'g' in value.lower():
44             raise ValidationError('书名不能包含g')
45         # 如果不包含g就可以出版
46         return value
47 
48         # 全局钩子 同一个出版社不能出名字相同的书
49 
50     def validate(self, attrs):
51         publish = attrs.get('publish')
52         name = attrs.get('name')
53         # 如果判断成立就抛异常
54         if models.Book.objects.filter(name=name, publish=publish):
55             # 全局的可以规定一下key和value
56             raise ValidationError({'book': '该书已存在'})
57         return attrs
代码

视图层:api/views.py

注意点:

单查:有pk
群查:无pk
    # 单增:传的数据是与model对应的字典
    # 群增:传的数据是 装多个model对应字典的列表


    # 单删:有pk
    # 群删:有pks  群删的形式:{"pks":[1,2,3]}
    # 单删和群删不需要序列化的处理,因为它就是改一下字段
如果是群增和群删需要指定一个参数:many=True
 1 # 负责请求过来的
 2 from rest_framework.views import APIView
 3 # 负责响应的
 4 from rest_framework.response import Response
 5 # 负责模型与序列化的
 6 from . import models,serializers
 7 
 8 # 序列化与反序列化整合版本
 9 class V2Book(APIView):
10     # 单查:有pk
11     # 群查:无pk
12     def get(self,request,*args,**kwargs):
13         pk = kwargs.get('pk')
14         if pk:
15             try:
16                 book_obj = models.Book.objects.get(pk=pk)
17                 book_data = serializers.V2BookModelSerializer(book_obj).data
18             except:
19                 return Response({
20                     'status':1,
21                     'msg':'书籍不存在',
22                 })
23         else:
24             book_query = models.Book.objects.all()                  # 因为是一个列表,有多个值
25             book_data = serializers.V2BookModelSerializer(book_query,many=True).data
26         return Response({
27             'status': 0,
28             'msg': 'ok',
29             'results':book_data
30         })
31 
32     # 单增:传的数据是与model对应的字典
33     # 群增:传的数据是 装多个model对应字典的列表
34     def post(self, request, *args, **kwargs):
35         request_data = request.data
36         # 如何完成群增,可以把问题想的简单一点,就字典就是单增,列表就是群增
37         # 判断如果request_data就走单增的逻辑
38         if isinstance(request_data,dict):
39             many = False  # 单增就是many=False ,也就是说不需要many
40         elif isinstance(request_data, list):
41             # 如果是list就走群增的逻辑 ,只要写了many=True就可以序列化和反序列化多个
42             many = True
43         else:
44             # 如果都不成立就是数据有问题
45             return Response({
46                 'status': 1,
47                 'msg': '数据有误',
48             })
49         book_ser = serializers.V2BookModelSerializer(data=request_data, many=many)
50         # 当校验失败,马上终止当前视图方法,抛异常返回给前台
51         book_ser.is_valid(raise_exception=True)
52         book_result = book_ser.save() # 序列化的结果调用保存方法
53         return Response({
54             'status': 0,
55             'msg': 'ok',                       # 如果要是多增,返回给前台数据也需要many=True
56             'results': serializers.V2BookModelSerializer(book_result,many=many).data
57         })
58 
59     # 单删:有pk
60     # 群删:有pks  群删的形式:{"pks":[1,2,3]}
61     # 单删和群删不需要序列化的处理,因为它就是改一下字段
62     def delete(self, request, *args, **kwargs):
63         pk = kwargs.get('pk')
64         if pk:
65             # 把单删和群删统一了
66             pks = [pk]
67         else:
68             pks = request.data.get('pks')         # 不能重复删除
69         if models.Book.objects.filter(pk__in=pks,is_delete=False).update(is_delete=True):
70             return Response({
71                 'status':0,
72                 'msg':'删除成功',
73             })
74         else:
75             return Response({
76                 'status': 1,
77                 'msg': '删除失败',
78             })
视图层代码

路由层:api/urls.py

urlpatterns = [
    url(r'^v2/books/$', views.V2Book.as_view()),
    url(r'^v2/books/(?P<pk>.*)/$', views.V2Book.as_view()),
]
class BookModelDeserializer(ModelSerializer):
class Meta:
# 需要序列化的model类,
model = models.Book
# 我要返回给前台哪些字段 也可以称为插拔式,不想反回了,就不写
fields = ('name', 'price','publish','authors')

# extra_kwargs 用来完成反序列化字段的系统校验规则
# required=True 就是代表这个字段也要校验,error_messages自定义报错信息
extra_kwargs = {
'name':{
'required':True,
'min_length':1,
'error_messages':{
'required':'必填项',
'min_length':'太短',
}
}
}

#局部钩子
def validate_name(self,value):
# 书名不能包含g字符
if 'g' in value.lower():
raise ValidationError('书名不能包含g')
# 如果不包含g就可以出版
return value

#全局钩子 同一个出版社不能出名字相同的书
def validate(self, attrs):
publish = attrs.get('publish')
name = attrs.get('name')
# 如果判断成立就抛异常
if models.Book.objects.filter(name=name,publish=publish):
# 全局的可以规定一下key和value
raise ValidationError({'book':'该书已存在'})
return attrs

猜你喜欢

转载自www.cnblogs.com/zahngyu/p/11695816.html