DRF框架准备
django restframework 框架
mysql
新建库
mysql> create database restframework charset utf8mb4;
Query OK, 1 row affected (0.00 sec)
配置xadmin
安装
pip3 install https://codeload.github.com/sshwsfc/xadmin/zip/django2 -i https://pypi.tuna.tsinghua.edu.cn/simple
注册xadmin
settings.py
INSTALLED_APPS = [
...
'xadmin',
'crispy_forms',
'reversion',
...
]
# 修改使用中文界面
LANGUAGE_CODE = 'zh-Hans'
#LANGUAGE_CODE = 'en-us'
# 修改时区
TIME_ZONE = 'Asia/Shanghai'
#TIME_ZONE = 'UTC'
xadmin数据库迁移
python3 manage.py makemigrations
python3 manage.py migrate
新增xadmin路由
新增总路由
# from django.contrib import admin
# from django.urls import path,include
#
# from django.urls import re_path
# from django.conf import settings
# from django.views.static import serve
import xadmin
xadmin.autodiscover()
# version模块自动注册需要版本控制的 Model
from xadmin.plugins import xversion
xversion.register_models()
#用xadmin,就不用admin要注释,
urlpatterns = [
# #path('admin/', admin.site.urls),
# re_path(r'media/(?P<path>.*)', serve, {"document_root": settings.MEDIA_ROOT}),
# path('', include("home.urls")),
path(r'xadmin/', xadmin.site.urls),
]
创建xadmin超级用户
$ python3 manage.py createsuperuser
用户名 (leave blank to use 'wangjunxiang'): root
电子邮件地址: root@root.com
Password: 123123
Password (again): 123123
密码长度太短。密码必须包含至少 8 个字符。
这个密码太常见了。
密码只包含数字。
Bypass password validation and create user anyway? [y/N]: y
Superuser created successfully.
配置xadminx.py
新建apps/自定义项目app名/adminx.py
- 注意:配置文件一定叫 adminx.py
import xadmin
from xadmin import views
class BaseSetting(object):
"""xadmin的基本配置"""
enable_themes = True # 开启主题切换功能
use_bootswatch = True
xadmin.site.register(views.BaseAdminView, BaseSetting)
class GlobalSettings(object):
"""xadmin的全局配置"""
site_title = "luffy" # 设置站点标题
site_footer = "luffy" # 设置站点的页脚
menu_style = "accordion" # 设置菜单折叠
xadmin.site.register(views.CommAdminView, GlobalSettings)
# 导入表
from .models import 表1,表2,表3
class 表1_ModelAdmin(object):
list_display=["表字段1","表字段2","表字段3"]
xadmin.site.register(表1, 表1_ModelAdmin)
class 表2_ModelAdmin(object):
list_display=["表字段1",]
xadmin.site.register(表2, 表2_ModelAdmin)
class 表3_ModelAdmin(object):
list_display=["表字段1",]
xadmin.site.register(表3, 表3_ModelAdmin)
设置访问白名单
settings.py中设置为 '*'
ALLOWED_HOSTS = ['*']
数据库录入数据
访问 127.0.0.1:8000/xadmin

