一、前戏要做好

配置:settings.py

  1. #注册drf
  2. INSTALLED_APPS = [
  3. # ...
  4. 'api.apps.ApiConfig',
  5. 'rest_framework',
  6. ]

  7. #配置数据库
  8. DATABASES = {
  9. 'default': {
  10. 'ENGINE': 'django.db.backends.mysql',
  11. 'NAME': 'dg_proj',
  12. 'USER': 'root',
  13. 'PASSWORD': '',
  14. }
  15. }
  16. """
  17. 在任何(根或者app)的__init__文件中声明数据库
  18. import pymysql
  19. pymysql.install_as_MySQLdb()
  20. """
  21. #国际化 提示时间等从英语转化为汉字
  22. LANGUAGE_CODE = 'zh-hans'
  23. TIME_ZONE = 'Asia/Shanghai'
  24. USE_I18N = True
  25. USE_L10N = True
  26. USE_TZ = False

  27. # 开放图像路经,后面还有他用,这个配置和静态文件路径配置非常相似,暴露图像资源
  28. MEDIA_URL = '/media/'
  29. 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. ] # 固定写法 url + serve + {'document_root': '路径'}
  11. # 可以点进serve源码,功能注释有样式解释

  12. # 子路由
  13. from django.conf.urls import url
  14. from . import views
  15. urlpatterns = [
  16. url(r'^books/$', views.Book.as_view()),
  17. url(r'^books/(?P<pk>.*)/$', views.Book.as_view()),
  18.  
  19. url(r'^publishes/$', views.Publish.as_view()),
  20. url(r'^publishes/(?P<pk>.*)/$', views.Publish.as_view()),
  21.  
  22. url(r'^v2/books/$', views.V2Book.as_view()),
  23. url(r'^v2/books/(?P<pk>.*)/$', views.V2Book.as_view()),
  24. ]

二、基表 模型类的封装思想(******)

分析auth组件继承引出元类思想:

auth组件中我们自定义的user表继承abstractuser而不是继承他的功能更丰富的子类user,为什么?因为我们自定义user表是想创建我们自己的user表,不想创建auth_user表,如果继承user那么会自动创建auth_user表,而我们继承abstractser,不会创建auth_user表,只会创建我们自己的user表

  1. # 1) 点进User
  2. from django.contrib.auth.models import User
  3.  
  4. # 2)User继承AbstractUser,点进去
  5. class User(AbstractUser):
  6. class Meta(AbstractUser.Meta):
  7. swappable = 'AUTH_USER_MODEL'
  8.  
  9. # 3)AbstractUser源码里发现有下面的元类
  10. class Meta:
  11. verbose_name = _('user')
  12. verbose_name_plural = _('users')
  13. # 该models类被加载后,也不会在数据库创建表,所有基类都应该有下面这个声明
  14. abstract = True

多表设计

  1. """
  2. Book表:name、price、img、authors、publish、is_delete、create_time

  3. Publish表:name、address、is_delete、create_time
  4.  
  5. Author表:name、age、is_delete、create_time

  6. AuthorDetail表:mobile, author、is_delete、create_time
  7.  
  8. BaseModel基表
  9. is_delete、create_time
  10. 上面四表继承基表,可以继承两个字段
  11. """

模型类的封装思想:

  1. # 将那些大家共有的字段封装成一个基类,所有类都继承该基类,
  2.  
  3. # 记得在元类中声明 abstract = True ,声明不要在数据库中创建该表
  4.  
  5. class BaseModel(models.Model):
  6. is_delete = models.BooleanField(default=False)
  7. create_time = models.DateTimeField(auto_now_add=True)

  8. # 设置 abstract = True 来声明基表,作为基表的Model不会在数据库中形成对应的表
  9. class Meta:
  10. abstract = True

django测试脚本

https://www.cnblogs.com/xp1315458571/p/11552738.html#_label1

  1. # django脚本话启动
  2. import os, django
  3. os.environ.setdefault("DJANGO_SETTINGS_MODULE", "dg_proj.settings") # 加载django配置
  4. django.setup() # 起socket
  5. # 启动django项目有几种方式:
  6. # 通过manage.py启动的时候其实是加载了项目环境配置而已,
  7. # 项目上线后启动wsgi.py也可以启动项目,因为它内部也有环境配置,现在不行
  8. # 我们自己建启动脚本,放入上面的配置即可在这里启动

三、多表关系  建外键 正反查 断关联  (******)

sql中多表关系:https://www.cnblogs.com/xp1315458571/p/11384183.html

