建数据库
>: mysql -uroot -p密码
>: create database day83 charset=utf8;
表分析
书表Book:name price create_time is_delete authors publish
出版社表Publish:name address phone create_time is_delete
作者表Author:name icon telephone create_time is_delete
作者详情表AuthorDetail:age sex info create_time is_delete author
表关系
Book 与 Publish 一对多
Book 与 Autho 多对多
Author 与 AuthorDetail 一对一
model类
"""
外键处理:
反向查询名字:related_name
表关系:db_constraint + on_delete
db_constraint=False => 断开表关系
on_delete=models.CASCADE 级联
on_delete=models.SET_NULL, null=True 设置为空
on_delete=models.SET_DEFAULT, default=0 设置成默认值0
on_delete=models.DO_NOTHING 不处理
注:多对多关系不需要明确on_delete
"""
from django.conf import settings
class BaseModel(models.Model):
create_time = models.DateTimeField(verbose_name='创建时间', auto_now_add=True)
is_delete = models.BooleanField(verbose_name='是否删除', default=False)
class Meta:
# 有该属性的Model类不会完成数据库迁移产生一张表 - 基表
abstract = True
class Publish(BaseModel):
name = models.CharField(verbose_name='出版社名', max_length=32)
address = models.CharField(verbose_name='地址', max_length=64)
phone = models.CharField(verbose_name='电话', max_length=32)
class Meta:
db_table = 'o_Publish'
verbose_name = '出版社'
verbose_name_plural = verbose_name
def __str__(self):
return self.name
class Author(BaseModel):
name = models.CharField(verbose_name='作者名', max_length=32)
icon = models.FileField(upload_to='icon', default='icon/icon.jpg')
telephone = models.CharField(verbose_name='电话', max_length=32)
class Meta:
db_table = 'o_Author'
verbose_name = '作者'
verbose_name_plural = verbose_name
def __str__(self):
return self.name
class AuthorDetail(BaseModel):
CHOICE_SEX = (
(0, '男'),
(1, '女')
)
age = models.IntegerField(verbose_name='年龄')
sex = models.IntegerField(verbose_name='性别', choices=CHOICE_SEX, default=0)
info = models.TextField(verbose_name='个人详情')
author = models.OneToOneField(verbose_name='作者', to='Author', db_constraint=False, on_delete=models.CASCADE, related_name='detail')
class Meta:
db_table = 'o_AuthorDetail'
verbose_name = '作者详情'
verbose_name_plural = verbose_name
def __str__(self):
return self.author.name + '的详情'
class Book(BaseModel):
name = models.CharField(verbose_name='书名', max_length=32)
price = models.DecimalField(verbose_name='价格', max_digits=5, decimal_places=2, default=66.66)
authors = models.ManyToManyField(verbose_name='作者们', to='Author', db_constraint=False, related_name='books')
publish = models.ForeignKey(verbose_name='出版社', to='Publish', db_constraint=False, on_delete=models.CASCADE,
related_name='books')
class Meta:
db_table = 'o_Book'
verbose_name = '书籍'
verbose_name_plural = verbose_name
def __str__(self):
return self.name
# 插拔字段 - 默认为read_only(不需要考虑反序列化),且不能修改
@property
def publish_name(self):
return self.publish.name
@property
def publish_detail(self):
from . import serializers
return serializers.PublishesModelSerializer(self.publish).data
@property
def author_list(self):
author_arr = []
for author in self.authors.all():
author_arr.append(author.name)
return author_arr
@property
def author_detail_list(self):
author_detail_arr = []
for author in self.authors.all():
author_dic = {}
author_dic['name'] = author.name
author_dic['age'] = author.detail.age
author_dic['telephone'] = author.telephone
# author.icon是对象类型,不能序列化
author_dic['icon'] = settings.MEDIA_URL + str(author.icon)
author_detail_arr.append(author_dic)
return author_detail_arr
# settings.py 配置文件
MEDIA_URL = '/media/'
MEDIA_ROOT = os.path.join(BASE_DIR, 'media')
# urls.py 中路由文件
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'^media/(?P<path>.*)', serve, {'document_root': settings.MEDIA_ROOT}),
]
Serializer序列化类配置
from rest_framework import serializers
from . import models
class TempSerializer(serializers.Serializer):
# 序列化()可以为空
k1 = serializers.CharField()
# 反序列化通常有校验的条件
k2 = serializers.CharField(write_only=True, max_length=32, min_length=3, error_messages={
'max_length': '超长',
'min_length': '超短',
})
k3 = serializers.CharField()
class AuthorsModelSerializer(serializers.ModelSerializer):
class Meta:
fields = ('name', 'icon', 'telephone')
model = models.Author
class PublishesModelSerializer(serializers.ModelSerializer):
class Meta:
fields = ('name', 'address', 'phone')
model = models.Publish
extra_kwargs = {}
class BooksModelSerializer(serializers.ModelSerializer):
# 自定义字段 不建议 书写在Serializer类中,迁移到Model类中
# 在ModelSerializer类的class Meta中 fields 字段值不能为__all__,因为publish_name字段必须参与序列化
# publish_name = serializers.SerializerMethodField()
# def get_publish_name(self, book_obj):
# return book_obj.publish.name
# 只可序列化,导致反序列化崩溃 用Model插拔式自定义字段完成连表深度查询
# publish = PublishesModelSerializer()
class Meta:
# 关联的Model类
model = models.Book
# 提供该表所有与数据库表对应的字段,不能和exclude同时出现
# fields = '__all__'
# 刨除该表的某些字段 - 不常用
# exclude = ('id', 'create_time', 'is_delete')
# 外键自动深度查询 - 不常用
# depth = 1
# 自定义提供该表的哪些字段 - 重点:可以插拔Model类中自定义字段 - 插拔式
fields = ('name', 'price', 'publish', 'authors', 'publish_name', 'publish_detail', 'author_list', 'author_detail_list')
# 1)可以区分 序列化(read_only) 与 反序列化(write_only) 字段
# 2)提供系统默认校验信息即校验失败信息
extra_kwargs = {
'publish': {
'write_only': True
},
'authors': {
'write_only': True
},
'publish_name': {
'read_only': True,
},
'price': {
# 数据库字段设置了默认值,也需要 反序列化 时必须提供该字段
'required': True,
'error_messages': {
'required': '价格不能为空',
}
},
'name': {
'min_length': 3,
'error_messages': {
'min_length': '太短',
}
},
}
# ModelSerializer重写了 update 和 create,如果没有特殊业务要求,可以不需要再重写
def create(self, validated_data):
authors = validated_data.pop('authors')
book_obj = models.Book.objects.create(**validated_data)
# 关系表的新增
# 关系表的相关操作 增add 删remove 改set 清空clear
book_obj.authors.add(*authors)
return book_obj
# def update(self, instance, validated_data):
# return instance
Views视图层配置
from rest_framework.views import APIView
from rest_framework.response import Response
from rest_framework import status
from . import models, serializers
from utils.response import APIResponse
class BooksAPIView(APIView):
# 获取所有
def get(self, request, *args, **kwargs):
books_query = models.Book.objects.all()
books_data = serializers.BooksModelSerializer(books_query, many=True).data
return APIResponse(0, 'ok', books_data)
# 新增一个
def post(self, request, *args, **kwargs):
request_data = request.data
book_ser = serializers.BooksModelSerializer(data=request_data)
if book_ser.is_valid():
book_obj = book_ser.save()
return Response({
'status': 1,
'msg': 'failed',
'results': serializers.BooksModelSerializer(book_obj).data
})
else:
return Response({
'status': 1,
'msg': 'failed',
'results': book_ser.errors
})
# 修改一个
def put(self, request, *args, **kwargs):
pk = kwargs.get('pk', 1)
book_obj = models.Book.objects.filter(pk=pk, is_delete=False).first()
book_ser = serializers.BooksModelSerializer(instance=book_obj, data=request.data)
if book_ser.is_valid():
book_obj = book_ser.save()
return Response({
'status': 0,
'msg': 'ok',
'results': serializers.BooksModelSerializer(book_obj).data
})
else:
return Response({
'status': 1,
'msg': 'failed',
'results': book_ser.errors
})
# 删除一个 /books/1/ | 删除多个 /books/ 数据[1, 2]
def delete(self, request, *args, **kwargs):
pk = kwargs.get('pk')
if pk:
pks = [pk]
else:
pks = request.data
delete_rows = models.Book.objects.filter(pk__in=pks, is_delete=False).update(is_delete=True)
if delete_rows != 0:
return APIResponse(0, 'ok')
return APIResponse(1, '删除失败')
class AuthorsAPIView(APIView):
# 获取所有
def get(self, request, *args, **kwargs):
authors_query = models.Author.objects.all()
authors_data = serializers.AuthorsModelSerializer(authors_query, many=True).data
return Response({
'status': 0,
'msg': 'ok',
'results': authors_data
})
class PublishesAPIView(APIView):
# 获取所有
def get(self, request, *args, **kwargs):
publishes_query = models.Publish.objects.all()
publishes_data = serializers.PublishesModelSerializer(publishes_query, many=True).data
# return Response({
# 'status': 0,
# 'msg': 'ok',
# 'results': publishes_data
# })
from utils.response import APIResponse
return APIResponse(0, 'ok', result=123,
headers={
'Token': 'as12df.88og5z.qw12cv'
}, status=status.HTTP_200_OK)
""" Response类
data:要返回给前台的数据
status:响应的网络状态码
template_name:drf也可以渲染页面
headers:响应头
exception:异常信息
content_type:响应的数据类型,接口默认application/json
def __init__(self, data=None, status=None,
template_name=None, headers=None,
exception=False, content_type=None):
return Response({
'status': 0,
'msg': 'ok',
'results': publishes_data
}, headers={
'Token': 'as12df.88og5z.qw12cv'
}, status=status.HTTP_511_NETWORK_AUTHENTICATION_REQUIRED)
from utils.response import APIResponse
return APIResponse(0, 'ok', result=123,
headers={
'Token': 'as12df.88og5z.qw12cv'
}, status=status.HTTP_511_NETWORK_AUTHENTICATION_REQUIRED)
"""