INSERT INTO `book` VALUES (1, '无限恐怖', 1, '2020-08-20', 1);
INSERT INTO `book` VALUES (2, '盘龙', 2, '2020-08-20', 2);
INSERT INTO `book` VALUES (3, '射雕英雄传', 3, '2020-08-20', 3);
INSERT INTO `book` VALUES (4, '星辰变与无限空间', 3, '2020-08-20', 3);
INSERT INTO `book` VALUES (5, 'asdadsasdasd', 3, '2020-08-20', 2);
INSERT INTO `book` VALUES (6, 'django', 1, '2020-08-20', 1);
BEGIN;
INSERT INTO `book_author` VALUES (1, 1, 1);
INSERT INTO `book_author` VALUES (2, 2, 3);
INSERT INTO `book_author` VALUES (3, 3, 2);
INSERT INTO `book_author` VALUES (4, 4, 1);
INSERT INTO `book_author` VALUES (5, 4, 3);
INSERT INTO `book_author` VALUES (6, 5, 1);
INSERT INTO `book_author` VALUES (7, 5, 2);
INSERT INTO `book_author` VALUES (8, 5, 3);
INSERT INTO `book_author` VALUES (9, 6, 4);
COMMIT;
BEGIN;
INSERT INTO `publisher` VALUES (1, '集英社');
INSERT INTO `publisher` VALUES (2, '华中出版社');
INSERT INTO `publisher` VALUES (3, '清华大学出版社');
COMMIT;
配置DRF框架
安装DRF
pip3 install djangorestframework==3.11.0
注册DRF
settings.py
INSTALLED_APPS = [
....
....
#导入DRF框架
'rest_framework',
]
DRF【序列化组件】
序列化:get()前端发起请求,后端给前端返回数据
反序列化:post()前端请求后端并带着数据,后端进行字段校验后,更新数据,返回前端
通用的模型/总路由
总路由做路由分发
from django.contrib import admin
from django.urls import path, include
urlpatterns = [
path('admin/', admin.site.urls),
path('books/', include("SerDemo.urls")),
]
models表结构
from django.db import models
# Create your models here.
__all__ = ["Book", "Publisher", "Author"]
class Book(models.Model):
title = models.CharField(max_length=32, verbose_name="图书名称")
CHOICES = ((1, "Python"), (2, "Go"), (3, "Linux"))
category = models.IntegerField(choices=CHOICES, verbose_name="图书的类别")
pub_time = models.DateField(verbose_name="图书的出版日期")
publisher = models.ForeignKey(to="Publisher", on_delete=None)
author = models.ManyToManyField(to="Author")
def __str__(self):
return self.title
class Meta:
db_table = "book"
verbose_name_plural = "图书表"
class Publisher(models.Model):
title = models.CharField(max_length=32, verbose_name="出版社的名称")
def __str__(self):
return self.title
class Meta:
db_table = "publisher"
verbose_name_plural = "出版社表"
class Author(models.Model):
name = models.CharField(max_length=32, verbose_name="作者的姓名")
def __str__(self):
return self.name
class Meta:
db_table = "author"
verbose_name_plural = "作者表"
迁移数据库
python3 manage.py makemigrations
python3 manage.py migrate
继承【Serializer】序列化器实例
1,查看多条数据的接口
设置子路由接口
urls.py
from django.urls import path, include
from .views import BookView
urlpatterns = [
path('list', BookView.as_view()),
]
继承【APIView】的视图
views.py
from .models import Book, Publisher #引入表
from rest_framework.views import APIView #引入DRF框架
from rest_framework.response import Response #引入DRF返回
from .serializers import BookSerializer #引入序列化器
class BookView(APIView):
def get(self, request):
"""序列化实例"""
book_list = Book.objects.all()
ret = BookSerializer(book_list, many=True)
return Response(ret.data)
def post(self, request):
"""
反序列化实例
当序列化器需要保存数据到数据库,需要在序列化器中重写 create方法
"""
print(request.data)
serializer = BookSerializer(data=request.data) #传反序列化的数据
if serializer.is_valid(): #序列化器对前端传来的数据校验
serializer.save() #验证通过,保存到数据库
return Response(serializer.validated_data)
else:
return Response(serializer.errors)
新建序列化器
新建 serializers.py文件
from rest_framework import serializers
from .models import Book
class PublisherSerializer(serializers.Serializer):
"""序列化器嵌套"""
id = serializers.IntegerField()
title = serializers.CharField(max_length=32)
class AuthorSerializer(serializers.Serializer):
"""序列化器嵌套"""
id = serializers.IntegerField()
name = serializers.CharField(max_length=32)
class BookSerializer(serializers.Serializer):
"""
read_only=True 前端对后端发起请求,后端返回数据给前端用,这个字段就定义为 read_only
write_only=True 前端提交字段修改数据库字段的值用到,让前端提交字段为 w_字段名,而不是数据库原先的字段,需要和前端说好
"""
id = serializers.IntegerField(required=False)
title = serializers.CharField(max_length=32)
CHOICES = ((1, "Python"), (2, "Go"), (3, "Linux"))
category = serializers.ChoiceField(choices=CHOICES, source="get_category_display", read_only=True)
w_category = serializers.ChoiceField(choices=CHOICES, write_only=True)
pub_time = serializers.DateField()
# 同理,凡是前端读取的字段都用read_only,凡是前端修改数据的都是write_only
publisher = PublisherSerializer(read_only=True)
publisher_id = serializers.IntegerField(write_only=True)
author = AuthorSerializer(many=True, read_only=True)
author_list = serializers.ListField(write_only=True)
def create(self, validated_data):
"""
当序列化器对字段校验成功后,保存新的数据,必须要重写create方法,views视图中 serializer.save() 才能不报错
validated_data:前端传来的数据都在这个里面
"""
"""
模拟前端发送json数据
{
"title": "Alex的使用教程",
"w_category": 1,
"pub_time": "2018-10-09",
"publisher_id": 1,
"author_list": [1, 2]
}
"""
book = Book.objects.create(
title=validated_data["title"],
category=validated_data["w_category"],
pub_time=validated_data["pub_time"],
publisher_id=validated_data["publisher_id"],
)
book.author.add(*validated_data["author_list"]) #.add对author表添加多条记录
return book
验证
查询所有数据【get请求】
当get请求 http://0.0.0.0:8000/books/list
查看到所有的数据

