一、Django/ORM框架介绍及配置
1.1、ORM框架介绍
ORM框架 O是object,也就类对象的意思,R是relation,翻译成中文是关系,也就是关系数据库中数据表的意思,M是mapping,是映射的意思。在ORM框架中,它帮我们把类和数据表进行了一个映射,可以让我们通过类和类对象就能操作它所对应的表格中的数据。ORM框架还有一个功能,它可以根据我们设计的类自动帮我们生成数据库中的表格,省去了我们自己建表的过程。
django中内嵌了ORM框架,不需要直接面向数据库编程,而是定义模型类,通过模型类和对象完成数据表的增删改查操作。
1.2、Django数据库配置
# 创建项目
django-admin startproject 项目名
# 创建应用app(两条都可实现)
django-admin startapp 应用名
python manage.py startapp 应用名
数据库连接(django 默认连接 aqlite3 数据库,这里使用 mysql 数据库)
# 使用mysql数据库需要在主目录的同名子目录下的 __init__.py 文件下配置
import pymysql
pymysql.install_as_MySQLdb()
# 在主目录的同名子目录下的 settings.py 文件中修改 django 默认数据库
# django 默认连接 sqlite3 数据库
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.sqlite3',
'NAME': os.path.join(BASE_DIR, 'db.sqlite3'),
}
}
#更改为连接 mysql 数据库
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.mysql', # 指明连接数据库的引擎
'NAME': 'django05', # 库名, django 连接的 mysql 数据库库名
'HOST': 'localhost', # 数据库的ip地址,
'PORT': 3306, # 数据库的端口号
'USER': 'root', # 用户名
'PASSWORD': 'admin123' # 密码
}
}
# 在终端登录 mysql
mysql -u root -p
# 输入密码
******
# 创建数据库
create database 库名 charset utf8;
若需跨域配置
# 在主目录的同名子目录下的 settings.py 文件中配置
INSTALLED_APPS = [
"corsheaders"
]
MIDDLEWARE = [
'django.middleware.security.SecurityMiddleware',
'django.contrib.sessions.middleware.SessionMiddleware',
'django.middleware.common.CommonMiddleware',
# 'django.middleware.csrf.CsrfViewMiddleware',
'django.contrib.auth.middleware.AuthenticationMiddleware',
'django.contrib.messages.middleware.MessageMiddleware',
'django.middleware.clickjacking.XFrameOptionsMiddleware',
"corsheaders.middleware.CorsMiddleware"
]
#允许所有源访问
CORS_ORIGIN_ALLOW_ALL =True
路由配置
#主路由里添加子路由(需在子应用中创建python file文件的子路由)
from django.urls import path,include
# from app名 import 子路由
urlpatterns = [
path('admin/', admin.site.urls),
# path("路由/",include(“子路由”))
# 也可以不导包,直接添加
path("路由/",include("app名.子路由"))
]
# 子路由中配置
from django.urls import path
# 导入视图
from . import views
urlpatterns = [
path("路由/",views.方法名.as_view())
]
二、定义模型类数
2.1、定义模型类
不同的数据库中 对应的 sql语句不一样, django为了简单, 统一采用 模型类,模型类 定义在 app/models.py 文件中
from django.db import models
class Books(models.Model):
# 模型类中不需要指定 id字段,会自动生成
name = models.CharField(max_length=20,verbose_name="书名")
# 数据库的可变字符串类型 varchar(20)
# max_length : 指定可变字符串的最大长度
price = models.DecimalField(max_digits=7, decimal_places=2, verbose_name='价格')
# 数据库的 金钱有关的字段 decimal(7,2)
# max_digits: 指定数字的最大位数,包括小数
# decimal_places: 指定小数的 位数
hire_date = models.DateField(verbose_name='出版日期')
# 数据库的 日期字段 date
# auto_now_add: 在对象添加时,自动设置为 当前时间, 后期不再改变
# auto_now: 在对象每次更新时,时间都会设置为更新时的时间
# 避免矛盾,`auto_now`,`auto_now_add`,`default`不能同时出现,一个字段属性只能有其中一条设置,
# 当设置了`auto_now`,或`auto_now_add`时,也会让该字段默认具有`blank=True`(字段可以为空)属性
author = models.CharField(max_length=20, verbose_name='作者')
num = models.IntegerField(verbose_name='库存', default=0)
publish = models.CharField(max_length=20, verbose_name='出版社')
type = models.CharField(max_length=10,verbose_name="类别")
sales_volume = models.IntegerField(verbose_name='销量', default=0)
def __str__(self):
# 修改对象的描述信息, 此时查看图书对象,已经不是默认的对象地址信息, 而是图书对象的书名
return self.name
# 元选项一定属于模型类中的一部分,不能单独使用
class Meta:
db_table = 'tb_book' # 指定表名, 默认为 app名_模型类名
verbose_name = '图书' # amdin中显示的表的名字,为单数形式
verbose_name_plural = verbose_name # 复数形式
2.2、迁移
模型类创建好后,将模型类迁移到数据库
在终端执行迁移命令,会在对应app下生成一个迁移文件migrations 用来记录数据库迁移的信息
如果数据库出错,需删库重创时,必须把migrations 文件删掉再重新创建,否则报错
# 生成迁移文件
python manage.py makemigrations
# 执行迁移文件同步数据到数据库
python manage.py migrate
迁移成功生成表格
修改字段、迁移
# 若数据库中未添加数据,修改字段属性,重新执行迁移命令即可
# 若有数据,添加新的字段,新字段的属性为:可以为空 或 有默认值,则可重新执行迁移命令
# 若有数据,想添加一个非空、没有默认值的字段则报:
You are trying to add a non-nullable field 'type' to books without a default; we can't do that (the database needs som
ething to populate existing rows).
Please select a fix:
1) Provide a one-off default now (will be set on all existing rows with a null value for this column)
2) Quit, and let me add a default in models.py
翻译:
请选择修复方案:
1)现在提供一个一次性的默认值(将在所有现有行上设置此列的空值)
2)退出,让我在models.py中添加一个默认值
# 选 1 后,需再输入一个默认值,(测试时,输入中文报错,如数据不多,建议再输入默认值: 1 后,在数据库中修改为需要数据),继续执行迁移命令5
# 选 2 ,给字段添加default 属性,即可重新迁移
反向迁移
若有一个完整的数据库和数据,想要生成模型类以使用,则可以使用反向迁移,
(只进行过简单尝试了解,并未深入写下去,感受:多个模型类在一起有些杂乱,有些字段属性可能用不到,但确实比自己重新写入模型类迁移插入数据快的多,并且字段对应不会出错,表关系清晰,可以把需要的模型类拉入自己的app下修修改改使用)
python manage.py inspectdb > models.py # >后面是生成的文件路径和名称
python manage.py inspectdb > ./APP名称/models.py # 生成到指定的app下
2.3、插入数据
常用的插入数据方法:一、创建超级用户 二、python连接数据库直接添加
在应用app下的admin.py 下注册
from django.contrib import admin
from .models import *
admin.site.register(模型类名)
python manage.py createsuperuser 创建超级用户
邮箱不需要添,账号密码依次设置
初次访问连接:127.0.0.1/admin
从右侧的database >>>> 点击“+” >>>> Data Source >>>>MYSQL
填写里面的数据,Test Connection验证如果成功就可以往里面添加数据
三、单表据库操作(增、删、改、查)
3.1、增
save() :通过创建模型类对象,执行对象的save()方法保存到数据库中。
from datetime import date
book = Books(
name= "《剑来》",
price = 33,
hire_date = date(2020.11.2),
author = "烽火戏诸侯",
num = 22,
publish = "起点",
type = "玄幻",
sales_volume = 2
)
book.save()
create :通过模型类.objects.create()保存
from datetime import date
Books.objects.create(
name= "《雪中悍刀行》",
price = 33,
hire_date = date(2020.11.2),
author = "烽火戏诸侯",
num = 22,
publish = "顶点",
type = "玄幻",
sales_volume = 2
)
3.2、删
通过get/filter 获取到需要删除的数据,使用delete()方法直接删除
book = Books.objects.get(id = 7)
book.delete()
book = Books.objects.filter(name= "《雪中悍刀行》")
book.delete()
Books.objects.get(id = 8).delete()
Books.objects.filter(name= "《雪中悍刀行》").delete()
逻辑删除只是给表添加字段,用来记录数据的状态,删除也只是修改了数据状态,查询的时候把这些数据筛选出去,看上去是删除了
例:添加字段 status 默认值为1,表示存在,当要删除时,把status 改为0,表示删除。查询数据的时候,加一个判断条件status = 1,这样获取的数据就是理论上还存在的,这种方法称为逻辑删除
3.3、改
save :修改模型类对象的属性,然后执行save()方法(单条数据修改)
book = Books.objects.get(id = 6)
book.publish = "笔趣阁"
book.save()
使用模型类.objects.filter().update(),(多条数据修改)
Books.objects.filter(num=22).update(publish="番茄阅读")
3.4查(重点)
查询所有
# 查询所有数据
>>> Books.objects.all()
<QuerySet [<Books: 《斗破苍穹》>, <Books: 《斗罗大陆》>, <Books: 《遮天》>,<Books: 《坏蛋是怎样炼成的》>, <Books: 《曹贼》>, <Books: 《剑来》>, <Books: 《雪中
悍刀行》>]>
# 查询id=1的详细数据(values不能使用get,会报错)
>>> Books.objects.filter(id=1).values()
<QuerySet [{'id': 1, 'name': '《斗破苍穹》', 'price': Decimal('25.00'), 'hire_date': datetime.date(2022, 5, 3), 'author': '天蚕土豆', 'num': 100, 'publish': '笔趣阁', 'type': '玄幻', 'sales_volume': 500}]>
# 查询的数据为查询集,想取里面的数据需要切片取值
# 查询所有数据,获取斗破苍穹数据里的id
>>> book = Books.objects.all()
>>> print(">>>>>>>>",book)
>>> print(">>>>>>>>",book[0])
>>> print(">>>>>>>>",book[0].id)
>>>>>>>> <QuerySet [<Books: 《斗破苍穹》>, <Books: 《斗罗大陆》>, <Books: 《遮天》>,<Books: 《坏蛋是怎样炼成的》>, <Books: 《曹贼》>, <Books: 《剑来》>, <Books: 《雪中悍刀行》>]>
>>>>>>>> 《斗破苍穹》
>>>>>>>> 1
查询单个
# 查询id = 2 的数据
>>> Books.objects.get(id = 2)
《斗罗大陆》
# 如果查询不存在或者有多个,则会抛出异常,这时可以使用filter 过滤查询
# 查询id= 30的数据,表中不存在id = 30 数据
>>> Books.objects.get(id = 30)
Traceback (most recent call last):
File "D:jiaocaisoftpythonpythonlibsite-packagesdjangocorehandlersexcepti
on.py", line 34, in inner
response = get_response(request)
......
File "D:jiaocaisoftpythonpythonlibsite-packagesdjangodbmodelsquery.py",
line 408, in get
self.model._meta.object_name
my_sql.models.Books.DoesNotExist: Books matching query does not exist.
# 查询num= 22 的数据,表中num = 22 数据有两条
>>> Books.objects.get(num=22)
Traceback (most recent call last):
File "D:jiaocaisoftpythonpythonlibsite-packagesdjangocorehandlersexcepti
on.py", line 34, in inner
......
my_sql.models.Books.MultipleObjectsReturned: get() returned more than one Books -- it returned 2!
查询数量
# 查询Books 表中的数据的数量
>>> Books.objects.count()
7
# 查询num= 22 的数据
>>> Books.objects.filter(num=22)
<QuerySet [<Books: 《剑来》>, <Books: 《雪中悍刀行》>]>
# 查询id=30的数据,id= 30 没有数据,
>>> Books.objects.filter(id = 30)
<QuerySet []>
模糊查询 (字段名__contains)判断是否包含,如果要包含%无需转义,直接写即可。
运算符都区分大小写,在这些运算符前加上i表示不区分大小写、icontains
# 查询书名包含“斗”的书籍
>>> Books.objects.filter(name__contains="斗")
<QuerySet [<Books: 《斗破苍穹》>, <Books: 《斗罗大陆》>]>
startswith、endswith :以指定值开头或结尾
运算符都区分大小写,在这些运算符前加上i表示不区分大小写、istartswith、iendswith
# 查询以“剑”开头的数据,因数据加书名号,所以查询也要加
>>> Books.objects.filter(name__startswith="《剑")
<QuerySet [<Books: 《剑来》>]>
# 查询名字不为空的,
>>> Books.objects.filter(name__isnull=False)
<QuerySet [<Books: 《斗破苍穹》>, <Books: 《斗罗大陆》>, <Books: 《遮天》>,<Books: 《坏蛋是怎样炼成的》>, <Books: 《曹贼》>, <Books: 《剑来》>, <Books: 《雪中
悍刀行》>]>
# 查询id在1,2,3,4里的数据
>>> Books.objects.filter(id__in=[1,2,3,4])
<QuerySet [<Books: 《斗破苍穹》>, <Books: 《斗罗大陆》>, <Books: 《遮天》>,<Books: 《坏蛋是怎样炼成的》>]>
# 查询id在1-4内的数据
>>> Books.objects.filter(id__range=(1,3))
比较查询
# 查询id大于等于3的数据
>>> Books.objects.filter(id__gte=3)
<QuerySet [<Books: 《遮天》>, <Books: 《坏蛋是怎样炼成的》>, <Books: 《曹贼》>, <Books: 《剑来》>, <Books: 《雪中悍刀行》>]>
日期查询
year、month、day、week_day、hour、minute、second:对日期时间类型的属性进行运算。
# 查询出版日期在2021年的数据
>>> Books.objects.filter(hire_date__year=2021)
<QuerySet [<Books: 《雪中悍刀行》>]>
# 查询出版日期在2022年7月1日之前的数据
>>> Books.objects.filter(hire_date__lte=date(2022,7,1))
<QuerySet [<Books: 《斗破苍穹》>, <Books: 《坏蛋是怎样炼成的》>, <Books: 《雪中悍刀行》>]>
# 库存大于销量的数据
# F 方法使用时注意导包
>>> from django.db.models import F
>>> Books.objects.filter(num__gt=F("sales_volume"))
<QuerySet [<Books: 《斗罗大陆》>, <Books: 《曹贼》>, <Books: 《剑来》>]>
Q 查询
多个过滤器逐个调用表示逻辑与关系,同sql语句中where部分的and关键字。
# 查询id 大于3,库存大于200的数据
# Q 方法使用时注意导包
>>> Books.objects.filter(id__gt=3,num__gt=200)
>>> Books.objects.filter(id__gt=3).filter(num__gt=200)
>>> Books.objects.filter(Q(id__gt=3) & Q(num__gt=200))
<QuerySet [<Books: 《曹贼》>]>
# 查询id 不等于3的数据
>>> Books.objects.filter(~Q(id=3))
# 查询id 不等于3的数据
>>> Books.objects.exclude(id=3)
使用aggregate()过滤器调用聚合函数。聚合函数包括:Avg(平均),Count(数量),Max(最大),Min(最小),Sum(求和),被定义在django.db.models中,需导包,返回值 {‘属性名__聚合类小写’:值}
# 查询库存总数 (Avg/Max/Min/Sum 等用法一致)
>>> from django.db.models import Sum,Avg,Max,Min
>>> Books.objects.aggregate(Sum("num"))
>>> Books.objects.all().aggregate(Sum("num"))
{'num__sum': 869}
# 查询所有信息的数量
>>> Books.objects.all().count()
7
# 查询所有数据按库存排序(根据字段排序为升序,字段前加负号 “-” 为降序
>>> Books.objects.all().order_by("num") # 升序
>>> Books.objects.all().order_by("-num") # 降序
四、两表联查
4.1、一对多、多对一
# 老师
class Teacher(models.Model):
name = models.CharField(max_length=10, verbose_name='姓名')
gender = models.IntegerField(choices=((0,"男"),(1,"女")),verbose_name='性别')
# 学生
class Student(models.Model):
name = models.CharField(max_length=10, verbose_name='姓名')
score = models.IntegerField(verbose_name='成绩')
# 此时的teacher 和 数据库中的 外键字段不太一样, 他是关联的整个老师对象, 并不是老师的id
# 但是通过模型类生成的表中的 字段就是 老师的id
# 也可以设置外键可以为空null=True,这样写入学生数据时可以不用提供老师的信息,如果外键设置不为空时,保存会引发错误
teacher = models.ForeignKey(to=Teacher, on_delete=models.CASCADE, verbose_name='老师')
# to:关联的模型类
# on_delete: 此时学生关联老师,如果要删除老师, 对应的学生应该怎么办
# CASCADE: 删除老师,与之关联的学生也会被删除
在创建一对多的关系的,需要在ForeignKey的第二参数中加入on_delete=models.CASCADE 主外关系键中,级联删除,也就是当删除主表的数据的时候从表中的数据也随着一起删除。
这是数据库外键定义的一个可选项,用来设置当主键表中的被参考列的数据发生变化时,外键表中响应字段的变换规则的。
update 是主键表中被参考字段的值更新;delete是指在主键表中删除一条记录
on_update 和 on_delete 后面可以跟的词语有四个:
1. no action 表示 不做任何操作,
2. set null 表示在外键表中将相应字段设置为null
3. set default 表示设置为默认值
4. cascade 表示级联操作,就是说,如果主键表中被参考字段更新,外键表中也更新,主键表中的记录被删除,外键表中改行也相应删除
4.1.2、增
# 增加老师,和单表一样
teacher = Teacher.objects.create(name='李老师', gender=1)
# 增加学生, 学生中的外键teacher实际是一个老师对象
# 通过外键_id形式给外键赋值 id
stu = Student.objects.create(name="小明",score=98,teacher_id=1)
# 直接给外键赋值一个老师对象 (注:必须是对象,get查询获取的是对象,filter查询获取的是查询集,需切片才可使用)
teacher = Teacher.objects.filter(id=2)
stu = Student.objects.create(name="小明",score=98,teacher=teacher[0])
4.1.3、删
# 删除学生(正常删除)
Student.objects.get(id = 9).delete()
# 删除老师(因创建表的时候,两表定义的关系为:on_delete=models.CASCADE ,所以删除老师,其对应的学生也会被删除)
Teacher.objects.filter(id=4).delete()
4.1.4、改
# 修改老师
Teacher.objects.filter(id=3).update(name="李老师")
# 修改学生(修改需要用 filter 获取学生的查询集,使用 get 报错)
Student.objects.filter(id = 6).update(teacher_id = 1)
4.1.5、查
# 正向查询:通过学生,查询对应老师
# 查询id为1的学生,以及对应的老师
# 1. 查询学生对象
student = Student.objects.get(id=1)
# 2. 想要获取对应的老师信息 (对象.外键.关联模型类的字段)
teacher = student.teacher.name
# 反向查询:通过老师,查询老师的学生
# 查询id为1 的老师 以及他对应的学生
# 1. 查询老师对象
teacher = Teacher.objects.get(id=1)
# 2. # 通过django内置的 属性 模型类_set, 可以反向查询老师名下的所有学生
student = teacher.student_set.all()
4.2、一对一
4.2.1、创建
# 一个老师对应一个班级,切记:外键一对一不能重复
# 班级:名字、地址
class Cls(models.Model):
name = models.CharField(max_length=10, verbose_name='班级名称')
address = models.CharField(max_length=20, verbose_name='教室地址')
# 老师
class Teacher(models.Model):
name = models.CharField(max_length=10, verbose_name='姓名')
gender = models.IntegerField(choices=((0,"男"),(1,"女")),verbose_name='性别')
cls = models.OneToOneField(to=Cls, on_delete=models.CASCADE)
4.2.2、增
# 添加班级
Cls.objects.create(name='四年级', address='304')
# 添加老师(由于老师和班级是一对一的关系,一个老师只能对应一个班级,所以添加班级表的外键一定不能和之前的重复,否则报错)
Teacher.objects.create(name="宋老师",gender=1,cls_id=4)
4.2.3、删
# 删除班级,其对应的老师也会被删除
Cls.objects.get(id=3).delete()
# 删除老师,其班级不变化
Teacher.objects.get(id=4).delete()
4.2.4、改
# 修改老师
Teacher.objects.filter(id=2).update(cls_id=4)
# 修改班级
Cls.objects.filter(id=4).update(name="三年级")
4.2.5、查
# 正向查询,通过老师,查询对应班级
teacher = Teacher.objects.get(id=1)
cls1 = teacher.cls.name
# 反向查询,通过班级查询老师, 反向查询时,只需要 模型类 本身即可
cls1 = Cls.objects.get(id=1)
teacher = cls1.teacher.name
4.3、多对多
4.3.1、创建
# 类别:名字
class Type(models.Model):
name = models.CharField(max_length=10,verbose_name="类别名")
# 书籍(之前的单表,将其 类别 设置为外键,实现多对多的关系,一本书可以有多个类别,一个类别可以对应多本书)
class Books(models.Model):
name = models.CharField(max_length=20,verbose_name="书名")
price = models.DecimalField(max_digits=7, decimal_places=2, verbose_name='价格')
hire_date = models.DateField(verbose_name='出版日期')
author = models.CharField(max_length=20, verbose_name='作者')
num = models.IntegerField(verbose_name='库存', default=0)
publish = models.CharField(max_length=50, verbose_name='出版社')
# type = models.CharField(max_length=10,verbose_name="类别")
sales_volume = models.IntegerField(verbose_name='销量', default=0)
# 多对多没有 on_delete参数
type = models.ManyToManyField(to=Type)
# 在多对多的情况,有专门的第三张表,存储 对应关系,表本身并没有字段来存储对应关系,此时删除任意数据,不影响另一张表数据
4.3.2、增
# 添加类别
Type.objects.create(name="黑道")
# 添加书籍
book = Books.objects.create(
name= "《雪中悍刀行》",
price = 33,
hire_date = date(2021,1,2),
author = "烽火戏诸侯",
num = 22,
publish = "顶点",
sales_volume = 2
)
# 给书籍添加类别
# 对象.关联字段.add(关联的type表的id)
book.type.add(1,2,3)
4.3.3、删
# 多对多关联字段的删除,要使用 remove 来进行关系的断开,而不是直接使用 delete ,remove 只会断开数据之间的联系,但是不会将数据删除
# 解除书籍绑定的标签
type1 = Type.objects.get(id=1)
book = Books.objects.get(id=1)
# 书籍对象.关联字段.remove(类别对象)
book.type.remove(type1)
4.3.4、改
# 先解除关联,在重新添加新关联
4.3.5、查
# 正向查询 :通过书籍查询对应的类别
book = Books.objects.get(id=1)
# 通过外键查询该书籍的全部类别
type1 = book.type.all()
# 反向查询:通过类别查询该类别的书籍
type1 = Type.objects.get(id=1)
# 查询该类别对应的所有书籍
book = type1.books_set.all()
五、模型类序列化器
5.1、序列化器介绍
序列化组件的作用
前后端通常是通过json格式进行数据传递,但是json序列化不能序列化对象,而序列化组件,可以自定义特定结构把对象序列化返回给前端,同时可以对前端传入的参数进行数据校验等功能
book_set = Book.objects.all()
books = []
for book in book_set:
books.append({
'id': book.id,
'btitle': book.btitle,
'price': book.price,
'bread': book.bread,
'bcomment': book.bcomment
})
序列化是将对象状态转换为可保持或传输的格式的过程。与序列化相对的是反序列化,它将流转换为对象。这两个过程结合起来,可以轻松地存储和传输数据
序列化:从Django数据库 >>>>> Django的模型 >>>>> JSON/XML等文本格式
例如:我们在django的ORM中获取到的数据默认是模型对象,但是模型对象数据无法直接提供给前端或别的平台使用,所以我们需要把数据进行序列化,变成字符串或者json数据,提供给别人。
反序列化:上面过程的反方向
例如:前端js提供过来的json数据,对于python而言就是字符串,我们需要进行反序列化换成模型类对象,这样我们才能把数据保存到数据库中。
模型类序列化器与序列化器的区别
ModelSerializer与常规的Serializer相同,但提供了:
基于Django模型类自动生成一系列字段
基于Django模型类自动为序列化器生成validators
包含默认的create() 创建方法和update() 更新方法的实现
DRF 框架(使用DRF框架里的序列化方法)
– 视图封装:DRF统一封装了请求的数据为request.data以及返回数据的Response方法
– 序列化器:DRF提供了序列化器可以统一便捷的进行序列化及反序列化工作
– 认证:对用户登陆进行身份验证
– 权限:对用户权限进行认证,超级用户、普通用户、匿名用户啥的
– 限流:对访问的用户流量进行限制,减轻接口的访问压力
– 过滤:可以对列表数据进行字段过滤,并可以通过添加django-fitlter扩展来增强支持
– 排序:来帮助我们快速指明数据按照指定字段进行排序
– 分页:可以对数据集进行分页处理
– 异常处理:DRF提供了异常处理,我们可以自定义异常处理函数
– 接口文档生成:DRF还可以自动生成接口文档
5.2、序列化器使用
安装DRF框架
pip install djangorestframework -i https://pypi.tuna.tsinghua.edu.cn/simple
配置 settings
INSTALLED_APPS = [
...
'rest_framework',
]
models.py 创建模型类
from django.db import models
class Books(models.Model):
name = models.CharField(max_length=20,verbose_name="书名")
price = models.DecimalField(max_digits=7, decimal_places=2, verbose_name='价格')
hire_date = models.DateField(verbose_name='出版日期')
author = models.CharField(max_length=20, verbose_name='作者')
num = models.IntegerField(verbose_name='库存', default=0)
publish = models.CharField(max_length=50, verbose_name='出版社')
sales_volume = models.IntegerField(verbose_name='销量', default=0)
在应用下创建文件 serializers.py 定义序列化
from rest_framework import serializers
# 1. 定义序列化类, 依赖于模型类
# 2. 指定序列化器字段, 字段和模型类的字段一样
# max_length: 校验name存储的字符串的 最大长度
# min_length: 校验name存储的字符串的 最小长度
# 序列化器中的字符串长度,可以不写,只有在反序列化时,才会使用
class BookSer(serializers.Serializer):
id = serializers.IntegerField()
name = serializers.CharField(max_length=20,label="书名")
price = serializers.DecimalField(max_digits=7, decimal_places=2, label='价格')
hire_date = serializers.DateField(label='出版日期')
author = serializers.CharField(max_length=20, label='作者')
num = serializers.IntegerField(label='库存', default=0)
publish = serializers.CharField(max_length=50, label='出版社')
sales_volume = serializers.IntegerField(label='销量', default=0)
在 views.py 里使用
from .serializers import BookSer
from django.http import JsonResponse
from rest_framework.views import APIView
class Getbook(APIView):
def post(self,request):
# 若使用get获取对象,序列化器里不需要加 many=True
# 若使用filter、all 获取查询集,序列化里需要加 many=True
# JsonResponse默认只允许转换 字典格式, 当需要转换非字典时,需要 设置safe参数为 False
book = Books.objects.filter(id=1)
ser = BookSer(book,many=True)
return JsonResponse(ser.data,safe=False)
返回的数据
[
{
"id": 1,
"name": "《斗破苍穹》",
"price": "25.00",
"hire_date": "2022-05-03",
"author": "天蚕土豆",
"num": 100,
"publish": "笔趣阁",
"sales_volume": 500
}
]
5.3、数据的拼接
models.py 创建模型类(一对多关系)
# 老师
class Teacher(models.Model):
name = models.CharField(max_length=10, verbose_name='姓名')
gender = models.IntegerField(choices=((0,"男"),(1,"女")),verbose_name='性别')
# 学生
class Student(models.Model):
name = models.CharField(max_length=10, verbose_name='姓名')
score = models.IntegerField(verbose_name='成绩')
teacher = models.ForeignKey(to=Teacher, on_delete=models.CASCADE, verbose_name='老师')
一对多时,定义普通的序列化数据展示
class StuSer(serializers.Serializer):
id = serializers.IntegerField(read_only=True)
# read_only=True,指明当前字段只参与序列化(查询), 不参与反序列化(添加)
name = serializers.CharField()
score = serializers.IntegerField()
teacher_id = serializers.IntegerField()
class Getstu(APIView):
def post(self,request):
stus = Student.objects.all()
ser = StuSer(stus,many=True)
return Response(ser.data)
展示数据
[
{
"id": 1,
"name": "张三",
"score": 85,
"teacher_id": 1
},
{
"id": 2,
"name": "李四",
"score": 88,
"teacher_id": 1
}
]
一对多时,定义普通的序列化数据展示不太全面,这时可以直接拼接数据
from django.http import JsonResponse
from rest_framework.views import APIView
from rest_framework.response import Response
class Addstu(APIView):
def post(self,request):
stus = Student.objects.all()
stu_list = []
for stu in stus:
stu_list.append({
"id":stu.id,
"name":stu.name,
"score":stu.score,
# 方便的获取学生对应的老师信息
"teacher":stu.teacher.name,
"teacher_gender":stu.teacher.gender
})
# 使用Response 返回效果一样
# return Response(stu_list)
return JsonResponse(stu_list,safe=False)
返回数据
[
{
"id": 1,
"name": "张三",
"score": 85,
"teacher": "张老师",
"teacher_gender": 0
},
{
"id": 2,
"name": "李四",
"score": 88,
"teacher": "张老师",
"teacher_gender": 0
}
]
5.4、自定义序列化器实现添加修改
定义序列化器
from rest_framework import serializers
from .models import Student
class StuSer(serializers.Serializer):
id = serializers.IntegerField(read_only=True)
# read_only=True,指明当前字段只参与序列化(查询), 不参与反序列化(添加)
name = serializers.CharField()
score = serializers.IntegerField()
teacher_id = serializers.IntegerField()
# 1.1 需要利用序列化器实现数据的反序列化添加,
# 需要自定义实现 create 方法,
def create(self, data):
# data是一个形参,格式是字典,存储就是需要添加的数据, 如 {"name":"王五, "score": 37, "teacher_id":1}
# 1.1.1 在方法中利用模型类创建对象
stu = Student.objects.create(**data) # ** 就是将字典进行拆包,按照键值对的形式传入create方法
# 1.1.2 返回创建后的对象
return stu
# 1.2 如果需要利用序列化器实现数据的更新,需要自定义实现update方法
def update(self, instance, validated_data):
"""
:param instance: 需要更新的实例对象, 这个序列化器对应学生, 所以 instance代表学生对象
:param validated_data: 需要更新的新数据
:return: 返回更新后的新对象
"""
# 1.2.1 从字典中按照键取值,如果不存在,设置默认值,
# 然后将取到的值 赋值给学生对象的属性
instance.name = validated_data.get('name', instance.name)
instance.score = validated_data.get('score', instance.score)
instance.teacher_id = validated_data.get('teacher_id', instance.teacher_id)
instance.save() # 1.2.2属性更新之后,需要重新保存
# 1.2.3 返回更新后的新对象
return instance
class Addstu(APIView):
def post(self,request):
# 1.2.1 获取参数
data = request.data
# 1.2.2 创建序列化器对象
ser = StuSer(data=data)
# 1.2.3 调用序列化器对象的验证方法进行验证, 如果有误,直接返回错误信息
ser.is_valid(raise_exception=True)
# 1.2.4 保存数据
ser.save()
# 1.2.5 返回创建后的对象信息,需要指明状态码
return Response(ser.data, status=201)
class Putstu(APIView):
# 修改对象属性,需要id,
def put(self, request, pk):
# 1. 查询到id对应的对象, 当id不存在时,找不到对象,会抛出异常
try:
stu = Student.objects.get(id=pk)
except Exception as e:
return Response({
'msg': 'NOT FOUND'
}, status=404)
# 2. 获取新数据
data = request.data
# 3. 创建序列化器对象
ser = StuSer(stu, data=data)
# 4. 校验
ser.is_valid(raise_exception=True)
# 5. 保存
ser.save()
# 6. 返回更新后的新对象, 更细或创建成功,状态码都是201
return Response(ser.data, status=201)
5.5、模型类序列化器
定义模型类序列化器
from rest_framework import serializers
from .models import Student
class Stuser(serializers.ModelSerializer):
# 必须定义元类
class Meta:
# 指明需要序列化的模型类
model = Student
# 指明模型类的所有字段参与序列化与反序列化
# 不需要所有字段时可自己定义,例:["id","name","score"]
fields = "__all__"
# 深度、查看关联对象而不是一个id,depth应该是整数,表明嵌套的层级数量(一般不用)
# depth = 1
视图获取全部、添加
from rest_framework.views import APIView
from rest_framework.response import Response
from .serializers import StuSer
class StudentView(APIView):
def get(self,request):
# 1. 查询全部数据,得到查询集
students = Student.objects.all()
# 2. 创建序列化器对象, 同时需要设置参数many=True
ser = StuSer(students, many=True)
# 3. 返回序列化数据
return Response(ser.data)
def post(self, request):
# 1. 获取客户端发送的数据
data = request.data
# 2. 创建序列化器对象
ser = StuSer(data=data)
# 3. 验证,如果错误,直接返回错误信息
ser.is_valid(raise_exception=True)
# 4. 保存
ser.save()
# 5. 返回序列化数据
return Response(ser.data, status=201)
视图、查询单个、删除、修改
# 查询单个、删除、修改
class StudentDetailView(APIView):
def get(self, request, pk):
# 1. 查询id对应的数据,得到对象
try:
student = Student.objects.get(id=pk)
except Exception as e:
return Response({
'msg': 'NOT FOUND'
}, status=404)
# 2. 创建序列化器对象
ser = StuSer(student)
# 3. 返回序列化数据
return Response(ser.data)
def put(self, request, pk):
# 1. 查询特定对象
try:
student = Student.objects.get(id=pk)
except Exception as e:
return Response({
'msg': 'NOT FOUND'
}, status=404)
# 2. 获取参数
data = request.data
# 3. 创建序列化器对象
ser = StuSer(student, data=data)
# 4. 验证
ser.is_valid(raise_exception=True)
# 5. 保存
ser.save()
# 6. 返回序列化后的数据
return Response(ser.data)
def delete(self, request, pk):
# 1. 利用id直接找到数据,并删除
Student.objects.filter(id=pk).delete()
# 2. 返回状态码 `204`
return Response(status=204)
路由配置
path('student/', StudentView.as_view()), # 增、查全部
path('student/<int:pk>/', StudentDetailView.as_view()), # 查单个、修改、删除
原文地址:https://blog.csdn.net/m0_65883616/article/details/125736469
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如若转载,请注明出处:http://www.7code.cn/show_38432.html
如若内容造成侵权/违法违规/事实不符,请联系代码007邮箱:suwngjj01@126.com进行投诉反馈,一经查实,立即删除!