原生django的orm中多表关系:https://www.cnblogs.com/xp1315458571/p/11557880.html#_label1

  1. 1、外键位置:
  2. 一对多 - 外键放多的一方,ForeignKey
  3. 一对一 - 从逻辑正反向考虑,如作者表与作者详情表,作者删除级联删除详情,详情删除作者依旧存在,所以建议外键在详情表中,
  4. 多对多 - 外键在关系表中
  5.  
  6. 2ORM正向反向连表查询:
  7. 正向:通过外键字段 通过详情对象查作者eg: author_detial_obj.author
  8. # detail = models.AuthorDetail.objects.first()
  9. # print(detail.mobile)
  10. # print(detail.author.name)
  11. 反向:通过related_name的值 通过作者对象查详情egauthor_obj.detail
  12. # author = models.Author.objects.first()
  13. # print(author.name)
  14. # 声明 related_name='detail'后这样查询,没有声明必须用类名小写查询,这个会报错
  15. # print(author.detail.mobile)
  16. #这个是原始查法,即反向查询类名小写,如果声明 related_name='detail'后,这个就会报错
  17. # print(author.authordetail.mobile)
  18. 注:依赖代码见下方4中作者详情表
  19.  
  20. 3、连表操作关系-级联:
  21. 1)作者删除,详情级联 - on_delete=models.CASCADE
  22. 2)作者删除,详情置空 - null=True, on_delete=models.SET_NULL
  23. 3)作者删除,详情重置 - default=0, on_delete=models.SET_DEFAULT
  24. 4)作者删除,详情不动 - on_delete=models.DO_NOTHING
  25. 注:拿作者与作者详情表举例
  26.  
  27. 4、外键关联字段的参数 - 断关联 db_constraint=False
  28. 原本通过外键是连在一起的,这样有个弊端就是连在一起的表多了很容易形成环,当你想删除一张表的时候必须把有关联的也删除,都形成环了还怎么下手,所以就有了断链接一说,
    虽然连接断开了想删谁就删谁,但是依旧不影响连表查询
  1. #i)作者详情表中的
  2. class AuthorDetail(BaseModel):
  3. """mobile, author、is_delete、create_time"""
  4. mobile = models.CharField(max_length=11)
  5. author = models.OneToOneField( # 这个继承ForeignKey,必须设置on_delete
  6. to='Author',
  7. db_constraint=False, # 声明False后就是断关联了
  8. related_name='detail', #反向查询用这个值,即 作者对象.detail 即可
  9. on_delete=models.CASCADE, # 级联删除,1.x中默认的可不写,2.x中必须写
  10. )
  11.  
  12. #ii)图书表中的
  13. class Book(BaseModel):
  14. """name、price、img、authors、publish、is_delete、create_time"""
  15. name = models.CharField(max_length=64)
  16. price = models.DecimalField(max_digits=5, decimal_places=2)
  17. img = models.ImageField(upload_to='img', default='img/default.jpg')
  18. publish = models.ForeignKey( #外键必须设置on_delete
  19. to='Publish',
  20. db_constraint=False,
  21. related_name='books',
  22. on_delete=models.DO_NOTHING,
  23. )
  24. authors = models.ManyToManyField( #多对多和一对一不一样,这个是在第三张额外关系表中有两个外键,自己本身并未继承外键,不能设置on_delete
  25. to='Author',
  26. db_constraint=False,
  27. related_name='books'
  28. )
  29. #注:ManyToManyField不能设置on_delete,
  30. #OneToOneField(内部继承外键)、ForeignKey必须设置on_delete(django1.x系统默认级联,但是django2.x必须手动明确)