新增一条数据【post请求】
当给 http://0.0.0.0:8000/books/list 发送post请求的 json 数据,提交成功
json数据如下
{
"title": "寸芒",
"w_category": 1,
"pub_time": "2018-10-09",
"publisher_id": 2,
"author_list": [2, 3]
}

2,查看单条数据的接口
设置子路由接口
urls.py 新增路由
查看单条数据需要携带id过来
# from django.urls import path, include
#from .views import BookView
from .views import BookEditView
urlpatterns = [
# path('list', BookView.as_view()),
path('retrieve/<int:id>', BookEditView.as_view()),
]
继承【APIView】的视图
views.py 新增一个视图类
from .models import Book
from rest_framework.views import APIView
from rest_framework.response import Response
from .serializers import BookSerializer
class BookEditView(APIView):
def get(self, request, id):
"""查看单条数据,前端需要传id进来,get要接收id"""
book_obj = Book.objects.filter(id=id).first()
ret = BookSerializer(book_obj)
return Response(ret.data)
def put(self, request, id):
"""
当序列化器修改某一条数据,需要重新写序列化器中 的update方法
"""
"""
前端put请求携带如下数据修改这条记录
{
"title":"神雕侠侣",
}
"""
book_obj = Book.objects.filter(id=id).first()
#第一个参数传需要更新的对象,第二个参数传需要更新的数据,第三个参数partial=True允许进行部分更新
serializer = BookSerializer(book_obj, data=request.data, partial=True)
if serializer.is_valid(): #对字段进行验证
serializer.save()
return Response(serializer.data)
else:
return Response(serializer.errors)
def delete(self, request, id):
book_obj = Book.objects.filter(id=id).first()
book_obj.delete()
return Response("")
修改序列化器函数
serializers.py文件
from rest_framework import serializers
from .models import Book
class PublisherSerializer(serializers.Serializer):
id = serializers.IntegerField()
title = serializers.CharField(max_length=32)
class AuthorSerializer(serializers.Serializer):
id = serializers.IntegerField()
name = serializers.CharField(max_length=32)
def my_validate(value):
"""
自定义钩子方法
例如,传的值不能含有「敏感信息」这4个字符串
"""
if "敏感信息" in value.lower():
raise serializers.ValidationError("不能含有敏感信息") #如果有,抛出异常
else:
return value
class BookSerializer(serializers.Serializer):
"""
read_only=True 前端对后端发起请求,后端返回数据给前端用,这个字段就定义为 read_only
write_only=True 前端提交字段修改数据库字段的值用到,让前端提交字段为 w_字段名,而不是数据库原先的字段,需要和前端说好
"""
id = serializers.IntegerField(required=False)
title = serializers.CharField(max_length=32, validators=[my_validate]) #validators=[] 列表中传入自定义钩子方法
CHOICES = ((1, "Python"), (2, "Go"), (3, "Linux"))
category = serializers.ChoiceField(choices=CHOICES, source="get_category_display", read_only=True)
w_category = serializers.ChoiceField(choices=CHOICES, write_only=True)
pub_time = serializers.DateField()
# 同理,凡是前端读取的字段都用read_only,凡是前端修改数据的都是write_only
publisher = PublisherSerializer(read_only=True)
publisher_id = serializers.IntegerField(write_only=True)
author = AuthorSerializer(many=True, read_only=True)
author_list = serializers.ListField(write_only=True)
def create(self, validated_data):
"""
当序列化器对字段校验成功后,保存新的数据,必须要重写create方法,views视图中 serializer.save() 才能不报错
validated_data:前端传来的数据都在这个里面
"""
"""
模拟前端发送json数据
{
"title": "寸芒",
"w_category": 1,
"pub_time": "2011-01-09",
"publisher_id": 2,
"author_list": [2, 3]
}
"""
book = Book.objects.create(
title=validated_data["title"],
category=validated_data["w_category"],
pub_time=validated_data["pub_time"],
publisher_id=validated_data["publisher_id"],
)
book.author.add(*validated_data["author_list"]) #.add对author表添加多条记录
return book
def update(self, instance, validated_data):
"""
instance 就是视图传过来的第一个参数:需要更新的模型对象,比如传过来的book_obj,里面有title,category字段
"""
instance.title = validated_data.get("title", instance.title) #如果第一个参数title取不到会报错,就给个第二个值不会报错了
instance.category = validated_data.get("category", instance.category)
instance.pub_time = validated_data.get("pub_time", instance.pub_time)
instance.publisher_id = validated_data.get("publisher_id", instance.publisher_id) #还能修改foreignkey
if validated_data.get("author_list"):
"""用来修改manytomany的字段"""
# instance就是book_obj,author就是book表中manytomany的字段
# ORM中manytomany新增是.add(),修改是.set()
instance.author.set(validated_data["author_list"])
instance.save()
return instance
def validate_title(self, value):
"""
局部钩子函数:对title字段数据进行校验
例如:title字段中必须含有python
"""
if "python" not in value.lower():
#如果验证失败,则抛出异常
raise serializers.ValidationError("标题必须含有python")
return value
def validate(self, attrs):
"""
全局钩子函数: 对多个字段进行校验
例如,当w_category是1(python),publisher是1的时候,验证才通过
attrs 是字典 {"字段名","值"}
"""
if attrs["w_category"] == 1 and attrs["publisher_id"] == 1:
return attrs
else:
raise serializers.ValidationError("分类以及标题不符合要求")
序列化器的验证功能
局部钩子函数【权重低】
与自定义钩子函数相比,先进行自定义钩子函数的校验,权重比较低
在序列化器中通过定义 def validate_想要验证的字段名(self, value) 的函数,校验单个定义的字段,来自定义验证方法
class BookSerializer(serializers.Serializer):
.....
def create(self, validated_data):
.....
def update(self, instance, validated_data):
......
def validate_title(self, value):
"""
局部钩子函数:对title字段数据进行校验
例如:title字段中必须含有python
"""
if "python" not in value.lower():
#如果验证失败,则抛出异常
raise serializers.ValidationError("标题必须含有python")
return value
全局钩子函数
直接在序列化器中定义 def validate(self, attrs) 函数,用来校验多个字段
class BookSerializer(serializers.Serializer):
.....
def create(self, validated_data):
.....
def update(self, instance, validated_data):
.....
def validate_title(self, value):
.....
def validate(self, attrs):
"""
全局钩子函数: 对多个字段进行校验
例如,当w_category是1(python),publisher是1的时候,验证才通过
attrs 是字典 {"字段名","值"}
"""
if attrs["w_category"] == 1 and attrs["publisher_id"] == 1:
return attrs
else:
raise serializers.ValidationError("分类以及标题不符合要求")
自定义钩子函数【权重高】
与局部钩子函数相比,先进行自定义钩子函数的校验,权重高
需要在类外面单独定义个函数 def 自定义函数名(value) ,里面写验证逻辑
某个字段调用这个自定义钩子函数,需要在参数后面加参数 alidators=[] 列表中传入自定义钩子方法
def my_validate(value):
"""
自定义钩子方法
例如,传的值不能含有「敏感信息」这4个字符串
"""
if "敏感信息" in value.lower():
raise serializers.ValidationError("不能含有敏感信息") #如果有,抛出异常
else:
return value
class BookSerializer(serializers.Serializer):
.....
title = serializers.CharField(max_length=32, validators=[my_validate]) #validators=[] 列表中传入自定义钩子方法,代表对这个字段进行校验
.....
def create(self, validated_data):
.....
def update(self, instance, validated_data):
.....
def validate_title(self, value):
.....
def validate(self, attrs):
.....
测试
查看单条数据【get请求】
请求 http://0.0.0.0:8000/books/retrieve/1 接口

