48、django工程(model)
48.1、数据库配置:
1、django默认支持sqlite,mysql, oracle,postgresql数据库:
(1)sqlite:
django默认使用sqlite的数据库,默认自带sqlite的数据库驱动 , 引擎名称为 django.db.backends.sqlite3。
(2)mysql:
引擎名称:django.db.backends.mysql。
2、mysql 驱动程序:
MySQLdb(mysql python)
mysqlclient
MySQL
PyMySQL(纯python的mysql驱动程序)
3、修改Django项目使用的数据库,在settings中进行设置:
(1)默认设置使用Sqlite数据库:
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.sqlite3',
'NAME': os.path.join(BASE_DIR, 'db.sqlite3'),
}
}
(2)更改为mysql数据库:
1)修改代码:
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.mysql',
'NAME': 'book',
# 你的数据库名称
'USER': 'root',
# 你的数据库用户名
'PASSWORD': '123456',
# 你的数据库密码
'HOST': '127.0.0.1',
# 你的数据库主机,留空默认为localhost
'PORT': '3306',
# 你的数据库端口
}
}
2)注意问题:
A、
NAME即数据库的名字,在mysql连接前该数据库必须已经创建,而上面的sqlite数据库下的db.sqlite3则是项目自动创建。
USER和PASSWORD分别是数据库的用户名和密码。设置完后,在启动我们的Django项目前,我们需要激活我们的mysql。
启动项目会报错,no module named MySQLdb,这是因为django默认你导入的驱动是MySQLdb,可是MySQLdb对于
python3有很大问题,所以我们需要的驱动是PyMySQL,所以我们只需要找到项目名文件下的__init__,在里面写入:
import pymysql
pymysql.install_as_MySQLdb()
B、
django2.2 LTS不支持pyMySQL。
报错:django.core.exceptions.ImproperlyConfigured: mysqlclient 1.3.13 or newer is required; you have 0.9.3.
解决办法:
第一步:
找到 C:\Program Files (x86)\Python3.7\lib\site-packages\django-2.2.9-py3.7.egg\django\db\backends\mysql\base.py 文件,
注释掉36行,加pass语句,这个是Django对MySQLdb版本的限制,我们使用的是PyMySQL,所以不用管它。
if version < (1, 3, 13):
#raise ImproperlyConfigured('mysqlclient 1.3.13 or newer is required; you have %s.' % Database.__version__)
pass
第二步:
找到 C:\Program Files (x86)\Python3.7\lib\site-packages\django-2.2.9-py3.7.egg\django\db\backends\mysql\operations.py
文件的146行,修改decode为encode。
if query is not None:
query = query.encode(errors='replace')
return query
提示:因为python对其安装路径下的所有文件有保护功能,导致文件无法修改,可以先把相应文件剪切到桌面修改后再拷贝回原目录。
48.2、ORM 对象关系映射:
1、说明:
(1)ORM 用于实现面向对象编程语言里不同类型系统的数据之间的转换,换言之,就是用面向对象的方式去操作数据库的
创建表以及增删改查等操作。
2、优点:
(1)ORM使得我们的通用数据库交互变得简单易行,而且完全不用考虑该死的SQL语句,快速开发,由此而来。
(2)可以避免一些新手程序猿写sql语句带来的性能问题,比如新手可能会用 select * from <表名>,这样会因为多了一个匹
配动作而影响效率的。
3、缺点:
(1)性能有所牺牲,不过现在的各种ORM框架都在尝试各种方法,比如缓存,延迟加载等来减轻这个问题,效果很显著。
(2)对于个别复杂查询,ORM仍然力不从心,为了解决这个问题,ORM一般也支持写raw sql。
48.3、ORM模型学习:
1、说明:
(1)学习Django ORM语法,为了更好的理解,我们来做一个基本的 书籍/作者/出版商 数据库结构。
(2)模型常用的字段类型参数:
1)models.AutoField:
自增列 = int(11),如果没有的话,默认会生成一个名称为 id 的列,如果要显示的自定义一个自增列,
必须将给列设置为主键 primary_key=True。
2)models.CharField:
字符串字段,必须 max_length 参数。
3)models.BooleanField:
布尔类型=tinyint(1),不能为空,Blank=True。
4)models.ComaSeparatedIntegerField:
用逗号分割的数字=varchar,继承CharField,所以必须 max_lenght 参数。
5)models.DateField:
日期类型 date,对于参数,auto_now = True 则每次更新都会更新这个时间,auto_now_add 则只是
第一次创建添加,之后的更新不再改变。
6)models.DateTimeField:
日期类型 datetime,同DateField的参数。
7)models.Decimal:
十进制小数类型 = decimal,必须指定整数位 max_digits 和小数位 decimal_places,max_digits 总位
数(不包括小数点和符号),decimal_places 小数位数。
举例来说, 要保存最大值为 999 (小数点后保存2位),你要这样定义字段,models.Decimal(max_digits=5, decimal_places=2)。
8)models.EmailField:
字符串类型(正则表达式邮箱) = varchar,对字符串进行正则表达式。
9)models.FloatField:
浮点类型 = double
10)models.IntegerField:
整形
11)models.BigIntegerField:
长整形
integer_field_ranges = {
'SmallIntegerField': (-32768, 32767),
'IntegerField': (-2147483648, 2147483647),
'BigIntegerField': (-9223372036854775808, 9223372036854775807),
'PositiveSmallIntegerField': (0, 32767),
'PositiveIntegerField': (0, 2147483647),
}
12)models.IPAddressField:
字符串类型(ip4正则表达式)
13)models.GenericIPAddressField:
字符串类型(ip4和ip6是可选的),参数protocol可以是 both、ipv4、ipv6。
验证时,会根据设置报错。
14)models.NullBooleanField:
允许为空的布尔类型。
15)models.PositiveIntegerField:
正Integer。
16)models.PositiveSmallIntegerField:
正smallInteger。
17)models.SlugField:
减号、下划线、字母、数字。
18)models.SmallIntegerField:
数字,数据库中的字段有 tinyint、smallint、int、bigint。
19)models.TextField:
字符串=longtext。
20)models.TimeField:
时间 HH:MM[:ss[.uuuuuu]]。
21)models.URLField:
字符串,地址正则表达式。
22)models.BinaryField:
二进制。
23)models.ImageField:
图片。
24)models.FilePathField
文件。
(3)Field重要参数:
1)null=True/False:数据库中字段是否可以为空。
2)blank=True/False:django的 Admin 中添加数据时是否可允许空值。
3)default:设定缺省值。
4)editable=True:如果为假,admin模式下将不能改写。缺省为真。
5)primary_key:设置主键,如果没有设置django创建表时会自动加上:
id = models.AutoField('ID', primary_key=True)
primary_key=True implies blank=False, null=False and unique=True. Only one
primary key is allowed on an object.
6)unique=True:数据唯一。
7)verbose_name:Admin中字段的显示名称。
8)validator_list=[]:有效性检查,非有效产生 django.core.validators.ValidationError 错误。
9)db_column|name:数据库中的字段名称。
10)choices:一个用来选择值的 2 维元组。第一个值是实际存储的值,第二个用来方便进行选择。
例如:
sex = models.BooleanField(max_length=1, choices=((0, '男'),(1, '女'),))
SEX_CHOICES = (('F','Female'),('M','Male'),)
gender = models.CharField(max_length=2,choices = SEX_CHOICES)
11)max_length:字段的字符长度。
12)db_index=True:数据库索引。
(4)书籍模型:
作者 书籍 出版商
多 多 一
一本书可能会有多个作者,一个作者也可以写多本书,所以作者和书籍的关系就是多对多的关联关系(many-to-many)。
一本书只应该由一个出版商出版,一个出版社可以出多本书,所以出版商和书籍是一对多关联关系(one-to-many),也被称作外键。
(5)模型分析:
1)每个数据模型都是 django.db.models.Model 的子类,它的父类Model包含了所有必要的和数据库交互的方法。并提供了
一个简介漂亮的定义数据库字段的语法。
2)每个模型相当于单个数据库表(多对多关系例外,会多生成一张关系表),每个属性也是这个表中的字段。属性名就是字段
名,它的类型(例如CharField)相当于数据库的字段类型(例如varchar)。
3)模型之间的三种关系:一对一,一对多,多对多:
一对一(OneToOneField):实质就是在主外键的关系基础上,给外键加了一个UNIQUE=True的属性。
一对多(ForeignKey):就是主外键关系。
多对多(ManyToManyField):自动创建第三张表(当然我们也可以自己创建第三张表:两个foreign key)。
2、在app01下的migration下的models.py中创建书籍模型类:
from django.db import models
# 出版社表
class Publish(models.Model):
# 自动在数据库的app01_publish表中创建字段为 id 的主键且从1自增
name = models.CharField(max_length=32, verbose_name="名称")
# 在数据库的app01_publish表中创建字符长度为32的name字段,详细名称为“名称”。
# 默认不允许为 null、可重复,自定义设置方法为 unique=True/False, null=True/False
city = models.CharField("城市", max_length=32)
# 在数据库的app01_publish表中创建字符长度为32的city字段,详细名称为“城市”。
# 默认不允许为 null、可重复(对除主键外的所有定义字段适用)。
def __str__(self):
return self.name
# 将输出的对象以指定属性的字符串形式进行返回。
# 书籍表
class Book(models.Model):
# 自动在数据库的app01_book表中创建字段为 id 的主键且从1自增
name = models.CharField(max_length=20)
price = models.IntegerField()
pub_date = models.DateField()
pub = models.ForeignKey("Publish", on_delete=models.CASCADE)
# 因为出版商和书籍是一对多的关联关系,这里创建的 pub 是 app01_publish 表的外键,
# 是一个对象,代表的是 app01_publish 表中的一行数据。
# 而在数据库的 app01_publish 表中存的是 pub_id 字段。
aut = models.ManyToManyField("Author")
# 因为作者和书籍是多对多的关联关系,这里创建的 aut 是一个对象,代表的是 app01_author
# 表中的多行数据,django 会自动帮我们创建一张名为 app01_book_aut 的中间表,中间表存在的字段有
# 主键 id、app01_book 表的外键字段 book_id、app01_author 表的外键字段 author_id。
# 在 app01_book 表中不会创建 aut 字段。该声明也可以放到 Author 类中。
def __str__(self):
return self.name
# 作者表
class Author(models.Model):
# 自动在数据库的app01_author表中创建字段为 id 的主键且从1自增
name = models.CharField(max_length=32)
age = models.IntegerField()
# sex = models.CharField(max_length=32, default=None)
# 这里的 default = "男" 代表的是为已存在且有数据的表增加字段,
# 同步数据库时新字段填的值,不能为 null,因为字段默认不能为 null。
def __str__(self):
return self.name
# 补充1:可以自定义多对多中间表(不推荐)
# class Book_Author(models.Model):
# book=models.ForeignKey("Book", on_delete=models.CASCADE)
# author=models.ForeignKey("Author", on_delete=models.CASCADE)
# 补充2:django orm的外键约束:
# on_delete = models.CASCADE
# 删除关联数据,与之关联也删除。
# on_delete = models.DO_NOTHING
# 删除关联数据,引发错误IntegrityError,是数据库操作后库级别抛出的。
# on_delete = models.PROTECT
# 删除关联数据,引发错误ProtectedError,是受保护的,由django级别抛出的。
# on_delete = models.SET_NULL
# 删除关联数据,与之关联的值设置为null,前提FK字段需要设置为可空。
# on_delete = models.SET_DEFAULT
# 删除关联数据,与之关联的值设置为默认值,前提FK字段需要设置默认值。
# on_delete = models.SET
# 删除关联数据。
# a.与之关联的值设置为指定值,models.SET(值)。
# b.与之关联的值设置为可执行对象的返回值,models.SET(可执行对象)。
3、同步数据库:
D:\mysite>python manage.py makemigrations
D:\mysite>python manage.py migrate
4、使用pycharm连接mysql数据库:
(1)
(2)
(3)
(4)
48.4、通过 ORM 操作表:
0、说明:
(1)在 views.py 文件中引入类 from app01.models import *
(2)表中查询测试数据:
1)app01_author 表:
2)app01_book 表:
3)app01_book_aut 表:
4)app01_publish 表:
1、单表操作(对app01_author表进行操作):
(1)增加记录:
Author.objects.create(name='老舍',age=56)
(2)修改记录:
Author.objects.filter(name='老舍').update(age=89)
(3)删除记录:
Author.objects.filter(name='老舍').delete()
(4)查询记录:
1)
author_list = Author.objects.filter(id=5)
print(author_list)
# <QuerySet [<Author: 鲁迅>]>
2)
author_list = Author.objects.all()
print(author_list)
# < QuerySet[ < Author: 老舍 >, < Author: 鲁迅 >, < Author: 高尔基 >, < Author: 雨果 >] >
3)查询除什么条件之外的数据:
author_list = Author.objects.exclude(name="雨果").values("id", "age")
print(author_list)
# <QuerySet [{'id': 4, 'age': 45}, {'id': 5, 'age': 46}, {'id': 6, 'age': 50}]>
4)切片:
author_list = Author.objects.all()[::2]
print(author_list)
# [<Author: 老舍>, <Author: 高尔基>]
5)倒叙:
author_list = Author.objects.all()[::-1]
print(author_list)
# [<Author: 雨果>, <Author: 高尔基>, <Author: 鲁迅>, <Author: 老舍>]
6)first、last、get 取到的是一个实例对象,并非一个QuerySet的集合对象:
A、
author_list = Author.objects.first()
print(author_list)
# 老舍
B、
author_list = Author.objects.last()
print(author_list)
# 雨果
C、get 只能取出一条记录时才不报错:
author_list = Author.objects.get(id=5)
print(author_list)
# 鲁迅
7)values 列表字典(可迭代):
author_list = Author.objects.filter(name="鲁迅").values("id","age")
print(author_list)
# <QuerySet [{'id': 5, 'age': 46}]>
8)values_list 列表元组(不可迭代):
author_list = Author.objects.filter(name="鲁迅").values_list("id","age")
print(author_list)
# <QuerySet [(5, 46)]>
9)排重:
author_list = Author.objects.all().values("name").distinct()
print(author_list)
# <QuerySet [{'name': '老舍'}, {'name': '鲁迅'}, {'name': '高尔基'}, {'name': '雨果'}]>
10)统计:
author_count = Author.objects.all().values("name").distinct().count()
print(author_count)
# 4
(5)模糊查询,双下划线__:
1)
author_list = Author.objects.filter(name__contains='老').values_list("id","age")
print(author_list)
# <QuerySet [(4, 45)]>
2)
author_list = Author.objects.filter(id__gt=2).values('id',"name")
print(author_list)
< QuerySet[{'id': 4, 'name': '老舍'}, {'id': 5, 'name': '鲁迅'}, {'id': 6, 'name': '高尔基'}, {'id': 7, 'name': '雨果'}] >
2、多表操作(一对多,对app01_publish、app01_book表进行操作):
(1)添加记录:
1)直接添加方式(linux运维这本书的出版社是上海出版社):
Book.objects.create(name="linux运维", price=77, pub_date="2017-12-12", pub_id=2)
2)通过对象方式添加(GO这本书的出版社是广东出版社):
pub_obj = Publish.objects.filter(id=3)[0]
Book.objects.create(name="GO", price=23, pub_date="2017-05-12", pub=pub_obj)
(2)删除记录及修改记录:
和单表操作方式相同。注意:如果删除的是主表数据,子表关联的数据也会被删除(级联删除);如果删除的是子表,
主表存在和子表关联的数据,则不允许子表的数据被删除。
(3)通过对象查询:
1)正向查询 GO 这本书出版社的名字:
book_obj = Book.objects.filter(name="GO")[0]
pub_obj = book_obj.pub
print(pub_obj.name)
# 广东出版社
2)反向查询 上海出版社 出版过的书籍与价格:
pub_obj = Publish.objects.filter(name="上海出版社")[0]
print(pub_obj.book_set.all().values("name", "price"))
# <QuerySet [{'name': 'linux运维', 'price': 77}]>
(4)查询记录(filter values 双下划线__):
1)上海出版社 出版过的书籍与价格:
ret = Book.objects.filter(pub__name="上海出版社").values("name", "price")
print(ret)
# <QuerySet [{'name': 'linux运维', 'price': 77}]>
2)GO 这本书出版社的名字:
ret2 = Publish.objects.filter(book__name="GO").values("name")
print(ret2)
# <QuerySet [{'name': '广东出版社'}]>
3)2017年5月到12月出版过书的出版社的名字:
ret5=Publish.objects.filter(book__pub_date__gt='2017-05-1',book__pub_date__lt='2017-12-31').values("name")
print(ret5)
# <QuerySet [{'name': '上海出版社'}, {'name': '广东出版社'}]>
ret6 = Book.objects.filter(pub_date__gt="2017-05-01", pub_date__lt="2017-12-31").values("pub__name")
print(ret6)
# <QuerySet [{'pub__name': '上海出版社'}, {'pub__name': '广东出版社'}]>
3、多表操作(多对多,对app01_book、app01_author、app01_book_aut 表进行操作):
(1)对象操作,正向,通过书指定作者(增、删、改、清空,查):
obj = Book.objects.filter(id=1).first()
#1 linux运维
1)把指定的model对象添加到关联对象集中,已存在不会增加,多加的会新增:
obj.aut.add(*[4,5,6])
2)从关联对象集中移除执行的model对象:
obj.aut.remove(*[4,5])
3)更新model对象的关联对象,已存在不会更新,多加的会新增:
obj.aut.set([4, 5, 6, 7])
4)从关联对象集中移除一切对象:
obj.aut.clear()
5)把 linux运维 书的所有作者列举出来:
ret = obj.aut.all()
print(ret)
# < QuerySet[ < Author: 老舍 >, < Author: 鲁迅 >, < Author: 高尔基 >, < Author: 雨果 >] >
(2)对象操作,反向,通过作者指定书(增、删、改、清空,查):
obj=Author.objects.filter(id=5).first()
# 5 鲁迅
1)把指定的model对象添加到关联对象集中,已存在不会增加,多加的会新增:
obj.book_set.add(*[1,2])
2)从关联对象集中移除执行的model对象:
obj.book_set.remove(*[1,2])
3)更新model对象的关联对象,已存在不会更新,多加的会新增:
obj.book_set.set([1,2])
4)从关联对象集中移除一切对象:
obj.book_set.clear()
5)鲁迅写了哪几本书:
ret = obj.book_set.all()
print(ret)
# <QuerySet [<Book: linux运维>, <Book: GO>]>
(3)查询操作,双下划__:
1)把 linux运维 书的所有作者列举出来:
obj=Author.objects.filter(book__name='linux运维').values('name')
print(obj)
# <QuerySet [{'name': '老舍'}, {'name': '鲁迅'}, {'name': '高尔基'}, {'name': '雨果'}]>
obj=Book.objects.filter(name='linux运维').values("aut__name")
print(obj)
# <QuerySet [{'aut__name': '老舍'}, {'aut__name': '鲁迅'}, {'aut__name': '高尔基'}, {'aut__name': '雨果'}]>
2)鲁迅写了哪几本书:
obj=Book.objects.filter(aut__name="鲁迅").values("name")
print(obj)
# <QuerySet [{'name': 'linux运维'}, {'name': 'GO'}]>
obj=Author.objects.filter(name='鲁迅').values("book__name")
print(obj)
# <QuerySet [{'book__name': 'linux运维'}, {'book__name': 'GO'}]>
4、F查询和Q查询:
(1)说明:
仅仅靠单一的关键字参数查询已经很难满足查询要求。此时Django为我们提供了F和Q查询。
(2)F查询(使用查询条件的值,专门取对象中某列值的操作):
from django.db.models import F
# 在views.py中导入 django F 查询模块
1)将app01_book表中书的价格都增加20元:
Book.objects.all().update(price=F('price')+20)
(3)Q查询(构建搜索条件"与、或、非"):
from django.db.models import Q
# 在views.py中导入 django Q 查询模块
1)Q对象(django.db.models.Q)可以对关键字参数进行封装,从而更好地应用多个查询:
在 app01_book 表中查询书名以"l"开头的所有书:
obj=Book.objects.filter(Q(name__startswith='l')).values("name")
print(obj)
# <QuerySet [{'name': 'linux运维'}]>
2)可以组合使用 &,| 操作符,当一个操作符是用于两个Q的对象,它产生一个新的Q对象:
在 app01_book 表中查询书名以"l"开头或以"O"结尾的所有书:
obj=Book.objects.filter(Q(name__startswith='l') | Q(name__endswith='O')).values("name")
print(obj)
# <QuerySet [{'name': 'linux运维'}, {'name': 'GO'}]>
3)Q对象可以用"~"操作符放在前面表示否定,也可允许否定与不否定形式的组合:
在 app01_book 表中查询书名中包含"l"且不以"O"结尾的所有书:
obj=Book.objects.filter(Q(name__contains='l') & ~Q(name__endswith='O')).values("name")
print(obj)
# <QuerySet [{'name': 'linux运维'}]>
4)应用范围:
每个采用关键字参数(例如filter()、exclude()、get())的查找函数也都可以传递一个或多个Q对象作
为位置(未命名)参数,如果为查找函数提供多个Q对象参数,则这些参数将使用"与"连在一起。 例
如:
在 app01_book 表中查询书名以"l"开头且出版时间为'2017-12-12'或'2017-05-12'的所有书:
obj=Book.objects.filter(
Q(name__startswith='l'),
Q(pub_date=datetime.date(2017,12,12)) | Q(pub_date=datetime.date(2017,5,12))
).values("name")
print(obj)
# <QuerySet [{'name': 'linux运维'}]>
# SQL语句:
# SELECT name FROM app01_book WHERE name LIKE 'l%' AND (pub_date = '2017-12-12' OR pub_date = '2017-05-12');
# import datetime
# datetime.date(2017,12,12) = 2017-12-12
5)Q对象可以与关键字参数查询一起使用,不过一定要把Q对象放在关键字参数查询的前面:
在 app01_book 表中查询出版时间为'2017-12-12'或'2017-05-12'且书名以"l"开头的所有书:
obj=Book.objects.filter(
Q(pub_date=datetime.date(2017,12,12)) | Q(pub_date=datetime.date(2017,5,12)),
name__startswith='l').values('name')
print(obj)
# <QuerySet [<Book: linux运维>]>
# SQL语句:
# SELECT name FROM app01_book WHERE (pub_date = '2017-12-12' OR pub_date = '2017-05-12') AND name LIKE 'l%';
5、聚合(aggregate)查询和分组(annotate)查询:
(0)在views.py中导入 django Max、Min、Sum、Avg 模块:
from django.db.models import Max,Min,Sum,Avg
(1)aggregate(*args,**kwargs):
通过对QuerySet进行计算,返回一个聚合值的字典,aggregate() 中每一个参数都指定一个包含在字典中的返回值,即在查询集上
生成聚合。
1)在 app01_book 表中查询所有图书价格的最大值、最小值、总和、平均值:
obj=Book.objects.aggregate(Max('price'), Min('price'), Sum('price'), Avg('price'))
print(obj)
# {'price__max': 77, 'price__min': 23, 'price__sum': 100, 'price__avg': 50.0}
# SQL:SELECT MAX(price) AS `price__max`, MIN(price) AS `price__min`, SUM(price) AS `price__sum`, AVG(price) AS `price__avg` FROM app01_book;
(2)annotate(*args,**kwargs):
可以通过计算查询结果中每一个对象所关联的对象集合,从而得出总计值(也可以是平均值或总和),即为查询集的每一项生成聚合。
1)查询各个作者的出书总价格:
obj=Book.objects.values("aut__name").annotate(Sum('price'))
print(obj)
# <QuerySet [{'aut__name': '老舍', 'price__sum': 77}, {'aut__name': '鲁迅', 'price__sum': 100}, {'aut__name': '高尔基', 'price__sum': 77}, {'aut__name': '雨果', 'price__sum': 77}]>
2)查询各个出版社最便宜的书价格是多少:
obj=Book.objects.values('pub__name').annotate(Min('price'))
print(obj)
# <QuerySet [{'pub__name': '上海出版社', 'price__min': 77}, {'pub__name': '广东出版社', 'price__min': 23}]>
# SQL:SELECT publish.name, MIN(book.price) AS `price__min` FROM app01_book AS book INNER JOIN app01_publish AS publish ON book.pub_id = publish.id GROUP BY publish.name;
obj=Publish.objects.values("name").annotate(Min("book__price"))
print(obj)
# <QuerySet [{'name': '上海出版社', 'book__price__min': 77}, {'name': '广东出版社', 'book__price__min': 23}, {'name': '北京出版社', 'book__price__min': None},
# {'name': '南京出版社', 'book__price__min': None}, {'name': '邮电出版社', 'book__price__min': None}]>
6、ORM 操作表小结:
(1)正向和反向查询(一):
只有在单个对象时,在一对多表关系中才有正向和反向查询,在多对多表关系中才有正向和反向查询及正向和反向往中间表新增数据的概念。
(2)双下划线(__)查询(多):
1)求谁写谁,values代表的是"select <字段名> from"sql语句中的<字段名>,filter代表的是sql语句中的where语句(
filter 可以填写多个过滤条件,用逗号","进行分割,逗号代表"sql"语句中的"and",即"与"的意思)。
2)在多表查询一对多时,filter括号中填写与当前表相对应的表,如果相对应的表的外键在当前表中就填写外键名。
3)在多表查询多对多时,filter括号中填写与当前表相对应的表,如果相对应的表的外键在当前表中就填写外键名。
(3)QuerySet 特点:
1)ORM语句只有在调用的时候才会执行,如果多次调用同一条orm语句会调用第一次执行的缓存,有利于提高软件的性能
如果在下一次调用前修改了数据,需要重新写orm查询语句,不然查询的还是旧的数据。
2)ret.iterator():迭代器用于查询,迭代器对象只能遍历一次,有利于节省内存空间,但是不能重复利用查询缓存了,用于大
数据量的查询,小数据量的查询不推荐使用迭代器。
3)if ret.exists():判断查询结果中是否中有数据,不会将数据库中的数据全部查询出来,有利于节省内存空间,提升软件性能。
4)QuerySet 可以迭代、切片。
(4)对于每次创建一个对象,想显示对应的raw sql,需要在settings加上日志记录部分:
LOGGING = {
'version': 1,
'disable_existing_loggers': False,
'handlers': {
'console':{
'level':'DEBUG',
'class':'logging.StreamHandler',
},
},
'loggers': {
'django.db.backends': {
'handlers': ['console'],
'propagate': True,
'level':'DEBUG',
},
}
}
(5)对象说明:
1)orm 对象操作:
(.filter()、.all()、.exclude() => where)、(.delete()、.update() = ddl):获取多个对象、操作的是多个对象。
.get() => where:获取的是单个对象(单行数据),有且只有一个对象,如果数据表中有多个对象会报错。
.values() => 显示的字段:获取的是一个列表字典,可迭代。
.values_list() => 显示的字段:获取的是一个列表元组,不可迭代。
.distinct():对查询结果去重,放在.values()或.values_list()后面。
2)一对多表关系:
类代表数据库表。
类的对象代指数据库的一行记录。
FK字段代指关联表中的一行数据(类的对象)。
3)多对多表关系:
类代表数据库表。
类的对象代指数据库的一行记录。
FK字段代指关联表中的多行数据(类的对象)。
(6)查询相关API:
1)filter(**kwargs):
它包含了与所给筛选条件相匹配的对象。
2)all():
查询所有结果。
3)get(**kwargs):
返回与所给筛选条件相匹配的对象,返回结果有且只有一个,如果符合筛选条件的对象超过一个或者没有都会抛出错误。
下面的方法都是对查询的结果再进行处理:比如 objects.filter().values()。
4)values(*field):
返回一个ValueQuerySet——一个特殊的QuerySet,运行后得到的并不是一系列 model的实例化对象,而是一个可迭
代的字典序列。
5)exclude(**kwargs):
它包含了与所给筛选条件不匹配的对象。
6)order_by(*field):
对查询结果排序。
7)reverse():
对查询结果反向排序。
8)distinct():
从返回结果中剔除重复纪录。
9)values_list(*field):
它与values()非常相似,它返回的是一个元组序列,values返回的是一个字典序列。
10)count():
返回数据库中匹配查询(QuerySet)的对象数量。
11)first():
返回第一条记录。
12)last():
返回最后一条记录。
13)exists():
如果QuerySet包含数据,就返回True,否则返回False。
48.5、admin的配置:
1、说明:
admin是django强大功能之一,它能够从数据库中读取数据,呈现在页面中,进行管理。默认情况下,它的功能已经非常强大,如果你不需要复杂的功能,
它已经够用,但是有时候,一些特殊的功能还需要定制,比如搜索功能等。
如果你觉得英文界面不好用,可以在setting.py 文件中修改以下选项:
默认英文:LANGUAGE_CODE = 'en-us'
修改为中文:LANGUAGE_CODE = 'zh-hans'
2、认识ModelAdmin:
管理界面的定制类,如需扩展特定的model界面需从该类继承。
3、注册Book类到admin的方法:
admin.site.register(Book,BookAdmin)
4、常用的设置技巧:
(1)list_display:指定要显示的字段。
(2)search_fields:指定搜索的字段。
(3)list_filter:指定列表过滤器。
(4)ordering:指定排序字段。
5、示例:
(1)在 app01.migrations.admin.py中添加如下内容:
from django.contrib import admin
from app01.models import *
# Register your models here.
# 样式定制类
# @admin.register(Book) #----->单给某个表加一个定制
class BookAdmin(admin.ModelAdmin):
list_display = ("name","price","pub_date","pub")
search_fields = ("name","pub")
list_filter = ("pub",)
ordering = ("price",)
# 在admin中注册表和样式定制类
admin.site.register(Book,BookAdmin)
admin.site.register(Publish)
admin.site.register(Author)
(2)界面:
1)
2)