models.py
  1. from django.db import models
  2.  
  3. # 图书管理系统:Book、Author、AuthorDetail、Publish
  4. """
  5. Book表: name、price、img、authors、publish、is_delete、create_time
  6. Publish表: name、address、is_delete、create_time
  7. Author表: name、age、is_delete、create_time
  8. AuthorDetail表: mobile, author、is_delete、create_time
  9. """
  10.  
  11. # 1) 基表
  12. class BaseModel(models.Model):
  13. is_delete = models.BooleanField(default=False)
  14. create_time = models.DateTimeField(auto_now_add=True)
  15.  
  16. # 作为基表的Model不能在数据库中形成对应的表,设置 abstract = True
  17. class Meta:
  18. abstract = True
  19.  
  20. class Book(BaseModel):
  21. """name、price、img、authors、publish、is_delete、create_time"""
  22. name = models.CharField(max_length=64)
  23. price = models.DecimalField(max_digits=5, decimal_places=2)
  24. img = models.ImageField(upload_to='img', default='img/default.jpg')
  25. publish = models.ForeignKey(
  26. to='Publish',
  27. # 不写默认为True即有关联,改为False即断开连接,依然可以联表查询,但是删除表时就不用考虑关联表了
  28. db_constraint=False, # 断关联
  29. related_name='books', # 反向查询字段:publish_obj.books 就能访问所有出版的书
  30. on_delete=models.DO_NOTHING, # 设置连表操作关系
  31. )
  32. authors = models.ManyToManyField(
  33. to='Author',
  34. db_constraint=False,
  35. related_name='books'
  36. )
  37.  
  38. # 序列化插拔式属性 - 完成连表查询
  39. #通过设置这样的插拔属性,跨表查询再也不难了,一个表里就可以直接得到其他关联表所有属性
  40. #其他地方比如序列化中选择参与序列化字段,用到这些属性就加上,不需要时就去掉该属性,非常方便
  41. @property #将方法伪装成属性,也就是说Book类有了publish_name属性,不要这个装饰器也可以,官方文档推荐使用,更健壮
  42. def publish_name(self):
  43. return self.publish.name # 正向查询通过外键publish
  44.  
  45. @property
  46. def author_list(self):
  47. return self.authors.values('name', 'age', 'detail__mobile').all()
  48. # authors是正向的字段名,detail__mobile是反向查询字段加orm双下划线查询,本来是类名小写authordetail的,因为规定了反向查询字段,就用反向字段代替类名小写
  49. #不好的一点是,传给前端的字典数据中该k为detail__mobile,而不是mobile
  50. # 之前在书籍表里是无法跨两张表查询到作者号码,但是这样自定义插拔就可以实现,简化了跨表查询
  51. class Meta:
  52. db_table = 'book'
  53. verbose_name = '书籍'
  54. verbose_name_plural = verbose_name
  55. def __str__(self):
  56. return self.name
  57.  
  58. class Publish(BaseModel):
  59. """name、address、is_delete、create_time"""
  60. name = models.CharField(max_length=64)
  61. address = models.CharField(max_length=64)
  62.  
  63. class Meta:
  64. db_table = 'publish'
  65. verbose_name = '出版社'
  66. verbose_name_plural = verbose_name
  67. def __str__(self):
  68. return self.name
  69.  
  70. class Author(BaseModel):
  71. """name、age、is_delete、create_time"""
  72. name = models.CharField(max_length=64)
  73. age = models.IntegerField()
  74.  
  75. class Meta:
  76. db_table = 'author'
  77. verbose_name = '作者'
  78. verbose_name_plural = verbose_name
  79. def __str__(self):
  80. return self.name
  81.  
  82. class AuthorDetail(BaseModel):
  83. """mobile, author、is_delete、create_time"""
  84. mobile = models.CharField(max_length=11)
  85. author = models.OneToOneField(
  86. to='Author',
  87. db_constraint=False,
  88. related_name='detail',
  89. on_delete=models.CASCADE,
  90. )
  91.  
  92. class Meta:
  93. db_table = 'author_detail'
  94. verbose_name = '作者详情'
  95. verbose_name_plural = verbose_name
  96. def __str__(self):
  97. return '%s的详情' % self.author.name

完整models.py 插拔式

四、ModelSerializer   序列化  三种方式

序列化层:api/serializers.py
  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 = models.Publish
  9. fields = ('name', 'address')
  10.  
  11. class BookModelSerializer(ModelSerializer):
  12. # 了解 不用: 该方式设置的序列化字段,虽然也可以达到和插拔式一样的效果,
  13. # 但是这些字段必须在fields中声明,而models中定义的插拔式可声明可不声明
  14. # publish_address = SerializerMethodField()
  15. # def get_publish_address(self, obj):
  16. # return obj.publish.address
  17.  
  18. # 自定义连表深度 - 子序列化方式 - 该方式不能参与反序列化,使用在序列化反序列化共存时,不能书写
  19. publish = PublishModelSerializer()
  20.  
  21. class Meta:
  22. # 序列化类关联的model类
  23. model = models.Book
  24. # 自定义参与序列化的字段,指谁打谁,随意推荐这种
  25. fields = ('name', 'price', 'img', 'author_list', 'publish')
  26.  
  27. # 了解知识点
  28. # 所有字段,都不常用了解即可
  29. # fields = '__all__'
  30. # 与fields不共存,exclude排除哪些字段
  31. # exclude = ('id', 'is_delete', 'create_time')
  32. # 自动连表深度,本来查到的结果外键关联信息是代码形式,如0/1,规定深度可以显示外键关联表的具体信息如:男/女
  33. # depth = 1
视图层:api/views.py
  1. class Book(APIView):
  2. def get(self, request, *args, **kwargs):
  3. pk = kwargs.get('pk')
  4. if pk:
  5. try:
  6. book_obj = models.Book.objects.get(pk=pk, is_delete=False) # 删除的用户就不用查了
  7. book_data = serializers.BookModelSerializer(book_obj).data
  8. except:
  9. return Response({
  10. 'status': 1,
  11. 'msg': '书籍不存在'
  12. })
  13. else:
  14. book_query = models.Book.objects.filter(is_delete=False).all()
  15. book_data = serializers.BookModelSerializer(book_query, many=True).data
  16. return Response({
  17. 'status': 0,
  18. 'msg': 'ok',
  19. 'results': book_data
  20. })