修改单条数据【put请求】
请求 http://0.0.0.0:8000/books/retrieve/1 接口

验证单条数据【put请求:序列化器中的局部钩子函数实现】
对 http://0.0.0.0:8000/books/retrieve/5 接口发起put请求,在钩子函数中会定义内容中是否含有python如果没有则抛出异常

带python的数据才会成功

继承【ModelSerializer】序列化器实例
之前继承 serializers.Serializer 需要写很多字段,很麻烦,为了解决繁琐的代码,不用写表的所有字段都定义了,继承 serializers.ModelSerializer 自动的解决
查看多条数据的接口
设置子路有接口
from django.urls import path, include
from .views import BookView
urlpatterns = [
path('list', BookView.as_view()),
]
继承【APIView】的视图
from .models import Book
from rest_framework.views import APIView
from rest_framework.response import Response
from .serializers import BookSerializer
class BookView(APIView):
def get(self, request):
book_list = Book.objects.all()
ret = BookSerializer(book_list, many=True)
return Response(ret.data)
def post(self, request):
""" 当序列化器需要保存数据到数据库,需要在序列化器中重写 create方法 """
print(request.data)
serializer = BookSerializer(data=request.data) #传反序列化的数据
if serializer.is_valid(): #序列化器对前端传来的数据校验
serializer.save() #验证通过,保存到数据库
return Response(serializer.data)
else:
return Response(serializer.errors)
序列化器
from rest_framework import serializers
from .models import Book
class BookSerializer(serializers.ModelSerializer):
"""继承ModelSerializer,序列化器会与models进行结合"""
class Meta:
"""先对序列化器的model进行配置"""
model = Book
fields = "__all__" # 返回__all__所有字段,或者指定字段["id", "title", "pub_time"]
# depth = 1 #代表外键嵌套层数为1层,有可能外键关联的表还会外键关联第三张表,这代表停到第一层就停止
extra_kwargs = {
"category": {"write_only": True}, # category 字段不写的话,会返回出去,这个字段不想通过接口提供出去
"publisher": {"write_only": True}, # 就写在这里,这个字段作为反序列化post请求过来修改字段用
"author": {"write_only": True}
}
############ SerializerMethodField 取出关联表想要的字段,不想要的可以不要 ,下面的变量名会带着值变成返回给前端 ##########
category_display = serializers.SerializerMethodField(read_only=True)
# 如果拿出想外键对应表中的字段,不是外键id,下面需要继续定义 def get_<publisher/字段名> 函数,返回想要关联表(外键/manytomany)的字段
publisher_info = serializers.SerializerMethodField(read_only=True)
# manytomany字段对应表中的值,下面需要继续定义 def get_<authors/字段名> 函数
authors = serializers.SerializerMethodField(read_only=True)
def get_category_display(self,obj):
return obj.get_category_display() # orm方法 get_字段_display ,获取chiose中文 ((1,张三),(2,李四))
def get_publisher_info(self, obj):
"""
函数以 get_字段命名
obj是序列化的每个book对象,因为Class meta 中定义了model=book
"""
publisher_obj = obj.publisher # 根据publisher外键取 Publisher 表里的值
return {
"id": publisher_obj.id,
"title": publisher_obj.title
}
def get_authors(self, obj):
"""
函数以 get_字段命名
obj是序列化的每个book对象,因为Class meta 中定义了model=book
"""
authors_query_set = obj.author.all()
return [{"id": author_obj.id, "name": author_obj.name} for author_obj in authors_query_set]
测试
查看所有数据【get请求】
当get请求 http://0.0.0.0:8000/books/list

新增一条数据【post请求】
对接口 http://0.0.0.0:8000/books/list post请求 携带数据
不需要重写create方法,自动新增数据
新增如下如下数据
{
"title": "Alex的使用教程2",
"category": 1,
"pub_time": "2018-10-09",
"publisher": 1,
"author": [
1,
2
]
}

Serializer和ModelSerializer区别

Serializer 和 ModelSerializer的区别
https://www.cnblogs.com/xiugeng/p/11460855.html
浙公网安备 33010602011771号