Custom Respoense
Although we already use, rest_framework the Response, but the code is still a little redundant, so they can rewrite their own (specific packaging requirements may be more practical to change)
Rewrite
from rest_framework.response import Response
class APIResponse(Response):
# 格式化data
def __init__(self, status=0, msg='ok', results=None, http_status=None, headers=None, exception=False, **kwargs):
# data默认加上json的response基础有数据状态码和数据状态信息
data = {
'status': status,
'msg': msg
}
# 如果后台有数据,响应数据
if results is not None:
data['results'] = results
# 后台的一切自定义响应数据直接放到响应数据data中
data.update(**kwargs)
super().__init__(data=data, status=http_status, headers=headers, exception=exception)
use
#查询正确,修改默认的状态码,和msg和http状态码
return APIResponse(status=1,msg="单查 error",http_status=400)
#查询错误,使用默认的msg和状态码
return APIResponse(results=user_data)
base table modles
modles a common field inside the table, the table can be extracted to the substrate
Note that the base table
Set up embedded abstract meta class to True, the default is False (creates this table is False)
is_delete field
I used to do tombstone, because the data is valuable
class BaseModel(models.Model):
is_delete = models.BooleanField(default=False)
create_time = models.DateTimeField(auto_now_add=True)
class Meta:
# 基表必须设置abstract,基表就是给普通Model类继承使用的,设置了abstract就不会完成数据库迁移完成建表
abstract = True
Models to physical logical foreign key foreign key
Off characteristics associated
There is no association between the key sheet 1, but logically associated foreign key (it is to be noted that, because there is no physical constraints, so to secure data on the logical operation)
2, will not affect the efficiency of breaking the association database query, but will greatly improve the efficiency of database CRUD (because to do less step to determine whether there is a foreign key operating data)
db_constraint
Off the association, but also to cascade (default cascading deletes), so to set up their own, as follows
db_constraint=False
on_delete-- cascade delete
By default there are in django1.x in the 2.x must implement their own
on_delete=models.CASCADE
Note-many exceptions
1. actually-many foreign key relationship table, ORM default relationship table two foreign keys are concatenated
2.ManyToManyField field does not provide the settings on_delete, if you want to set the table to cascade, only manually define the relationship table
作者没了,详情也没:on_delete=models.CASCADE
出版社没了,书还是那个出版社出版:on_delete=models.DO_NOTHING
#下面两个比较类似
部门没了,员工没有部门(空不能):null=True, on_delete=models.SET_NULL
部门没了,员工进入默认部门(默认值):default=0, on_delete=models.SET_DEFAULT
related_name
Foreign key columns to forward the query field, related_name a reverse lookup field
obj = models.Author.objects.filter(pk=1).first()
print(obj.detail.mobile)
obj2 = models.AuthorDetail.objects.filter(pk=1).first()
print(obj2.author.name)
Case
# 多表:Book,Publish,Author,AuthorDetail
class BaseModel(models.Model):
is_delete = models.BooleanField(default=False)
create_time = models.DateTimeField(auto_now_add=True)
class Meta:
abstract = True
class Book(BaseModel):
name = models.CharField(max_length=16)
price = models.DecimalField(max_digits=5, decimal_places=2)
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)
# 自定义连表深度,不需要反序列化,因为自定义插拔属性不参与反序列化
@property
def publish_name(self):
return self.publish.name
@property
def author_list(self):
temp_author_list = []
for author in self.authors.all():
temp_author_list.append({
'name': author.name,
'sex': author.get_sex_display(),
'mobile': author.detail.mobile
})
return temp_author_list
class Publish(BaseModel):
name = models.CharField(max_length=16)
address = models.CharField(max_length=64)
class Author(BaseModel):
name = models.CharField(max_length=16)
sex = models.IntegerField(choices=[(0, '男'),(1, '女')], default=0)
class AuthorDetail(BaseModel):
mobile = models.CharField(max_length=11)
author = models.OneToOneField(to='Author', related_name='detail', db_constraint=False, on_delete=models.CASCADE)
DRF multi-table relations
One-to-many
Option One
In fact, like the use of the self-definition of the characteristics of the field, you can go to get the return value data alone, the last in the sequence data, but be aware that argument can not be returned in the form of the object, or can not support this target sequence in addition to other objects of
fields
fields = ('name', 'price', 'publish_name', 'author_list')
models
#self为book对象,直接用它进行多表查询,返回想要的数据
@property
def publish_name(self):
return self.publish.name
@property
def author_list(self):
temp_author_list = []
for author in self.authors.all():
temp_author_list.append({
'name': author.name,
'sex': author.get_sex_display(),
'mobile': author.detail.mobile
})
return temp_author_list
Option II - Custom depth
Compared
Contrast the above objects can not pass, this method directly to the serializer used to use other data, can serialize the other recording data
But we can not deserialize, and will direct error
premise
If only the interface needs to check, it can also be used to customize the depth of the sub-sequences is accomplished
class PublishModelSerializer(serializers.ModelSerializer):
子序列化都是提供给外键(正向方向)完成深度查询的,外键数据是唯一:many=False,不唯一many=True
#只有带外键的记录能这样搞
books = BookModelSerializer(many=True)
class Meta:
model = models.Publish
fields = ('name', 'address', 'books')
Single investigation, the investigation group
def get(self, request, *args, **kwargs):
pk = kwargs.get('pk')
if pk:
book_obj = models.Book.objects.filter(pk=pk, is_delete=False).first()
if not book_obj:
return APIResponse(1, 'pk error', http_status=400)
book_data = serializers.BookModelSerializer(book_obj).data
return APIResponse(results=book_data)
book_query = models.Book.objects.filter(is_delete=False).all()
return APIResponse(0, 'ok', data=serializers.BookModelSerializer(book_query, many=True).data)
Single delete, delete group
def delete(self, request, *args, **kwargs):
pk = kwargs.get('pk')
# 将单删群删逻辑整合,都设为列表形式统一
if pk:
pks = [pk]
else:
pks = request.data.get('pks')
# 前台数据有误(主要是群删没有提供pks)
if not pks:
return APIResponse(1, 'delete error', http_status=400)
# 只要有操作受影响行,就是删除成功,反之失败
# 这里使用的是存orm的方法
rows = models.Book.objects.filter(is_delete=False, pk__in=pks).update(is_delete=True)
if rows:
return APIResponse(0, 'delete ok')
return APIResponse(1, 'delete failed')
Tenzin, population growth
To be noted that the sequence and deserialization setting field
principle
In fact, it calls the create method ListSerializer, and then create increased ModelSerializer cycle call, and finally returns the result ListSerializer cycle
note
But ListSerializer provides only create method does not provide the update method, change the method to achieve the group but also their own rewrite achieve (why not rewrite it? May be because the group needs to change too complicated)
def post(self, request, *args, **kwargs):
request_data = request.data
#通过数据类型判断单增还是群增
if isinstance(request_data, dict):
book_ser = serializers.BookModelSerializer(data=request_data)
#手动处理错误
if book_ser.is_valid():
book_obj = book_ser.save()
return APIResponse(results=serializers.BookModelSerializer(book_obj).data)
return APIResponse(1, msg=book_ser.errors)
elif isinstance(request_data, list) and len(request_data) != 0 :
book_ser = serializers.BookModelSerializer(data=request_data, many=True)
#自动处理错误
book_ser.is_valid(raise_exception=True)
book_obj_list = book_ser.save()
return APIResponse(results=serializers.BookModelSerializer(book_obj_list, many=True).data)
else:
return APIResponse(1, 'data error', http_status=400)
Single overall change, the overall change group
Since the default method calls ListSerializer create, but ListSerializer not rewrite, so we need to achieve their own
Rewrite
As long as the overriding implementation cycle call, ModelSerializer the update function on the line, and finally returns the results
class BookListSerializer(serializers.ListSerializer):
#父级ListSerializer没有通过update方法的实现体,需要自己重写
def update(self, instance, validated_data):
#self.child能反向获取ModelSerializer函数
return [
self.child.update(instance[i], attrs) for i, attrs in enumerate(validated_data)
]
Binding
Add a binding relationship with ListSerializer in ModelSerializer, note added to the meta inside
# 关联ListSerializer完成群增群改
list_serializer_class = BookListSerializer
def put(self, request, *args, **kwargs):
"""
单整体改:前台提交字典,接口 /books/(pk)/
群整体改:前台提交列表套字典,接口 /books/,注每一个字典都可以通过pk
"""
pk = kwargs.get('pk')
request_data = request.data
#单改
if pk:
try:
book_obj = models.Book.objects.get(pk=pk)
except:
return APIResponse(1, 'pk error')
# 修改和新增,都需要通过数据,数据依旧给data,修改与新增不同点,instance要被赋值为被修改对象,这样两个值都有才会去调用update方法
book_ser = serializers.BookModelSerializer(instance=book_obj, data=request_data)
book_ser.is_valid(raise_exception=True)
book_obj = book_ser.save()
return APIResponse(results=serializers.BookModelSerializer(book_obj).data)
# 群改
else:
#如果数据不是列表形式或为空数据不符合要求
if not isinstance(request_data, list) or len(request_data) == 0:
return APIResponse(1, 'data error', http_status=400)
# 注:一定不要在循环体中对循环对象进行增删(影响对象长度)的操作(危险操作)
obj_list = []
data_list = []
for dic in request_data:
#由于内部数据不一定是dict,所以修改操作要注意异常
try:
#如果数据不是字典就会报错
pk = dic.pop('pk')
try:
#可能没有这个id的数据可以修改
obj = models.Book.objects.get(pk=pk, is_delete=False)
obj_list.append(obj)
data_list.append(dic)
except:
pass
except:
return APIResponse(1, 'data error', http_status=400)
book_ser = serializers.BookModelSerializer(instance=obj_list, data=data_list, many=True)
#最后一次全部校验
book_ser.is_valid(raise_exception=True)
book_obj_list = book_ser.save()
return APIResponse(results=serializers.BookModelSerializer(book_obj_list, many=True).data)
Single locally modified, all locally modified
Local and global difference is that the data do not provide all of the field
So long as the coupled partial = True deserializing method on the line
# 局部修改就是在整体修改基础上设置partial=True,将所有参与反序列化字段设置为required=False
book_ser = serializers.BookModelSerializer(instance=book_obj, data=request_data, partial=True)
Little knowledge
Above ListSerializer, ModelSerializer may bind to each other is so achievable
Wl mm below the existing content code have zx content
class wl():
@classmethod
def w(cls):
print(cls.child)
class zx():
class meta():
@classmethod
def m(cls):
mm=wl
mm.child=zx
print(mm)
return mm
zx.meta.m().w()
<class '__main__.wl'>
<class '__main__.zx'>