路由层:api/urls.py
  1. urlpatterns = [
  2. url(r'^books/$', views.Book.as_view()),
  3. url(r'^books/(?P<pk>.*)/$', views.Book.as_view()),
  4. ]

五、ModelSerializer  反序列化

序列化层:api/serializers.py
  1. """
  2. 1)设置必填与选填序列化字段,设置系统校验规则
  3. 2)为需要额外校验的字段提供局部钩子函数,如果该字段不入库,且不参与全局钩子校验,可以将值取出校验
  4. 3)为有联合关系的字段们提供全局钩子函数,如果某些字段不入库,可以将值取出校验
  5. 4) # ModelSerializer类已经帮我们实现了 create 与 update 方法,不需重写
  6. """
  7. class BookModelDeserializer(ModelSerializer):
  8. class Meta:
  9. model = models.Book
  10. fields = ('name', 'price', 'publish', 'authors')
  11. # extra_kwargs 固定语法 用来定义反序列化字段的 系统校验规则 和返回错误信息
  12. # 例如fields中有img字段,前端就算不传图片也不会报错,因为有默认值的字段默认可以不传,
  13. # 想规定必须要,就可以在下面加入'img': {'required': True,'error_messages': {'required': '必填项'}}
  14. extra_kwargs = {
  15. 'name': {
  16. 'required': True,
  17. 'min_length': 1,
  18. 'error_messages': {
  19. 'required': '必填项',
  20. 'min_length': '太短',
  21. }
  22. }
  23. }
  24. # 真正强大的不是系统校验规则而是全局和局部钩子
  25. # 局部钩子
  26. def validate_name(self, value):
  27. # 书名不能包含 g 字符
  28. if 'g' in value.lower():
  29. raise ValidationError('该g书不能出版')
  30. return value
  31. # 全局钩子
  32. def validate(self, attrs):
  33. publish = attrs.get('publish')
  34. name = attrs.get('name')
  35. if models.Book.objects.filter(name=name, publish=publish):
  36. raise ValidationError({'book': '该书已存在'})
  37. return attrs

  38. # ModelSerializer类已经帮我们实现了 create 与 update 方法
视图层: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:当校验失败,马上终止当前视图方法,抛异常返回给前台,可以在is_valid源码参数中看到,这样写就不能自定义response了
  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. urlpatterns = [
  2. url(r'^books/$', views.Book.as_view()),
  3. url(r'^books/(?P<pk>.*)/$', views.Book.as_view()),
  4. ]

六、 序列化与反序列化整合 单查群查 单增群增 单删群删(重点)

序列化层:api/serializers.py
  1. """
  2. 1) fields中设置所有序列化与反序列化字段
  3. 2) extra_kwargs划分只序列化或只反序列化字段
  4. write_only:只反序列化
  5. read_only:只序列化
  6. 自定义字段默认只序列化(read_only)
  7. 3) 设置反序列化所需的 系统、局部钩子、全局钩子 等校验规则
  8. 4)一般的序列化我们只需要这一个整合的序列化类就可以,一个序列化类对应一个视图类,一个视图类对应六大接口
  9. 除非说要求贼高,比如权限不一样得到字段不一样时序列化和反序列化就必须分开处理了
  10. """
  11. class V2BookModelSerializer(ModelSerializer):
  12. class Meta:
  13. model = models.Book
  14. fields = ('name', 'price', 'img', 'author_list', 'publish_name', 'publish', 'authors')
  15. extra_kwargs = {
  16. 'name': { # 这些系统校验规则依然可以有
  17. 'required': True,
  18. 'min_length': 1,
  19. 'error_messages': {
  20. 'required': '必填项',
  21. 'min_length': '太短',
  22. }
  23. },
  24. 'publish': {
  25. 'write_only': True #只参与反序列化,入库
  26. },
  27. 'authors': {
  28. 'write_only': True
  29. },
  30. 'img': {
  31. 'read_only': True, # 只参与序列化,出库,即使你前台传了我也不用只用默认的(你只传路经我怎么知道该路径下有没有,不能走字符串上传,必须走文件上传来实现)
  32. },
  33. 'author_list': {
  34. 'read_only': True, # 自定义字段只序列化,出库
  35. },
  36. 'publish_name': {
  37. 'read_only': True,
  38. }
  39. }
  40.  
  41. #钩子和分开写时是一样的
  42. def validate_name(self, value):
  43. # 书名不能包含 g 字符
  44. if 'g' in value.lower():
  45. raise ValidationError('该g书不能出版')
  46. return value

  47. def validate(self, attrs):
  48. publish = attrs.get('publish')
  49. name = attrs.get('name')
  50. if models.Book.objects.filter(name=name, publish=publish):
  51. raise ValidationError({'book': '该书已存在'})
  52. return attrs
