Django框架之模型层
【一】前言
- django自带的sqlite3数据库对日期格式不敏感,处理的时候总是出错
- 所以通常都不用自带的数据库
【1】测试脚本
- django项目的每一个app下都有一个test.py文件,这是一个测试脚本
- 当我们想要测试一个django的某一张模型表时,就可以通过这个测试脚本,直接测试,而不需要写前后端路由和视图的交互。
- 当然,也可以不用app自带的测试脚本,可以自己创建一个,但是测试脚本的测试环境都需要我们自己配置
## test.py
from django.test import TestCase
import os
# Create your tests here.
if __name__ == '__main__':
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'student.settings')
import django
django.setup()
## 以上就是测试环境配置的代码
from app1 import models ## 这一句话时导入模型层,必须得写在配置好的测试环境之下,要不然就会报错
【2】数据准备
- 在模型层创建好一张表
from django.db import models
import datetime
# Create your models here.
class Student(models.Model):
username = models.CharField(max_length=15)
password = models.CharField(max_length=15)
reg_time = models.DateTimeField(default=datetime.datetime.now())
- 数据库配置代码
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.mysql',
'NAME': 'student',
'USER': 'root',
'PASSWORD': '123456',
'IP': '127.0.0.1',
'PORT': 3306
}
}
【二】单表操作
【1】增删改查
# 增
# 方法1 这个返回值是创建的对象本身
res = models.Student.objects.create(username='hqq', password='123123')
# 方法2
user_obj = models.Student(username='hqqq',password='123123')
user_obj.save()
# 删
# 方法1 res 返回值是一个元组,元组的第一个值是删除的个数
res = models.Student.objects.filter(pk=6).delete()
# 方法2
user_obj = models.Student.objects.filter(pk=12).first()
user_obj.delete()
# 改
# 方法1 返回值是影响的行数
res = models.Student.objects.filter(pk=1).update(password='123123123123')
# 方法2 get取对象的方法容易报错,如果get里面的条件找不到对象的话就会报错
user_obj = models.Student.objects.get(pk=1)
user_obj.password='123123'
user_obj.save()
# 查
# 方法1
user_obj = models.Student.objects.filter(pk=1)
# 方法2 get在找不到对象的时候就会报错
user_obj2 = models.Student.objects.get(pk=7)
【2】必知必会13条
# all 查询所有数据 查询的结果类似于一个字典
res = models.Student.objects.all()
# fillter() 筛选出符合条件的所有数据,如果没有筛选出数据不会报错
res = models.Student.objects.filter(pk=1)
# get() 筛选出符合条件的唯一对象,如果返回多个对象就会报错,没有符合条件的对象也会报错
res = models.Student.objects.get(username='tom')
# first() 返回查询到的对象中的第一个对象
res = models.Student.objects.all().first()
# last() 返回查询到的对象中的第最后一个对象
res = models.Student.objects.all().last()
# values() 返回指定字段的数据 返回的结果是一个类似于列表套字典的形式
res = models.Student.objects.values('username','password')
# values_list() 返回指定字段的数据,返回的结果是一个类似于列表套元组的形式
res = models.Student.objects.values_list('username','password')
# distinct() 对查询出来的数据进行去重,注意查询的数据的字段不能有主键
res = models.Student.objects.values('username', 'password').distinct()
# order_by() 对查询出来的数据以指定的字段进行排序,在指定字段前面加上减号就是降序,默认是升序
res1 = models.Student.objects.order_by('pk')
res2 = models.Student.objects.order_by('-pk')
# reverse() 对数据进行反转,数据必须是经过排序的,要不然不生效
res = models.Student.objects.order_by('pk').reverse()
# count() 对数据进行统计,一共有多少条
res = models.Student.objects.filter(username='green').count()
# exclude() 筛选除了符合条件以外的数据
res = models.Student.objects.exclude(username='green')
# exists() 判断某条数据是否存在,返回值是一个布尔值
res = models.Student.objects.filter(pk=1).exists()
【3】神奇的双下划线查询
# 大于 gt
# 查询年龄大于23岁的数据
res = models.Student.objects.filter(age__gt=23)
# 小于 lt
# 查询年龄小于21岁的数据
res = models.Student.objects.filter(age__lt=23)
# 大于等于 gte
# 查询年龄大于等于22岁的数据
res = models.Student.objects.filter(age__gte=23)
# 小于等于 lte
# 查询年龄小于等于19岁的数据
res = models.Student.objects.filter(age__lte=19)
# 在...里 in
# 查询年龄在18 19 23 岁的数据
res = models.Student.objects.filter(age__in=[18, 19, 23])
# 在...之间 range
# 查询年龄在18到25岁之间的数据 顾头又顾尾
res = models.Student.objects.filter(age__range=[18, 25])
# 模糊查询,区分大小写 contains
# 查询出名字里面含有y的数据,它默认是区分大小写的
res = models.Student.objects.filter(username__contains='y')
# 模糊查询,不区分大小写 icontains
res = models.Student.objects.filter(username__icontains='Y')
# 查询名字以g开头的数据 startswith
res = models.Student.objects.filter(username__startswith='g')
# 不区分大小写 istartswith
res = models.Student.objects.filter(username__istartswith='G')
# 查询时间 __year __month __day __hour __minute __second
# 查询注册时间的月份是4月的
res = models.Student.objects.filter(reg_time__month=4)
【三】多表查询引入
【1】数据准备
- 在django中,建立外键联系与mysql中不一样,djiango是先建立表再建立外键联系
# 书籍表
class Book(models.Model):
title = models.CharField(max_length=15)
price = models.DecimalField(max_digits=8, decimal_places=2)
publish_time = models.DateField(auto_now_add=True)
publish = models.ForeignKey(to='Publish', on_delete=models.CASCADE)
author = models.ManyToManyField(to='Author')
'''
书籍和作者的关系是多对多,需要带三张表来维系两表之间的关系,
在django中,只需要声名一个虚拟字段,再用ManyToManyField建立联系,就能自动建立第三张表
书籍和出版社的关系是一对多,一个出版社可以出版多本书,外键建立多的一放,即Book表,使用ForeignKey建立联系
'''
# 作者表
class Author(models.Model):
name = models.CharField(max_length=15)
age = models.IntegerField(default=18)
detail = models.OneToOneField(to='AuthorDetail', on_delete=models.CASCADE)
'''
作者表和作者详情表是一对一的关系,外键建立再任意一方都可以,但是建立再查询频率高的一方,即Author表
'''
# 作者详情表
class AuthorDetail(models.Model):
phone = models.CharField(max_length=11)
addr = models.CharField(max_length=15)
# 出版社表
class Publish(models.Model):
name = models.CharField(max_length=15)
addr = models.CharField(max_length=15)
email = models.EmailField()
【2】一对多关系外键的增删改查
增
# 给书籍表添加数据
# 方式1 直接传值
res = models.Book.objects.create(title='三国演义', price='99.99', publish_id=1)
# 方式2 通过虚拟字段(就是在建立外键关系时用的字段名),传入出版社表的对象
publish_obj = models.Publish.objects.filter(pk=2).first()
res = models.Book.objects.create(title='西游记', price=88.88, publish=publish_obj)
删
# 删除某个出版社
# 返回的对象是一个元组,元组的第一个参数是删除的数量,第二个对象是一个字典,字典的键某张表,值是某张表删除数据的数量
res = models.Publish.objects.filter(pk=1).delete()
改
# 修改书籍表中的出版社ID
# 方式一 直接修改
res = models.Book.objects.filter(pk=2).update(publish_id=3)
# 方式二 通过虚拟字段(就是在建立外键关系时用的字段名),传入出版社表的对象
publish_obj = models.Publish.objects.filter(pk=2).first()
res = models.Book.objects.filter(pk=3).update(publish=publish_obj)
【3】多对多关系外键的增删改查
- 操作多对多关系的外键,就要操作第三张表,很明显不能再直接操作现有的表了,因为models.py里面并没有django自动创建的第三张表
- 需要通过建立外键的那张表创建的对象的属性去操作,这个属性就是我们建立第三张表时的那个虚拟字段
- 最后再点add,括号里面可以填数字或者对应作者表创建的对象
- 就可以给这本书添加一个在作者表中id为所填数字的作者id
增
# 给书籍添加作者
# 方法1 先创建一个书籍对象,再点书籍对象的author,再点add方法
book_obj = models.Book.objects.filter(pk=1).first()
book_obj.author.add(1) #给该书添加一个在作者表中主键为1的作者
# 方法2 直接塞一个对象进去
book_obj = models.Book.objects.filter(pk=2).first()
author_obj = models.Author.objects.filter(pk=1).first() # 创建作者对象
book_obj.author.add(author_obj)
删
# 给书籍删除作者
# 方法1 先创建一个书籍对象,再点书籍对象的author,再点remove方法
book_obj = models.Book.objects.filter(pk=1).first()
res = book_obj.author.remove(2) # 删除在作者表中主键为2的作者
# 方法2 直接删除对象
book_obj = models.Book.objects.filter(pk=1).first()
author_obj = models.Author.objects.filter(pk=3).first()
res = book_obj.author.remove(author_obj)
改
# 修改书籍作者
# 修改的本质是先删除,再添加.需要使用set方法,set方法的参数必须是一个可迭代对象,如元组或者列表
# 方法1
book_obj = models.Book.objects.filter(pk=1).first()
book_obj.author.set([1, 2, 3])
# 方法2 塞对象
book_obj = models.Book.objects.filter(pk=1).first()
author_obj_1 = models.Author.objects.filter(pk=1).first()
author_obj_2 = models.Author.objects.filter(pk=2).first()
book_obj.author.set([author_obj_1, author_obj_2])
清空
# 清空某本书和作者的所有关联
book_obj = models.Book.objects.filter(pk=1).first()
book_obj.author.clear()
【4】正反向的概念
- 现有书籍表和出版社表,是一对多的关系
- 通过书籍表查询出版社,外键字段建立在书籍表,那么这就是正向查询
- 通过出版社表查询书籍,外键字段建立在书籍表,那么这就是反向查询
- 多对多和一对一的关系也是如此,外键建立在哪里,从那张表查询另一张表就是正向查询,反之就是反向查询。
【四】多表查询案例
【1】子查询(基于对象的跨表查询)
- 在写代码前,先确认这次查找是正向查找还是反向查找
- 正向查找直接找字段名,反向查找直接找表名的小写
.all
和__set.all()
是在前对象可能有多个后对象的情况下用的
# 1.查询书籍主键为1的出版社名称 正向查询找字段
book_obj = models.Book.objects.filter(pk=1).first()
res = book_obj.publish.name
# 2.查询书籍主键为1的作者名称 正向查询找字段
book_obj = models.Book.objects.filter(pk=2).first()
author = book_obj.author.all().first().name # 由于这里一本书可能有多个作者,所以需要.all()
# 3.查询作者green的电话号码
author_obj = models.Author.objects.filter(name='green').first()
detail_obj = author_obj.detail.phone
# 4.查询出版社是东方出版社出版的书 反向查询找表名的小写
publish_obj = models.Publish.objects.filter(name='东方出版社').first()
res = publish_obj.book_set.all() # 由于一个出版社可能会对应很多本书所以这里需要加上_set.all()
# 5.查询作者是green的书 反向查询 找表名的小写
author_obj = models.Author.objects.filter(name='green').first()
res = author_obj.book_set.all() # 由于一个作者可能会有很多本书,所以这里需要加上_set.all()
# 6.查询手机号是110的作者姓名 反向查询 找表名的小写
author_detail_obj = models.AuthorDetail.objects.filter(phone='110').first()
author_obj = author_detail_obj.author.name # 由于这里作者详情和作者是一对一的关系,直接.表名的小写即可
【2】联表查询(基于双下划线的跨表查询)
- 还是那句话正向查询找字段,反向查询找表名小写
- filter和values都同样适用
# 1.查询green的手机号(一行代码解决) 正向查询找字段,反向查询找表名小写
# 正向查询
res = models.Author.objects.filter(name='green').values('detail__phone')
# 反向查询
res = models.AuthorDetail.objects.filter(author__name='green').values('phone')
# 2.查询书籍主键为1的出版社名称和书的名称
# 正向查询
res = models.Book.objects.filter(pk=1).values('publish__name','title')
# 反向查询
res = models.Publish.objects.filter(book__pk=1).values('name','book__title')
# 3.查询书籍主键为1的作者姓名、
# 正向查询
res = models.Book.objects.filter(pk=1).values('author__name')
# 反向查询
res = models.Author.objects.filter(book__pk=1).values('name')
# 4.查询green的手机号(一行代码解决) 不允许通过Author表查询
# 正向查询
res = models.Author.objects.filter(name='green').values('detail__phone')
# 反向查询
res = models.AuthorDetail.objects.filter(author__name='green').values('phone')
# 5.查询书籍主键是1的作者的手机号
# 正向查询
res = models.Book.objects.filter(pk=1).values('author__detail__phone')
# 反向查询
res = models.AuthorDetail.objects.filter(author__book__pk=1).values('phone')
【五】聚合查询
【1】引入
- 聚合查询通常是需要配合分组一起使用的
- 如果想要单独使用聚合查询就需要用到方法aggregate
- 在django中使用聚合查询,需要从django.db.models导入方法
from django.db.models import Sum, Max, Min, Count, Avg
【2】案例
# 查询所有书的平均价格
res = models.Book.objects.aggregate(Avg('price'))
# 聚合方法可以一次使用多个
res = models.Book.objects.aggregate(Avg('price'), Sum('price'), Max('price'), Min('price'), Count('pk'))
【六】分组查询
【1】引入
- 在mysql中的分组查询,分组之后只能获取到分组的数据,其他字段无法获取。
- 这是因为默认开启了严格模式
【2】语法
-
在django中,分组的语法是
models.表名.objects.annotate()
,这时是以models.后面的表名为分组依据 -
如果想要以某张表的字段为分组依据
models.表名.objects.values('字段名').annotate()
-
总结:如果有values则以values里面的字段为分组依据,如果没有则以models.后面的表名为分组依据
【3】案例
# 1.统计每个出版社买的书的最便宜的价格
res = models.Publish.objects.annotate(min_price=Min('book__price')).values('name', 'min_price')
# 分析
读题可知以出版社为分组依据,再利用聚合函数,对每个出版社出版的书的价格进行处理,得到价格最便宜的书
# 2.统计每一本书的作者个数
res = models.Book.objects.annotate(author_num=Count('author__pk')).values('title','author_num')
# 分析
读题可知以书籍为分组依据,再利用聚合函数Count,先跳到author表中,去计算主键的个数。
# 3.统计不止一个作者的图书
res = models.Book.objects.annotate(author_num=Count('author__pk')).filter(author_num__gte=2).values('title','author_num')
# 解析
读题可知以书籍分组,先通过聚合函数Count,跳到author表中,去计算主键的个数得到每本书的作者的个数,再通过filter筛选author_num大于等于2的
# 4.查询每个作者出的书的总价格
res = models.Author.objects.annotate(sum_price=Sum('book__price')).values('name','sum_price')
# 解析
读题可知以作者分组,在分组内先跳到书籍表,利用Sum聚合函数获取书籍总价格
【七】F和Q查询
【1】F查询
- 使用F查询前需要导入F类
from django.db.models import F
- F查询可以帮助我们直接获取到表中的某个字段的值
# 1.查询卖出数大于库存数的书籍
res = models.Book.objects.filter(maichu__gt=F('kucun'))
# 解析
如果不用F查询,可以发现一个尴尬的点,就是没办法表示出maichu__gt= 等号后面的数字,但是用了F查询,就可以很轻松的拿到某个字段对应的数据
# 2.将所有书籍的价格提升50块
res = models.Book.objects.all().update(price=F('price') + 50)
# 3.将所有数的名称后面加上爆款两个字
# 如果需要进行字符串拼接操作就需要导入其他两个类
'''
# from django.db.models.functions import Concat
# from django.db.models import Value
'''
res = models.Book.objects.all().update(title=Concat(F('title'), Value('爆款')))
【2】Q查询
- 使用Q查询前需要导入Q类
from django.db.models import Q
- Q查询可以方便的改变查询条件之间是or 还是 and 还是 not
- 两个Q对象之间用逗号连接是and关系 |连接是or关系 ~连接是not关系
# 1.查询卖出数大于100或者价格小于80的书籍
res = models.Book.objects.all().filter(Q(maichu__gt=100)|Q(price__lt=80))
# Q的高阶用法 能够将查询条件的左边也变成 字符串形式
q = Q()
q.connector = 'or'
q.children.append(('maichu__gt', 100))
q.children.append(('price__lt', 80))
res = models.Book.objects.all().filter(q)
print(res)
【八】Django中如何开启事务
【1】事务的四大特性ACID
# 原子性(Atomicity)
事务被视为一个不可分割的原子操作单元。
这意味着要么全部操作成功并永久保存,要么全部操作失败并回滚到事务开始前的状态,不存在部分成功或部分失败的情况
# 一致性(Consistency)
事务在执行前后,数据库都必须保持一致状态。
这意味着事务执行前后,数据库中的数据必须满足所有定义的完整性约束,例如列级别的约束、外键关系等。
# 隔离性(Isolation)
事务之间应该相互隔离,每个事务的执行应该与其他事务的执行相互独立,互不干扰。
隔离性确保了多个事务可以并发执行,而不会产生不一致的结果。
# 持久性(Durability)
一旦事务成功提交后,其所做的修改将永久保存在数据库中,即使发生系统故障或重启,数据也能够恢复到提交后的状态。
持久性通过将事务日志写入非易失性存储介质来实现,如硬盘驱动器或固态硬盘。
【2】Django中如何开启事务
# 首先要导入方法
# from django.db import transaction
## 开启事务
with transaction.atomic():
...
【九】ORM中常用的字段及参数
【1】常用字段
# 1.AutoField
int自增列,必须填入参数primary_key=True。一张表没有自增列时,会自动创建一个名为id的字段
# 2.IntegerField
一个整数类型,范围在 -2147483648 to 2147483647。(一般不用它来存手机号(位数也不够),直接用字符串存,)
# 3.CharField
字符类型,必须提供max_length参数,它表示字符串的最长长度
# 4.DateField
日期字段,日期格式为YYYY-MM-DD 相当于Python中的datetime.date()的实例
# 5.DateTimeField
日期时间字段,格式 YYYY-MM-DD HH:MM[:ss[.uuuuuu]][TZ],相当于Python中的datetime.datetime()实例。
【2】字段合集
- 基础字段:
CharField(max_length=None)
: 用于存储短文本字符串,指定最大长度。TextField()
: 用于存储长文本字符串。IntegerField()
: 用于存储整数。FloatField()
: 用于存储浮点数。BooleanField()
: 用于存储布尔值(True 或 False)。DateField()
: 用于存储日期。DateTimeField()
: 用于存储日期和时间。TimeField()
: 用于存储时间。EmailField()
: 用于存储电子邮件地址。URLField()
: 用于存储 URL。UUIDField()
: 用于存储 UUID。FileField()
: 用于上传文件。ImageField()
: 用于上传图像文件。
- 关系字段:
ForeignKey(to, on_delete=None)
: 用于定义一对多关系,指向另一个模型的主键字段。OneToOneField(to, on_delete=None)
: 用于定义一对一关系,每个源记录只能与一个目标记录关联。ManyToManyField(to, ...)
: 用于定义多对多关系,允许一个模型的多个实例与另一个模型的多个实例相关联。
- 特殊字段:
AutoField()
: 自动增长的整数字段。BigIntegerField()
: 用于存储大整数。BinaryField()
: 用于存储二进制数据。DecimalField(max_digits=None, decimal_places=None)
: 用于存储十进制数。DurationField()
: 用于存储时间间隔。IPAddressField()
: 用于存储 IPv4 地址。GenericIPAddressField()
: 用于存储 IPv4 或 IPv6 地址。PositiveIntegerField()
: 用于存储正整数。PositiveSmallIntegerField()
: 用于存储小范围的正整数。SlugField()
: 用于存储 URL 中的部分。SmallIntegerField()
: 用于存储小整数。
- 特殊约束:
UniqueConstraint(fields, name=None)
: 确保字段组合的唯一性。CheckConstraint(check, name=None)
: 添加自定义的检查约束条件。
【3】django和mysql字段之间的对应关系
'AutoField': 'integer AUTO_INCREMENT',
'BigAutoField': 'bigint AUTO_INCREMENT',
'BinaryField': 'longblob',
'BooleanField': 'bool',
'CharField': 'varchar(%(max_length)s)',
'CommaSeparatedIntegerField': 'varchar(%(max_length)s)',
'DateField': 'date',
'DateTimeField': 'datetime',
'DecimalField': 'numeric(%(max_digits)s, %(decimal_places)s)',
'DurationField': 'bigint',
'FileField': 'varchar(%(max_length)s)',
'FilePathField': 'varchar(%(max_length)s)',
'FloatField': 'double precision',
'IntegerField': 'integer',
'BigIntegerField': 'bigint',
'IPAddressField': 'char(15)',
'GenericIPAddressField': 'char(39)',
'NullBooleanField': 'bool',
'OneToOneField': 'integer',
'PositiveIntegerField': 'integer UNSIGNED',
'PositiveSmallIntegerField': 'smallint UNSIGNED',
'SlugField': 'varchar(%(max_length)s)',
'SmallIntegerField': 'smallint',
'TextField': 'longtext',
'TimeField': 'time',
'UUIDField': 'char(32)',
【4】自定义字段
- 自定义字段需要自己写一个类,继承models.Field类
- 重写
__init__
和db_type
方法
class MyCharField(models.Field):
def __init__(self, max_length, *args, **kwargs):
super().__init__(max_length=max_length, *args, **kwargs)
self.max_length = max_length
def db_type(self, connection):
# 返回真正的数据以及各种约束条件
return f'CHAR({self.max_length})'
【十】数据库查询优化
【1】惰性查询
- ORM语句的特点是惰性查询
- 如果我们只是写了一条ORM语句,但是并没有用到这条语句锁查出来的数据时,django是不会执行这条ORM语句的。
# 不执行的情况
models.Book.objects.all()
# 执行的情况
res = models.Book.objects.all()
print(res)
【2】only与defer
-
only和defer是django中控制查询返回字段的方法
-
only和defer括号里面的参数都是一个或者多个字段
-
only方法用于指定查询结果中应该包含的字段,用该方法得到的对象,点括号内的字段可以不用再经过数据库直接拿到数据
-
defer方法用于指定查询结果中不应该包含的字段,用该方法得到的对象,点括号内的字段需要重新再从数据库拿数据。
# only
res = models.Book.objects.all()
for i in res:
print(res.get('title'))
# defer
res = models.Book.objects.defer('title')
for s in res:
print(res.price)
【3】select_related与prefetch_related
- select_related和prefetch_related是django中用于优化数据库查询的两种方法
- select_related内部对应的是数据库的联表查询,它的参数只能填一对一或者一对多的外键字段
- prefetch_related内部对应的是数据库的子查询,它的参数可以填所有关系的外键字段
- 用这两个方法创建出来的对象,封装好了本表与外键关联的表的所有数据,通过他们查询数据将不再需要经过数据库,从而优化了查询效率
# prefetch_related
res = models.Book.objects.prefetch_related('publish')
for i in res:
print(i.publish.name)
# select_related
res = models.Book.objects.select_related('publish') # INNER JOIN
for i in res:
print(i.publish.name)
【十一】(数据库字段设计常见)
【1】引入
-
在Django中,字段属性
choices
允许您为模型字段指定一组预定义选项。这通常用于限制字段的值,使其仅限于预定义的一组选项之一。 -
choices
属性通常与CharField
或IntegerField
等字段一起使用,但它也可以与其他字段类型一起使用 -
以一张用户表为例,它有名称,年龄,性别,生育情况这些字段
-
其中,性别和生育情况的对应数据是很有限的,这时候就可以使用choices参数
【2】数据准备
class User(models.Model):
name = models.CharField(max_length=15)
age = models.IntegerField()
gender_choices = (
(1, 'male'),
(2, 'female'),
(3, 'other')
)
birth_choices = (
('1', '是'),
('2', '否'),
('3', '未知'),
)
gender = models.IntegerField(choices=gender_choices)
birth = models.CharField(choices=birth_choices, max_length=15)
【3】使用
- 对于定义了choices属性的字段来说,可以通过
obj.get_字段名_display
- 如果对应字段的值在自定义的choices内,就可以拿到对应的值
- 如果不在自定义的范围内,就会拿到它原本的值
# 1.插入数据,其中gender和birth的参数在预定义选项之内,并且查询
models.User.objects.create(name='green', age=18, gender=1, birth='1')
models.User.objects.create(name='green', age=18, gender=1, birth='1')
obj = models.User.objects.filter(pk=1).first()
print(obj.gender) # 1
print(obj.birth) # 2
print(obj.get_gender_display()) # male
print(obj.get_birth_display()) # 否
# 2.插入数据,其中gender和birth的参数不在预定义选项之内,并且查询
models.User.objects.create(name='green', age=18, gender=5, birth='5')
obj = models.User.objects.filter(pk=2).first()
print(obj.gender) # 5
print(obj.birth) # 5
print(obj.get_gender_display()) # 5
print(obj.get_birth_display()) # 5
【十二】MTV和MVC模型
- MTV(Model-Template-View)和MVC(Model-View-Controller)都是用于设计和组织Web应用程序的模式。
- 它们都旨在将应用程序的不同组成部分分离开来,以便更好地管理代码、提高可维护性和重用性。
- django框架就是MVC模型
【1】MVC模型
- Model(模型):负责处理应用程序的数据逻辑。它通常包含与数据库交互的代码,以及数据的验证和处理。
- View(视图):负责用户界面的呈现。它将数据从模型中获取,并将其呈现给用户。视图通常是用户与之交互的界面元素,如HTML页面、模板等。
- Controller(控制器):负责协调模型和视图之间的交互。它接收用户的输入,处理请求,并相应地更新模型和视图。控制器通常包含应用程序的业务逻辑。
【2】MTV模型
- Model(模型):与MVC中的模型类似,负责处理应用程序的数据逻辑,包括数据的存储、验证和处理。
- Template(模板):与MVC中的视图类似,负责用户界面的呈现。模板将数据从模型中获取,并将其呈现给用户。模板通常包含HTML和模板语言代码。
- View(视图):与MVC中的控制器类似,负责协调模型和模板之间的交互。它接收用户的请求,处理请求,并相应地更新模型和模板。视图通常包含应用程序的业务逻辑。
【十三】创建多对多外键关系的三种方法
- 在django中创建多对多外键的方法有三种,可以把他们总结为全自动,半自动,和纯手动
- 最推荐的是半自动,因为它支持orm的正向查询和反向查询,第三张表还有很强的拓展性
【1】全自动
- 通过django强大的orm功能,自动创建第三张表
- 虽然它很方便,但是第三章表的字段我们完全没法自定义,所以会导致第三章表的拓展性很差
class Book(models.Model):
name = models.CharField(max_length=32)
# 全自动
authors = models.ManyToManyField(to='Author')
class Author(models.Model):
name = models.CharField(max_length=32)
【2】半自动(推荐)
- 半自动也是需要我们自己去定义第三张表,虽然要多写代码,但是也能自定义关系表,有很强的拓展性
- 同时它也需要用ManyToManyField定义外键,里面的还要多两个属性through和through_fields
- 用半自动的方法,不能再使用add,remove,set,remove等方法,但是可以直接去操作第三张表,也是挺方便的
class Book(models.Model):
name = models.CharField(max_length=32)
# 全自动
# through_fields : 当前表是谁,第一个参数就是谁
# 判断的本质:通过第三张表查询对应的表,需要用到哪个字段就把哪个字段放在前面
authors = models.ManyToManyField(to='Author', through='BookAuthor', through_fields=('book', 'author'))
class Author(models.Model):
name = models.CharField(max_length=32)
class BookAuthor(models.Model):
book_id = models.ForeignKey(to='Book')
author_id = models.ForeignKey(to='Author')
【3】纯手动
- 这种方法一般不推荐,因为它不仅代码量大,还不能使用orm提供的快捷方便的正反向查询语法
class Book(models.Model):
name = models.CharField(max_length=32)
class Author(models.Model):
name = models.CharField(max_length=32)
class BookAuthor(models.Model):
book_id = models.ForeignKey(to='Book')
author_id = models.ForeignKey(to='Author')