多表与基表等概念

 

搭建前奏

打开pycharm,建立day71的程序,如图

分享图片

项目建好以后在settings里面进行简单配置,如图所示

分享图片

然后简单地进行数据库的配置:

分享图片

接下来再在settings里面注册,如图:

分享图片

配置文件完成后再做一个路由分发,如图:

分享图片

接下来在总路由中进行路由分发与查找照片的相应配置,如图:

分享图片

再下来就是在__init__中进行连接数据库的相应配置,如图

分享图片

接着在settings进行全局配置,看图

分享图片

基础的结构配置已完成,接下来在models里面进行表的创建,如图:创建表所需的字段

分享图片

先创建一个基表,基表 : 基表的class Mate一定要加上abstract = True,因为该表是提供共有字段的,不是用来创表的如果创建表就要继承我,如果不想增加新的字段就继承我就行,若果想加新的字段,就在我的基础上增加新的字段。

还有提一个就是模型类的封装就是共有类的封装,依据是abstract的Meta里面规定的

# 所有的东西都来自于models.Model
class BaseModel(models.Model):
    is_delete = models.BooleanField(default=0)
    create_time = models.DateTimeField(auto_now_add=True)
  # 作为基表的Model不能在数据库中形成对应的表    class Meta:
      abstract = True
     class Book(BaseModel): name = models.CharField(max_length=64) price = models.DecimalField(max_digits=5, decimal_places=2) image = models.ImageField(upload_to=‘img‘, default=‘image/default.jpg‘) publish = models.ForeignKey(to=‘Publish‘) authors = models.ManyToManyField(to=‘Author‘) class Meta: db_table = ‘book‘ verbose_name = ‘书籍‘ verbose_name_plural = verbose_name def __str__(self): return self.name
   # 序列化插拔式属性===》完成自定义字段名完成连表查询
   @propery
   def publish_name(self)
      return self.publish.name
class Publish(BaseModel): name = models.CharField(max_length=64) address = models.CharField(max_length=64) class Meta: db_table = ‘publish‘ verbose_name = ‘出版社‘ verbose_name_plural = verbose_name def __str__(self): return self.name class Author(BaseModel): name = models.CharField(max_length=64) age = models.IntegerField() class Meta: db_table = ‘author‘ verbose_name = ‘作者‘ verbose_name_plural = verbose_name def __str__(self): return self.name
   def get_sex(self, obj):
     # choice类型的解释性值, get_字段_display() 来访问
     return obj.get_sex_display
class AuthorDetail(BaseModel): mobile = models.CharField(max_length=11) author = models.OneToOneField(to=‘Author‘) class Meta: db_table = ‘author_detail‘ verbose_name = ‘作者详情‘ verbose_name_plural = verbose_name def __str__(self): return ‘%s的详情‘ % self.author.name

  表建好以后进行数据库的创建,然后连接数据库,将数据迁移在数据库里面,如图

分享图片

 

分享图片

表成功迁移至是数据库

 

2. 多表断关联

  1,创建超级用户,在app01下的admin进行注册,如图

分享图片

 现在就开始断关系,来到models模块里面,作者被删,那么作者详情也就会被删,如图,related_name = detail叫做反向查询 , db_constraint=False  断关联

分享图片

 在根目录下建立script/model.py的测试脚本,如图

分享图片

 django脚本化启动

运行django脚本化并不是运行manage.py,运行结果:

分享图片

在这边拓展下级联关系,比如,书籍是作者写的,写这本书的人西去了,那么这本书的作者还是有的,并且还是他,最鲜明的例子就是《西游记》,这就叫do_nothing,还有一个叫set_default,另外一个叫做SET_NULL,

当unll=true, on_delete = models.SET_NULL时,会出现作者被删除,外键被删除,

分享图片

作者被删除

分享图片外键被置空

 

当设置为on_delete = models.SET_DEFAULT, default = true时,如图, 详情重置

分享图片

 

当设置为do_nothing时,如图:在现实生活中只是改了下字段,如图

分享图片

作者会被删掉

分享图片外键什么的都没变

总体来说,四种关系是这样的

分享图片

manytomany不能直接设置on_delete,要在第三张表中设置才可以

 

三 . 多表序列化组件

  序列化层: app01/serializers.py

from rest_framework.serializers import ModelSerializer
from . import models