视图层:api/views.py
  1. class V2Book(APIView):
  1. # 单查:有pk
  2. # 群查:无pk
  3. def get(self, request, *args, **kwargs):
  4. pk = kwargs.get('pk')
  5. if pk:
  6. try:
  7. book_obj = models.Book.objects.get(pk=pk, is_delete=False)
  8. book_data = serializers.V2BookModelSerializer(book_obj).data
  9. except:
  10. return Response({
  11. 'status': 1,
  12. 'msg': '书籍不存在'
  13. })
  14. else:
  15. book_query = models.Book.objects.filter(is_delete=False).all()
  16. book_data = serializers.V2BookModelSerializer(book_query, many=True).data
  17. return Response({
  18. 'status': 0,
  19. 'msg': 'ok',
  20. 'results': book_data
  21. })
  1. # 单增:传的数据是与model对应的字典
  2. # 群增:传的数据是 装多个 model对应字典 的列表
  3. def post(self, request, *args, **kwargs):
  4. request_data = request.data
  5. if isinstance(request_data, dict):
  6. many = False
  7. elif isinstance(request_data, list):
  8. many = True
  9. else:
  10. return Response({
  11. 'status': 1,
  12. 'msg': '数据有误',
  13. })
  14. book_ser = serializers.V2BookModelSerializer(data=request_data, many=many)
  15. # 当校验失败,马上终止当前视图方法,抛异常返回给前台
  16. book_ser.is_valid(raise_exception=True)
  17. book_result = book_ser.save()
  18. return Response({
  19. 'status': 0,
  20. 'msg': 'ok',
  21. 'results': serializers.V2BookModelSerializer(book_result, many=many).data
  22. })
  1. # 单删:有pk
  2. # 群删:有pks | {"pks": [1, 2, 3]}
  3. # 删除不需要走序列化,没有数据交互,只是更改了状态码
  4. # 走delete请求过来直接跳到这里
  5. def delete(self, request, *args, **kwargs):
  6. pk = kwargs.get('pk')
  7. if pk:
  8. pks = [pk]
  9. else:
  10. pks = request.data.get('pks')
  11. if models.Book.objects.filter(pk__in=pks, is_delete=False).update(is_delete=True):
  12. #这个是有返回值的,返回值是受影响的行数,可以点进update源码看一下
  13. return Response({
  14. 'status': 0,
  15. 'msg': '删除成功',
  16. })
  17. return Response({
  18. 'status': 1,
  19. 'msg': '删除失败',
  20. })

# 单个对象局部和整体修改

  1. """
  2. ) 前台提供修改的数据要入库,就需要校验,校验的数据应该在实例化“序列化类对象”时,赋值给data
  3. )要修改,就必须明确被修改的模型类对象,即修改谁,并在实例化“序列化类对象”时,赋值给instance
  4. )整体修改,所有校验规则有required=True的字段,都必须提供,因为在实例化“序列化类对象”时,参数partial默认为False
  5.  
  6. 注:如果partial值设置为True,就是可以局部改
  7. )单整体修改,一般用put请求:
  8. V2BookModelSerializer(
  9. instance=要被更新的对象,
  10. data=用来更新的数据,
  11. partial=默认False,必须的字段全部参与校验
  12. )
  13. )单局部修改,一般用patch请求:
  14. V2BookModelSerializer(
  15. instance=要被更新的对象,
  16. data=用来更新的数据,
  17. partial=设置True,必须的字段都变为选填字段
  18. )
  19. 注:partial设置True的本质就是使字段 required=True 校验规则失效
  20. """

  1. # 单整体改: 对 v2/books/(pk)/ 传的数据是与model对应的字典{name|price|publish|authors}
  2. def put(self, request, *args, **kwargs):
  3. request_data = request.data
  4. pk = kwargs.get('pk')
  5. old_book_obj = models.Book.objects.filter(pk=pk).first()
  6. # 目的:将众多数据的校验交给序列化总类来处理 - 此时发挥反序列化作用,校验成功后,序列化总类来帮你入库
  7. book_ser = serializers.V2BookModelSerializer(instance=old_book_obj, data=request_data, partial=False)
  8. #想去校验就必须传入data(上面如果不关键字传参,只穿一个requst_data会默认传给instance,这个校验就不能通过)
  9. book_ser.is_valid(raise_exception=True)
  10. # 校验通过,要完成数据的更新而不是创建新对象就必须传入要更新的对象,即instance
  11. # 如果只传data=request_data,上面校验可以通过,这里会报错‘对象已经存在’,因为instance为空默认走create新建而不是updata更新
  12. book_obj = book_ser.save()
  13.  
  14. return Response({
  15. 'status': 0,
  16. 'msg': 'ok',
  17. 'results': serializers.V2BookModelSerializer(book_obj).data
  18. })

