搭建前奏
打开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()), ]