class BookModelSerializer(ModelSerializer):
    class Meta:
        # 序列化类关联的model类
        model = models.Book
        # 参与序列化的字段
        fields = (‘name‘,)  # 往前台返回的字段
     # 所有字段
     fields = ‘__all__’
     # 刨除。。不展示, 不能与fields同用
     exclude = (‘id‘, ‘is_delete‘)

  分享图片

视图层: app01/views.py

from rest_framework.views import APIView  # 负责请求过来的
from rest_framework.response import Response  # 负责响应的

from . import models, serializers  # 负责模型与序列化

class Book(APIView):  
    def get(self, request, *args, **kwargs):
        pk = kwargs.get(‘pk‘)
        if pk:
            try:
               book_obj = models.Book.objects.get(pk=pk)
         # 序列化对象 book_data = serializers.BookModelSerializer(book_obj).data print(book_data) except: return Response({ ‘status‘: 1, ‘msg‘: ‘书籍不存在‘ }) else: book_query = models.Book.objects.all() book_data = serializers.BookModelSerializer(book_query,many=True).data # return Response({ ‘status‘: 0, ‘msg‘: ‘ok‘, ‘results‘: book_data })

  路由层: app01/urls.py

urlpatterns = [
    url(r‘^books/$‘, views.Book.as_view()),
    url(r‘^books/(?P<pk>.*)/$‘, views.Book.as_view()),
]

  

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

  自定义深度查询

from rest_framework.serializers import ModelSerializer
from . import models

class PublishModelSerializer(ModelSerializer):
    class Meta:
        model = models.Publish
        fields = (‘name‘, ‘address‘)

class BookModelSerializer(ModelSerializer):


    # 自定义连表深度 - 子序列化方法

    publish = PublishModelSerializer()  # 相当于调用了class PublishModelSerializer这个类,对其外键完成深度序列化



    class Meta:
        # 序列化类关联的model类
        model = models.Book
        # 参与序列化的字段
        fields = (‘name‘, ‘price‘,‘publish‘)  # 往前台返回的字段
        # fields = ‘__all__‘

  效果如图:

分享图片

  

五. 多表反序列化组件

  序列化层: api/serializers.py

分享图片

视图层: app01/views.py

分享图片

效果如下:

分享图片

局部钩子与全局钩子的校验

class BookModelDeserializer(ModelSerializer):
    class Meta:
        # 序列化类关联的model类
        model = models.Book
        # 参与序列化的字段
        fields = (‘name‘, ‘price‘,‘publish‘,‘authors‘, ‘image‘)  # 往前台返回的字段
        # 加系统的约束条件,用来完成反序列化字段的系统校验规则
        extra_kwargs = {
            ‘name‘: {
                ‘required‘: True,  # required是否是必须的
                ‘min_length‘: 1,
                ‘error_messages‘: {
                    ‘required‘: ‘必填项‘,  # 将原来没有传照片的提示改变为‘必填项‘,其实也就是自定义的
                    ‘min_length‘: ‘太短‘
                }
            }
        }


    # 局部钩子的校验
    def validate_name(self, value):
        # 重复的书名校验
        # 检验书名不能包含‘g’
        if ‘g‘ in value.lower():
            raise ValidationError(‘改书已经不能出版‘)
        return value

    # 全局钩子校验
    def validate(self, attrs):
        publish = attrs.get(‘publish‘)  # 序列化类已经将外键转化为对象
        name = attrs.get(‘name‘)
        if models.Book.objects.filter(name=name, publish=publish):

            raise ValidationError({‘book‘: ‘改书已存在‘})
        return attrs

        # ModelSerializer类已经帮我们实现了create与updata方法

  视图层:

def post(self,request,*args,**kwargs):
        request_data = request.data  #获取post提交的数据包
        book_ser = serializers.BookModelDeserializer(data=request_data)
        # raise_exception=True:当校验失败,马上终止当前视图方法,抛异常返回给前台
        book_ser.is_valid(raise_exception=True) #检验是否合格 raise_exception=True必填的
        book_obj = book_ser.save()  #保存
        return Response({
            ‘status‘:0,
            ‘msg‘:‘ok‘,
            ‘results‘:serializers.BookModelSerializers(book_obj).data
        })

  

六 .序列化与反序列化的整合(************)

  序列化层:

  