# 单或群 局部修改

序列化层:serializers.py
  1. # 重点:ListSerializer与ModelSerializer建立关联的是:
  2. # ModelSerializer的Meta类的 - list_serializer_class
  3.  
  4. # 重写upadte
  5. class V2BookListSerializer(ListSerializer):
  6. def update(self, instance, validated_data):
  7. # print(instance) # 要更新的对象们;[obj1,obj2,...]
  8. # print(validated_data) # 更新的对象对应的数据们 [{},{},...]
  9. # print(self.child) # 服务的模型序列化类 - V2BookModelSerializer
  10. for index, obj in enumerate(instance):
  11. self.child.update(obj, validated_data[index])
  12. return instance
  13.  
  14. # 原模型序列化类变化
  15. class V2BookModelSerializer(ModelSerializer):
  16. class Meta:
  17. # ...
  18. # 群改,需要设置 自定义ListSerializer,重写群改的 update 方法
  19. list_serializer_class = V2BookListSerializer
  20. # ...
视图层:views.py
  1. class V2Book(APIView):
  2. # 单局部改:对 v2/books/(pk)/ 传的数据,数据字段key都是选填
  3. # 单改请求数据 {name:123}
  4. # 群局部改:对 v2/books/ 传的数据,数据字段key都是选填
  5. # 群该请求数据 - [{pk:1, name:123}, {pk:3, price:7}, {pk:7, publish:2}]
  6.  
  7. def patch(self, request, *args, **kwargs):
  8. request_data = request.data
  9. pk = kwargs.get('pk')
  10. # 无论是修改单还是多个对象,统一按照多来处理,many=True,只不过单是多的特例
  11. # 将单改,群改的数据都格式化成 pks=[要需要的对象主键标识] | request_data=[每个要修改的对象对应的修改数据]
  12. if pk and isinstance(request_data, dict): # 单改,url有pk,数据是字典
  13. pks = [pk, ]
  14. request_data = [request_data, ]
  15. elif not pk and isinstance(request_data, list): # 群改,url无pk,数据是字典的列表
  16. pks = []
  17. for dic in request_data: # 遍历前台数据[{pk:1, name:123}, {pk:3, price:7}, {pk:7, publish:2}],拿一个个字典
  18. pk = dic.pop('pk', None)
  19. if pk:
  20. pks.append(pk)
  21. else:
  22. return Response({
  23. 'status': 1,
  24. 'msg': '数据有误',
  25. })
  26. else:
  27. return Response({
  28. 'status': 1,
  29. 'msg': '数据有误',
  30. })

  31. # pks与request_data数据筛选,
  32. # 1)将pks中的没有对应数据的pk与数据已删除的pk移除,request_data中对应索引位上的数据也移除
  33. # 2)将合理的pks转换为对应 objs
  34. objs = []
  35. new_request_data = []
  36. for index, pk in enumerate(pks):
  37. try:
  38. # pk对应的数据合理,将合理的对象存储-数据得存在且没有删除
  39. obj = models.Book.objects.get(pk=pk,is_delete=False)
  40. objs.append(obj)
  41. # 对应索引的数据就需要保存下来
  42. new_request_data.append(request_data[index])
  43. except:
  44. # 重点:反面教程—循环内部永远不要操作列表长度,你把3弹出,4变成3,下次循环去循环4找不到,报错
  45. # 不能弹出,那么我们就变减为增,在上面操作
  46. # pk对应的数据有误,将对应索引的data中request_data中移除
  47. # index = pks.index(pk) # 列表取索引
  48. # request_data.pop(index)
  49. continue

  50. book_ser = serializers.V2BookModelSerializer(instance=objs, data=new_request_data, partial=True, many=True)
                                                # 可局部改 partial=True,群 要声明 many=True

      # 一旦设置了many=True,反序列化情况下的create、update就不再调用ModelSerializer的
      # 而是调用 ModelSerializer.Meta.list_serializer_class 指向的 ListSerializer 类的create、update
      # ListSerializer默认只实现了群增的create,要实现群改,必须重写update,

  1. book_ser.is_valid(raise_exception=True) # 校验不通过自动抛异常
  2. book_objs = book_ser.save()

  3. return Response({
  4. 'status': 0,
  5. 'msg': 'ok',
  6. 'results': serializers.V2BookModelSerializer(book_objs, many=True).data
  7. })
