Model准备

建数据库
>: mysql -uroot -p密码
>: create database day83 charset=utf8;
数据库配置
# settings.py 配置引擎
DATABASES = {
   'default': {
       'ENGINE': 'django.db.backends.mysql',
       'NAME': '数据库名',
       'USER': '账号',
       'PASSWORD': '密码'
  }
}

# __init__.py 配置数据库操作模块
import pymysql
pymysql.install_as_MySQLdb()
表分析
书表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
配置media
# 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}),
]
admin注册model
from django.contrib import admin
from . import models

admin.site.register(models.Book)
admin.site.register(models.Author)
admin.site.register(models.Publish)
admin.site.register(models.AuthorDetail)

 

 

URL接口

# 主路由
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}),
   url(r'^api/', include('api.urls')),
]


# 子路由
from django.conf.urls import url
from . import views
urlpatterns = [
   url(r'^books/$', views.BooksAPIView.as_view()),
   url(r'^books/(?P<pk>\d+)/', views.BooksAPIView.as_view()),
   url(r'^authors/$', views.AuthorsAPIView.as_view()),
   url(r'^authors/(?P<pk>\d+)/', views.AuthorsAPIView.as_view()),
   url(r'^publishes/$', views.PublishesAPIView.as_view()),
   url(r'^publishes/(?P<pk>\d+)/', views.PublishesAPIView.as_view()),
]

 

 

 

ModelSerializers类

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

 

 

二次封装Response类:/utils/response.py

""" 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):
"""

from rest_framework.response import Response
class APIResponse(Response):
   def __init__(self, data_status, msg, results=None, headers=None, status=None, **kwargs):
       # 响应数据必须有数据 状态码 与 信息
       data = {
           'status': data_status,
           'msg': msg,
      }
       # 有响应数据添加响应数据
       if results:
           data['results'] = results
       # 添加其他响应格式数据
       data.update(kwargs)
       # 响应头 和 网络状态码 原样带下与 响应数据 一同生成 Response类 对象
       super().__init__(data=data, headers=headers, status=status)
       
""" 封装前
return Response(
{
          'status': 0,
          'msg': 'ok',
          'results': serializer_data
      },
      headers={
          'Token': 'as12df.88og5z.qw12cv'
      },
      status=status.HTTP_200_OK
)
"""
""" 封装后
return Response(0, 'ok', serializer_data,
headers={'Token': 'as12df.88og5z.qw12cv'},
status=status.HTTP_200_OK
)
"""

 

 

视图接口类:/api/views.py

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 APIResponse(0, 'ok', serializers.BooksModelSerializer(book_obj).data)
       else:
           return APIResponse(1, 'failed', 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 APIResponse(0, 'ok', serializers.BooksModelSerializer(book_obj).data)
       else:
           return APIResponse(1, 'failed', 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 APIResponse(0, 'ok', books_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='一个响应数据',
           headers={
          'Token': 'as12df.88og5z.qw12cv'
      }, status=status.HTTP_200_OK)
posted on 2019-08-15 21:26  郝俊连城  阅读(213)  评论(0)    收藏  举报