class V2BookModelSerializer(ModelSerializer):
    class Meta:
        model = models.Book
        fields = (‘name‘, ‘price‘, ‘img‘, ‘author_list‘, ‘publish_name‘, ‘publish‘, ‘authors‘)
        extra_kwargs = {
            ‘name‘: {
                ‘required‘: True,  # requirred是否是必须的
                ‘min_length‘: 1,
                ‘error_messages‘: {
                    ‘required‘: ‘必填项‘, # 将原来没有传照片的提示改变为‘必须填’
                    ‘min_length‘: ‘太短‘,
                }
            },
            ‘publish‘: {
                ‘write_only‘: True
            },
            ‘authors‘: {
                ‘write_only‘: True
            },
            ‘img‘: {
                ‘read_only‘: True,
            },
            ‘author_list‘: {
                ‘read_only‘: True,
            },
            ‘publish_name‘: {
                ‘read_only‘: True,
            }
        }

    def validate_name(self, value):
        # 书名不能包含 g 字符
        if ‘g‘ in value.lower():
            raise ValidationError(‘该g书不能出版‘)
        return value

    def validate(self, attrs):
        publish = attrs.get(‘publish‘)
        name = attrs.get(‘name‘)
        if models.Book.objects.filter(name=name, publish=publish):
            raise ValidationError({‘book‘: ‘该书已存在‘})
        return attrs

  序列化注意点:

1) fields中设置所有序列化与反序列化字段
2) extra_kwargs划分只序列化或只反序列化字段(一般我们把需要存入到数据库中的使用write_only(反序列化),只需要需要展示的就read_only(序列化),看需求设计)
    write_only:只反序列化
    read_only:只序列化
    自定义字段默认只序列化(read_only)
    如果字段没设置write_only或者read_only,那么该字段可以序列化和反序列化
3) 设置反序列化所需的 系统、局部钩子、全局钩子 等校验规则

  视图层. views.py

class V2Book(APIView):
    def get(self,request,*args,**kwargs):
        pk = kwargs.get(‘pk‘)
        #单查
        if pk:
            try:
                book_obj = models.Book.objects.get(pk=pk,is_delete=False)
                book_data = serializers.V2BookModelSerializer(book_obj).data  #序列化
            except:
                return Response({
                    ‘status‘:1,
                    ‘msg‘:‘参数有误‘
                })
        #群查
        else:
            book_query=models.Book.objects.filter(is_delete=False).all()
       # many = true 多条数据 book_data = serializers.V2BookModelSerializer(book_query,many=True).data #序列化 return Response({ ‘status‘:0, ‘msg‘:‘ok‘, ‘results‘:book_data }) def post(self,request,*args,**kwargs): #单增:传的数据是与model对应的一个字典 # 群增:设计传递的是多个model对应的字典列表 request_data = request.data if isinstance(request_data,dict): many = False elif isinstance(request_data,list): #在postman中设计一个列表存入每条数据 many = True else: return Response({ ‘status‘:1, ‘msg‘:‘数据错误‘ }) book_ser = serializers.V2BookModelSerializer(data=request_data,many=many) #反序列化 book_ser.is_valid(raise_exception=True) book_result = book_ser.save() #book_result是对象<class ‘app01.models.Book‘>,如果增加多个就是列表套一个个对象
     return Response({ ‘status‘:0, ‘msg‘:‘ok‘, ‘results‘:serializers.V2BookModelSerializer(book_result,many=many).data }) #单删: 有pk #在postman中通过路径传参 #群删:有pks {"pks": [1, 2, 3]} #通过json传参 两者都不需要序列化,只是将数据库中的0变为1 def delete(self,request,*args,**kwargs): pk = kwargs.get(‘pk‘) if pk: # 单删 pks = [pk] else: # 群删 pks = request.data.get(‘pks‘) if models.Book.objects.filter(pk__in=pks,is_delete=False).update(is_delete=True): return Response({ ‘status‘:0, ‘msg‘:‘删除成功‘ }) return Response({ ‘status‘:1, ‘msg‘:‘删除失败‘ })

  视图层注意点:(*****)

1.序列化数据最后必须要.data
2.反序列化通过data传参
3.反序列化与序列化都能使用many=True

  路由层: urls.py

urlpatterns = [
    url(r‘^v2/books/$‘, views.V2Book.as_view()),
    url(r‘^v2/books/(?P<pk>.*)/$‘, views.V2Book.as_view()),
]
相关文章
相关标签/搜索