drf-->ModelSerializer:
相关:
1.setting配置;
2.路由分发,路由相关;
3.自定义异常处理;
4.model相关;
5.serializers序列化相关;
6.view相关;
settings.py
INSTALLED_APPS = [
...
'rest_framework',
]
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.mysql',
'NAME': 'dg_proj',
'USER': 'root',
'PASSWORD': '123',
}
}
LANGUAGE_CODE = 'zh-hans'
TIME_ZONE = 'Asia/Shanghai'
USE_I18N = True
USE_L10N = True
USE_TZ = False
MEDIA_URL = '/media/'
MEDIA_ROOT = os.path.join(BASE_DIR, 'media')
项目名下__init__文件中

import pymysql pymysql.install_as_MySQLdb()
路由相关
# 主路由
from django.conf.urls import url, include
from django.contrib import admin
from django.views.static import serve
from django.conf import settings
urlpatterns = [
url(r'^admin/', admin.site.urls),
url(r'^api/', include('api.urls')),
url(r'^media/(?P<path>.*)', serve, {'document_root': settings.MEDIA_ROOT}),
]
#子路由
urlpatterns = [
url(r'^books/$', views.Book.as_view()),
url(r'^books/(?P<pk>.*)/$', views.Book.as_view()),
url(r'^v2/books/$', views.V2Book.as_view()),
url(r'^v2/books/(?P<pk>.*)/$', views.V2Book.as_view()),
]
model.py
基表:存储有关数据库的信息的底层表,在数据库中首创的对象
class BaseModel(models.Model):
is_delete = modles.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)
img = models.ImageField(upload_to='img', default='img/default.jpg')
publish = models.ForeignKey(
to='Publish',
db_constraint=False, # 断关联
related_name='books', # 反向查询字段:publish_obj.books 就能访问所有出版的书
on_delete=models.DO_NOTHING, # 设置连表操作关系
)
authors = models.ManyToManyField(
to='Author',
db_constraint=False,
related_name='books'
)
# 序列化插拔式属性 - 完成自定义字段名完成连表查询
@property
def publish_name(self):
return self.publish.name
@property
def author_list(self):
return self.authors.values('name', 'age', 'detail__mobile').all()
class Publish(BaseModel):
"""name、address、is_delete、create_time"""
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、age、is_delete、create_time"""
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
class AuthorDetail(BaseModel):
"""mobile, author、is_delete、create_time"""
mobile = models.CharField(max_length=11)
author = models.OneToOneField(
to='Author',
db_constraint=False,
related_name='detail',
on_delete=models.CASCADE,
)
class Meta:
db_table = 'author_detail'
verbose_name = '作者详情'
verbose_name_plural = verbose_name
def __str__(self):
return '%s的详情' % self.author.name
admin.py
from . import models
admin.site.register(models.Book)
admin.site.register(models.AuthorDetail)
admin.site.register(models.Author)
admin.site.register(models.Publish)
django 脚本化启动
import osos.environ.setdefault("DJANGO_SETTINGS_MODULE", "drfday1.settings")
django.setup()
exception.py:自定义异常处理器
from rest_framework.views import excepthon_handler as drf_excepthon_handler
from rest_framework.views import Response
from rest_framework import status
def exception_handler(exc,context):
#drf的 exception_handler做基础处理
response = drf_exception_handler(exc,conteax)
if response is None:
print('%s-%s-%s'%(context['view'],context['request'].method,exc))
return Response({
'detail':'服务器错误'
},status=status.HTTP_500_INTERNAL_SERVER_ERROR,exception=True)
return response
Serializer.py
from rest_frameword.serializers import ModelSerializer,serializerMethodField
from . import models
from rest_frameword.excepthon import ValidationError
#序列化
class BookModelSerializer(ModelSerializer):
class Meta:
#(*****)
#序列化类关联的model类
model = models.Book
#参与序列化的字段
fields = ('name','price','publish','author')
#(***)
#所有字段
fields = '__all__'
#exclude 是除过fields查出的所有字段,与fields不能共存
exclude = ('id','img')
#连表查询深度
depth=1
#反序列化
class BookModelDeserializer(ModelSerializer):
class Meta:
model = models.Book
# fields = ('name','price','publish','authors')
# extra_kwargs 用来完成反序列化字段的 系统校验规则
fields = '__all__'
extra_kwargs ={
'name':{
'write_only':True,
'min_length':1,
'error_messages':{
'required': '必填项',
'min_length': '不够',
}
}
}
单个字段的验证
1.在序列化器里定义校验字段的钩子方法 validate_字段
2.获取字段的数据
3.验证不通过,抛出异常 raise serializers.ValidationError("校验不通过的说明")
4.验证通过,直接返回字段数据
def validate_title(self,value):
# 判断value是否含有敏感字段
if "xx" in value:
# 存在敏感字段,抛出异常并附上自定义的原因
raise serializers.ValidationError("该字段含有敏感词")
# 不存在,则直接返回
return value
多个字段的验证
1.在序列化器定义validate方法
2.attrs是所有数据组成的字典
3.不符合抛出异常 raise serializers.ValidationError("校验不通过的说明")
def validate(self, attrs):# arrrs是数据组成的字典
# 判断linux的数是否在linux分类
if "linux" in attrs.get('title') and attrs['category_post'] == 2:
return attrs
else:
raise serializers.ValidationError("图书与分类不一致")
自定义验证器
使用:在字段添加 validators=[自定义验证器,]
def my_validate(value):
if "xxx" in value:
raise serializers.ValidationError("该字段包含敏感词!!!")
else:
return value
title = serializers.CharField(max_length=32,validators=[my_validate,]) # 使用自定义验证器
#序列化与反序列化整合版 (终极版本)
class V2BookModelSerializer(ModelSerializer):
"""
1) fields中设置所有序列化与反序列化字段
2) extra_kwargs划分只序列化或只反序列化字段
write_only:只反序列化
read_only:只序列化
自定义字段默认只序列化(read_only)
3) 设置反序列化所需的 系统、局部钩子、全局钩子 等校验规则
"""
class Meta:
model = models.Book
fields = ('name','price','img','author_list','publish_name','publish','authors')
extra_kwargs = {
'name':{
'required':True,
'min_length':3,
'error_messages':{
'required':'必填项',
'min_length':'最少3'
}
},
'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):
if 'xx' 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('这本书已存在')
return attrs
views.py:
from . importo models,serializers
from rest_framework.views import APIView
from rest_framework.response import Pesponse
class Books(APIView):# 继承rest_framework的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.BookModelSerializer(book_obj).data
except:
return Response({
'status':1,
'msg':'没有这本书'
})
else:
book_query = models.Book.objects.all().filter(is_delete=False)
book_data = serializers.BookModelSerializer(book_query,many=True).data
return Response({
'status':0,
'msg':'ok',
'results':book_data
})
def post(self,request,*args,**kwargs):
request_data = request.data
book_ser = serializers.BookModelDeserializer(data=request_data)
# 当校验失败,马上终止当前视图方法,抛异常返回给前台
book_ser.is_valid(raise_exception=True)
book_obj = book_ser.save()# 调用 create
return Response({
'status': 0,
'msg': 'ok',
'results': serializers.BookModelSerializer(book_obj).data
})
class V2books(APIView):
#查
def get(self,request,*args,**kwargs):
pk = kwargs.get('pk')
if pk:
try:
book_obj = models.Book.objects.filter(pk=pk,is_delete=False)
book_data = serializers.V2BookModelSerializer(book_obj).data
except:
return Response({
'status': 1,
'msg': '书籍不存在'
})
else:
book_list = models.Book.objects.all().filter(is_delete=False)
book_data = serializers.V2BookModelSerializer(book_list,many=True).data
return Response({
'status': 0,
'msg': 'ok',
'results': book_data
})
# 单增:传的数据是与model对应的字典
# 群增:传的数据是 装多个 model对应字典 的列表
def post(self,request,*args,**kwargs):
request_data = request.data
if isinstance(request_data,dict):
many = False
elif isinstance(request_data, list):
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()
return Response({
'status': 0,
'msg': 'ok',
'results': serializers.V2BookModelSerializer(book_result, many=many).data
})
# 单删:有pk
# 群删:有pks | {"pks": [1, 2, 3]}
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': '删除失败',
})
orm之 断关联多表关系
1、外键位置:
一对多 - 外键放多的一方
一对一 - 从逻辑正反向考虑,如作者表与作者详情表,作者删除级联删除详情,详情删除作者依旧存在,所以建议外键在详情表中
多对多 - 外键在关系表中
2、ORM正向方向连表查找:
正向:通过外键字段 eg: author_detial_obj.author
反向:通过related_name的值 eg:author_obj.detail
注:依赖代码见下方
3、连表操作关系:
1)作者删除,详情级联 - on_delete=models.CASCADE
2)作者删除,详情置空 - null=True, on_delete=models.SET_NULL
3)作者删除,详情重置 - default=0, on_delete=models.SET_DEFAULT
4)作者删除,详情不动 - on_delete=models.DO_NOTHING
注:拿作者与作者详情表举例
4、外键关联字段的参数 - 如何实现 断关联、目前表间操作关系、方向查询字段
i)作者详情表中的
author = models.OneToOneField(
to='Author',
related_name='detail',
db_constraint=False,
on_delete=models.CASCADE
)
ii)图书表中的
publish = models.ForeignKey(
to='Publish',
related_name='books',
db_constraint=False,
on_delete=models.DO_NOTHING,
)
authors = models.ManyToManyField(
to='Author'
related_name='books',
db_constraint=False,
)
注:
1.ManyToManyField不能设置on_delete,OneToOneField、ForeignKey必须设置on_delete(django1.x系统默认级联,但是django2.x必须手动明确)
2.db_constraint
db_constraint 唯一约束
db_constraint = True 方便查询 约束字段
db_constraint = fales(*) 不约束字段 同时也可以查询,就是保留跨表查询的便利
3.on_delete 外键的删除
1.on_delete = CASCADE:这就是默认的选项,级联删除,你无需显性指定它
2.on_delete = PROTECT:保护模式,如果采用该选项,删除的时候,会抛出ProtectedError错误
3.on_delete = SET_NULL:置空模式,删除的时候,外键字段被设置为空
注:前提就是blank=True, null=True,定义该字段的时候,允许为空
4.on_delete = SET_DEFAULT: 置默认值,删除的时候,外键字段设置为默认值,
5.on_delete = DO_NOTHING: 该模式作者删除,详情不动
4 related_name = 'xxx' 子表在主表中对应的外键属性,反向引用