路由层:api/urls.py
  1. urlpatterns = [
  2. url(r'^v2/books/$', views.V2Book.as_view()),
  3. url(r'^v2/books/(?P<pk>.*)/$', views.V2Book.as_view()),
  4. ]

# 视图类传递参数给序列化类

  1. # 1)在视图类中实例化序列化对象时,可以设置context内容
  2. # 2)在序列化类中的局部钩子、全局钩子、create、update方法中,都可以用self.context访问视图类传递过来的内容


  3. # 需求:
  4. # 1) 在视图类中,可以通过request得到登陆用户request.user
  5. # 2) 在序列化类中,要完成数据库数据的校验与入库操作,可能会需要知道当前的登陆用户,但序列化类无法访问request
  6. # 3) 在视图类中实例化序列化对象时,将request对象传递进去
视图层:views.py
  1. class Book(APIView):
  2. def post(self, request, *args, **kwargs):
  3. book_ser = serializers.BookModelSerializer(data=request_data,context={'request':request})
  4. book_ser.is_valid(raise_exception=True)
  5. book_result = book_ser.save()
  6. return Response({
  7. 'status': 0,
  8. 'msg': 'ok',
  9. 'results': serializers.BookModelSerializer(book_result).data
  10. })
序列化层:serializers.py
  1. class BookModelSerializer(ModelSerializer):
  2. class Meta:
  3. model = models.Book
  4. fields = ('name', 'price')
  5. def validate_name(self, value): # 局部狗子
  6. print(self.context.get('request').method) # get、patch、post、delete等
  7. return value 

七、二次封装Response类

  1. # 1.我们发现在我们写的各种方法中要频繁地返回各种response,形式大概一样,能不能封装起来呢?
  2. # 常规的response数据格式:
  3. Response({
  4. 'status': 0,
  5. 'msg': 'ok',
  6. 'results': [],
  7. 'token': '' # 可能有一个或多个类似这样的额外的key-value数据,所以加上**kwargs参数
  8. },status=http_status,headers=headers,exception=True|False)
  9. # 2.看response源码找灵感
  10. def __init__(self, data=None, status=None,template_name=None, headers=None,
  11. exception=False, content_type=None):
  12. super().__init__(None, status=status)

新建utils / response.py

  1. from rest_framework.response import Response

  2. class APIResponse(Response):
  3. # 模板不用要,因为我们封装就是给我们自己项目用,都是json,content_type默认json,也不要
  4. def __init__(self, data_status=0, data_msg='ok', results=None, http_status=None, headers=None, exception=False, **kwargs):
  5. # data的初始状态:状态码与状态信息
  6. data = {
  7. 'status': data_status,
  8. 'msg': data_msg,
  9. }
  10. # data的响应数据体
  11. # results可能是False、0等数据,这些数据某些情况下也会作为合法数据返回
  12. if results is not None:
  13. data['results'] = results
  14. # data响应的其他内容
  15. # if kwargs is not None:
  16. # for k, v in kwargs.items():
  17. # setattr(data, k, v)
  18. # data[k]=v # 这样也行
  19. data.update(kwargs) # 直接这样更新增加键值对更简单

  20. super().__init__(data=data, status=http_status, headers=headers, exception=exception)

视图层使用:views.py

  1. from utils.response import APIResponse

  2. **......
  3. # 封装前写法++++++++++++++++++++++++++++++++++++
  4. # return Response({
  5. # 'status': 0,
  6. # 'msg': 'ok',
  7. # 'results': serializers.V2BookModelSerializer(book_objs, many=True).data
  8. # })

  9. # 采用 自定义二次封装 (返回Json格式) 的响应对象 ++++++++++++++++++++++++++++
  10. book_objs_data = serializers.V2BookModelSerializer(book_objs, many=True).data
  11. return APIResponse(1, 'ooo', token="123.abc.xyz", results=book_objs_data, http_status=201) # 位置传参或者关键字传参,额外
    对应不上的都放进kwargs

5) ModelSerializer(重点) 基表 测试脚本 多表关系建外键 正反查 级联 插拔式连表 序列化反序列化整合 增删查 封装response的更多相关文章

  1. SQL删除数据库里所有表的外键,同时删除所有用户表

    SQL删除数据库里所有表的外键,同时删除所有用户表 删除所有的用户表的外键,直接将下面的代码拷贝到数据库里执行即可: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 ...

  2. Django框架表关系外键-多对多外键(增删改查)-正反向的概率-多表查询(子查询与联表查询)

    目录 一:表关系外键 1.提前创建表关系 2.目前只剩 书籍表和 书籍作者表没创建信息. 3.增 4.删 5.修改 二:多对多外键增删改查 1.给书籍绑定作者 2.删 3.修改 4.清空 三:正反向的 ...

  3. 在Sql Server 2005中将主子表关系的XML文档转换成主子表“Join”形式的表

    本文转载:http://www.cnblogs.com/Ricky81317/archive/2010/01/06/1640434.html 最近这段时间在Sql Server 2005下做了很多根据 ...

  4. MySQL表关系--外键

    一.外键前戏 如果我们把所有的信息都记录在一张表中会带来的问题: 1.表的结构不清晰 2.浪费磁盘空间 3.表的扩展性极差 所以我们要把这种表拆成几张不同的表,分析表与表之间的关系. 确定表与表之间的 ...

  5. db2数据库创建一张表,并为该表加上主键递增的性能和中间表的创建的sql语句

    创建角色表 CREATE TABLE NBCTXP.TBL_NBC_NONBANKROLE (    ID BIGINT NOT NULL,    ROLENAME VARCHAR(50),    C ...

  6. 测试脚本配置、ORM必知必会13条、双下划线查询、一对多外键关系、多对多外键关系、多表查询

    测试脚本配置 ''' 当你只是想测试django中的某一个文件内容 那么你可以不用书写前后端交互的形式而是直接写一个测试脚本即可 脚本代码无论是写在应用下的test.py还是单独开设py文件都可以 ' ...

  7. Postman—测试脚本

    前言 对于Postman中的每个请求,我们都可以使用JavaScript语言来开发测试脚本.这也就好比单元测试.我们先看看Postman的相关界面: 编写测试脚本 Postman测试脚本本质上是在发送 ...

  8. 关于数据库主从表、主键PRIMARY KEY 外键约束 FOREIGN KEY 约束----NOT NULL,DEFAULT,CHECK

    如果由两个列共同组成主键,而且一个子表将主键作为可为空值的外键来继承,就可能得到错误的数据.可在一个外键列中插入有效的值,但在另一个外键列中插入空值.然后,可添加一个数据表检查约束,在可为空的外键中检 ...

  9. DRF的orm多表关系补充及serializer子序列化

    目录 一.控制多表关系的字段属性 1.如何建立基表 2.断开连表关系 3.四种级联关系 二.子序列化 一.控制多表关系的字段属性 1.如何建立基表 要在基表中配置Meta,设置abstract=Tru ...

随机推荐

  1. Django 已生成数据时怎么查询数据库

    数据库已写好时,怎样查询数据库 1.输入命令:python manage.py inspectdb  > model1.py     注:>重定向 到model1.py

  2. HAproxy 基础配置

    基础配置详解 HAProxy 的配置文件haproxy.cfg由两大部分组成,分别是global和proxies部分 global:全局配置段 进程及安全配置相关的参数性能调整相关参数Debug参数 ...

  3. C与C++的函数声明中省略参数的不同意义

    一直都以为C/C++中形如 int func(); 这样的函数声明其意义就是一个参数 void(没有参数)的函数.然而今天在看C++的时候突然看到这么一句: 对于带空参数表的函数,C和C++有很大的不 ...

  4. git撤销远程commit

    git reset --hard [commit_id] git push origin HEAD --force

  5. Node.js 的事件循环机制

    目录 微任务 事件循环机制 setImmediate.setTimeout/setInterval 和 process.nextTick 执行时机对比 实例分析 参考 1.微任务 在谈论Node的事件 ...

  6. linux常用命令整理(一)

    1.sort(排序) 典型例题:sort -t: -k3n /etc/passwd 以冒号为分隔符根据第三个域的数字大小进行排序(默认分隔符是空格) 2.uniq(去除文件中的连续重复行) 典型例题: ...

  7. Web三维编程入门总结之二:面向对象的基础Web3D框架

    本篇主要通过分析Tony Parisi的sim.js库(原版代码托管于:https://github.com/tparisi/WebGLBook/tree/master/sim),总结基础Web3D框 ...

  8. A - Wireless Network POJ - 2236

    题目大意:有n台坏掉的电脑,给出每台电脑的坐标,然后每次询问输入0(字符) x,表示电脑x恢复正常,输入S x y 询问x和y是否可以联网.只要是x和y的距离小于距离d,那么就可以联网,如果有个中介c ...

  9. python的历史和下载python解释器

    一.python的诞生 1.Python的创始人为Guido van Rossum.1989年圣诞节期间,在阿姆斯特丹,Guido为了打发圣诞节的无趣,决心开发一个新的脚本解释程序,创造了一种C和sh ...

  10. pysparnn 模块使用,相似句子召回

    import pysparnn.cluster_index as ci from sklearn.feature_extraction.text import TfidfVectorizer data ...