python学习:Django的ORM(Model)(3)
Django的ORM
ORM
ORM:对象关系映射,是通过使用描述对象和数据库之间映射的元数据,将面向对象语言程序中的对象自动持久化到关系数据库中。
表与表直接关系:一对一,一对多,多对多。
Python的ORM,Python的类操作数据库表,类对应数据库中的表,类对象就是表中一条记录。
Django默认使用sqlite数据库。
setting.py中可以看到:
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.sqlite3',
'NAME': os.path.join(BASE_DIR, 'db.sqlite3'),
}
}
Mysql驱动
Mysqldb(python2使用)
Pymysql(python3使用)
使用mysql需要安装对应驱动。
Django创建数据库表
在models.py中编写python类,类继承models.Model类。
示例:
class Book(models.Model):
name = models.CharField(max_length=4);
price = models.FloatField();
pub_date=models.DateField();
count = models.IntegerField();

终端执行:python manage.py makemigrations
生成migrations文件夹中文件。
然后执行:python manage.py migrate
在数据库中生成对应表。
可以在migrations文件夹中看到0001_initial.py文件,可以看到我们book类的属性,如果没有设置主键,自动添加一个id主键。
operations = [
migrations.CreateModel(
name='Book',
fields=[
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('name', models.CharField(max_length=4)),
('price', models.FloatField()),
('pub_date', models.DateField()),
('count', models.IntegerField()),
],
),
]
我们使用的是默认数据库,sqlite3。可以使用SqliteStudio打开db.salite3文件,可以看到我们创建的表和Django自动生成的其他数据表。表名一般是你的AppName+类名。


使用Mysql数据库
修改setting.py文件:
# DATABASES = {
# 'default': {
# 'ENGINE': 'django.db.backends.sqlite3',
# 'NAME': os.path.join(BASE_DIR, 'db.sqlite3'),
# }
# }
#使用mysql数据库
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.mysql',
#数据库名
'NAME': 'python_test',
#用户名
'USER':'root',
#密码
'PASSWORD':'tlj123456',
#主机,默认localhost
'HOST':'',
#端口
'PORT':'3306'
}
}

在项目文件夹,_init_.py写入语句,声明使用mysql引擎,因为默认项目使用sqlite3
import pymysql
pymysql.install_as_MySQLdb()
然后执行python manage.py makemigrations和python manage.py migrate创建数据库表。

可以看到我们创建的表helloapp_book。
Django数据库增删改查
新增数据:
通过新建类对象,调用对象的save方法。
#方式1
#新建对象,一个对象对应一条记录
book = Book(name="数据库基础",price=10.33,pub_date="2017-2-22",count=20);
#保存记录到数据库
book.save();
使用类Book.objects.create()方法:
#方式2
Book.objects.create(name="python基础",price=22.33,pub_date="2019-2-22",count=50)
更新数据:
#方式1
#更新数据
Book.objects.filter(name="数据库基础").update(price="20.33")
#方式2
book = Book.objects.filter(name="数据库基础");
#book为querySet类型,数据集合
for b in book:
b.price=33.22;
b.save();
get方式获取的是单条记录,返回对应对象
#方式3
book = Book.objects.get(id=1);
book.price ="33.34";
book.save();
删除数据:
#查询出对应记录删除
Book.objects.filter(name="数据库基础").delete();
查询数据:
使用all()查询所有记录,返回querySet对象
#查询所有结果
book_list = Book.objects.all();
使用filter(),筛选指定条件,返回querySet对象
#查询符合条件结果
Book.objects.filter(name="python基础",count=50)
切片查询部分记录,返回querySet对象
#切片查询指定条数记录,正数正序,负数倒序
book_list = Book.objects.all()[::2];
获取第一条,最后一条记录,返回一个对应对象
#查询第一条,最后一条记录
book = Book.objects.first();
book = Book.objects.last();
get查询一条符合条件记录
#查询一条指定记录
book = Book.objects.get(id=1);
只查询出指定栏位values()
#查询出指定栏位,返回一个字典集合
result = Book.objects.filter().values("name","price")
# 查询出指定栏位,返回一个元组列表集合
result = Book.objects.filter().values_list("name", "price")
查询出不符合条件的记录exclude()
#查询出不符合条件的记录
book_list = Book.objects.exclude(name="python基础")
使用distinct()去除重复字段
#去除重复字段
book_list = Book.objects.all().values("name","price","count").distinct();
使用count()获取记录数量
#获取记录数量
count_num = Book.objects.all().count();
模糊查询:
使用语法:字段名_关键字
关键字:
lt 小于 ;
gt 大于;
contains 包含 ;
icontains 包含(不区分大小写);
in 在一个数组中;
range 在range值范围内;
startwith,endwith,istartwith,iendwith:以什么开始和结尾,是否区分大小写。
#模糊查询,lt 小于,gt 大于,contains 包含,icontains 包含(不区分大小写)
book_list = Book.objects.filter(name__contains="基础",price__lt=20)
创建一对多表外键关系,使用ForeignKeyField
示例:
# Create your models here.
class Book(models.Model):
name = models.CharField(max_length=20);
price = models.FloatField();
pub_date=models.DateField();
count = models.IntegerField();
# #默认创建时pub,变成pub_id,如果pub_id数据库表变成pub_id_id,一般不用这种。
#pub = models.ForeignKey('Publish',to_field='id', on_delete=models.CASCADE);
# #将整个对象作为外键(创建时自动将表主键作为外键)
publish = models.ForeignKey('Publish',on_delete=models.CASCADE)
class Publish(models.Model):
id = models.IntegerField(primary_key=True,auto_created=True);
name = models.CharField(max_length=20);
addr = models.CharField(max_length=30);
一对多添加数据
#一对多添加数据
#方式1,直接添加一条记录
book = Book(name="数据库基础",price=10.33,pub_date="2017-2-22",count=20,publish_id=1);
#保存记录到数据库
book.save();
#方式2,通过对象添加数据
publish = Publish.objects.filter(id = 1)[0];
Book.objects.create(name="c语言",price="22.3",pub_date="2012-02-12",count="22",publish=publish);
一对多连接查询
查询book的出版商
#方式1
#这种方式可以直接使用publish外键获取到Publish值
book = Book.objects.get(id = 2);
#book的外键pbulish是一个Publish类对象
print(book.publish);
#方式2
#使用外键关系id,分步查询
book = Book.objects.get(id=2);
publish = Publish.objects.get(id = book.publish_id);
return render(request,"books.html",locals());
查询出版商出版的书籍
#方式1,Book有publish类对象外键
publish = Publish.objects.get(name="新华出版社");
book = Book.objects.filter(publish=publish)
#方式2,类名_set,使用publish.book_set.all(),获取对应书籍信息
publish = Publish.objects.get(name="新华出版社");
#获取的是一个QuerySet,
print(publish.book_set.all())
book_list = publish.book_set.all()
#方式3,双下划线访问外键对象属性,要求:Book有publish类对象外键,使用__双下划线,访问类对象属性
#查找出版社出版书籍
book_list=Book.objects.filter(publish__name="新华出版社")
#查找对应书籍出版社
publish = Publish.objects.filter(book__name="c基础");
#同样查找对应书籍出版社,publish的类对象属性可以作为筛选列
ret = Book.objects.filter(name="c基础").values("publish__name")
一对多关系整理:
书籍和出版社的关系是一对多的关系,规定一本书只能对应一个出版社,而一个出版社可以出版多本书。Book书籍类和Publish出版社类,Book有个外键publish对应Publish出版社类(publish = models.ForeignKey('Publish',on_delete=models.CASCADE))。体现在数据库表中:Book表中有个栏位publish_id,外键约束对应Publish表的id栏位。
1、正向查询
通过Book表查询Publish表信息,就是查询书籍对应出版社信息,由于Book类有publish这个外键,直接可以连接操作publish表。可以通过对象获取,也可以通过‘__‘双下划线获取。这种叫做正向查询。
对象方式操作:
获取所有书籍:
book_list = Book.objects.all();
通过对象方式获取
循环获取所有书籍的出版社:
for book in book_list:
#book的名字
book.name
#book.publish是一个publish对象,.name获取publish名字
book.publish.name
通过”__”双下划线操作:
使用filter获取指定条件书籍:
book =Book.objects.filter(name = “python基础”,publish__name = “长江出版社”).first()
使用values限制查询列:
book = Book.objects.values(“name”,”publish__name”);
其中publish__name就是通过“__“双下划线访问外键对应表属性。
2、反向查询
通过Publish出版社表查询Book的信息,由于Publish中没有Book表的任何关联信息,Publish只是被动被Book表外键关联。通过Publish查询Book的信息,比如查询出版社出版的所有书籍,这种查询叫反向查询。
对象方式操作:
#获取出版社对象
publish = Publish.objects.filter(name = “长江出版社”).first();
#出版社名
print(publish.name)
#通过book_set获取到了所有书籍信息,book_set就相当于Book.objects
print(publish.book_set.all())
#在filter,values中使用
#filter条件使用“__“双下划线
Publish.objects.filter(name = “长江出版社”, book_set__name = “python基础”)
#values查询列使用”__”双下划线
Publish.objects.values(“name”,”book_set__name”)
Djaongo中默认反向查找使用小写类名_set可以反向访问到类对应表信息。但是这个是可以修改的。定义ForeiginKey时,将related_name属性赋予其他值。
例如不使用book_set,需要修改创建表
publish = models.ForeignKey('Publish',on_delete=models.CASCADE,related_name =”books”),
修改后就可以使用publish.books.all()获取book信息。
多对多数据库连接查询
当删除掉app的migrations文件夹中所有py文件后,执行python manage.py makemigrations 成功,但是执行python manage.py migrate创建没效果。
解决方式:
1、首先将各个子应用 app 下 migrations 文件夹中除 init.py 之外,其他文件全部删掉。
2、python manage.py dbshell 进到数据库中,
删除 django_migrations 表中,迁移时出错的子应用的所有记录
delete from django_migrations where app='your_appname';
3、python manage.py makemigrations
4、python manage.py migrate --fake
这样执行依然没用?重新创建数据库吧!
创建多对多表关系, models.ManyToManyField()。Django会自动生产多对多的那个关系表,表名为app名_多对多关系表名_多对多关系表名。
这里示例中的是ormApp_book_author。
示例:
from django.db import models
# Create your models here.
class Book(models.Model):
name = models.CharField(max_length=20);
price = models.FloatField();
pub_date=models.DateField();
count = models.IntegerField();
# #默认创建时pub,变成pub_id,如果pub_id数据库表变成pub_id_id
# pub = models.ForeignKey('Publish',to_field='id',default=1,on_delete=models.CASCADE);
#将整个对象作为外键
publish = models.ForeignKey('Publish',on_delete=models.CASCADE)
#多对多关系
author = models.ManyToManyField("Author");
class Publish(models.Model):
name = models.CharField(max_length=20);
addr = models.CharField(max_length=30);
class Author(models.Model):
name = models.CharField(max_length=10);
age = models.IntegerField();
多对多关系数据添加
#多对多关系添加数据
#通过对象绑定关系
book_obj = Book.objects.get(id=1);
#book_obj.author保存的是这本书对应作者的集合,使用all()获取集合所有对象
print(book_obj.author.all())
print(type(book_obj.author.all()))
#获取一个作者
author_obj = Author.objects.get(id = 1);
#book和作者关系绑定,写入多对多关系表ormApp_book_author
book_obj.author.add(author_obj);
#book和作者关系解除绑定
book_obj.author.remove(author_obj);
#多个作者添加删除
#获取多个作者,author_objs是一个集合,需要使用*添加
author_objs = Author.objects.all();
book_obj.author.add(*author_objs);
多对多查询
#多对多查询
#方式1:表名_set方式
#通过author,拿到author对应book信息
author_obj = Author.objects.get(id = 1);
#和一对多一样,通过book_set获取
print(author_obj.book_set.all())
#方式2:通过表名__列名作为筛选条件
#查询author对应book信息
book_list = Book.objects.filter(author__id = 1)
以上是Django自动创建的第三张关系表。
我们也可以自己创建第三张关系表类,但是不推荐自己建立第三张关系表。
# class Book_Author(models.Model):
# book = models.ForeignKey("Book",on_delete=models.CASCADE);
# author = models.ForeignKey("Author",on_delete=models.CASCADE);
#添加关联数据
Book_Author.objects.create(book_id=1,author_id =2);
多对多查询
#通过书籍查询作者信息
book_obj = Book.objects.create(id=2);
#通过书籍对象,获取作者信息
authors = book_obj.book_author_set.all()[0].author
#使用双下划线,通过表名__关联表名__关联表列名,作为条件。获取对应作者的书籍
book_list = Book.objects.filter(book_author__author__name=”作者名”)
多对多关系整理
书籍表Book和作者表Author,一本书可以对应多个作者,一个作者可以写多本书,所以Book和Author直接是多对多关系。
表定义多对多关系在Book表中建立字段:
author = models.ManyToManyField("Author")
ManyToManyField定义多对多关系。数据库中会自动生成对应的多对多关系的第三张表。其中关系表名:应用名_book_author。数据库中第三张关系表有book_id字段和author_id这两个外键,确定Book和Author表之间关系。
1、正向查询
Book表拥有author这个ManyToManyField字段,通过Book查询作者信息,这种查询叫做正向查询。
对象操作:
#添加记录
book = Book.objects.filter(id = 1).first();
#通过author操作add,添加操作
#为书籍1,添加一个作者2
book.author.add(2)
#通过author操作set,更新操作
#将Book和Author关系设置为1,1 和1,2,
#就是将书籍1和作者1和2关联,书籍1如果之前对应作者3会被删除
book.author.set([1,2])
#通过author对象操作
book = Book.objects.all().first();
#通过author字段操作作者表
print(book.author.all())
#filter和values中使用“__“双下划线访问关系表属性
book = Book.objects.filter(id = 1,author__name = “tom”).first();
book_list = Book.objects.values(“id”,”author__name”);
2、反向查询
Author表没有ManyToManyField字段,作为被动多对多连接表可以通过关系表小写表名_set作为操作字段访问关系表,这里Book表作为关系表,Author可以通过book_set作为对象操作Book表。这里也可以在创建Book表的author字段设置字段的related_name属性赋予其他值。
例如:
#设置related_name,反向查询通过Author表查询Book表时,使用books操作Book表相关信息
author = models.ManyToManyField("Author",related_name="books");
#查询作者对应书籍
author = Author.objects.filter(id = 1).first();
#设置了related_name,直接使用books或书籍名,否则使用book_set
print(author.books.name)
对象操作:
#通过book_set添加关系
author = Author.objects.filter(id = 2).first();
#让作者和book 2添加关系
author.book_set.add(2);
#filter和values使用”__”双下划线查找
author = Author.objects.filter(id = 2, book_set__name = “python基础”).first();
author_list = Author.objects.values(“id”,”book_set__name”)
Django聚合查询和分组查询
使用aggregate()聚会查询。
导入模块
from django.db.models import Avg,Sum,Max,Min
示例:
#聚合函数
#查询所有书籍平均值
ret = Book.objects.all().aggregate(Avg("price"));
print("书籍平均值:",ret)
#查询author的id为1的书籍价格总和
ret = Book.objects.filter(author__id = 1).aggregate(Sum("price"));
print("id为1作者书籍价格总和:", ret)
使用annotate()分组查询。
示例:
#分组作者,作者书籍价格总和
ret = Book.objects.values("author__name").annotate(Sum("price"));
print("按作者名分组,每个作者书价格总和:",ret)
Django的F和Q查询
需要导入F,Q模块
from django.db.models import F,Q
示例:
#将book的价格加上10
#这样写price识别不出来,需要用F对象将列包起来
#Book.objects.all().update(price = price + 10)
Book.objects.all().update(price = F("price") +10);
#查询时可以将条件使用Q对象包起来,可以使用与或非运算
#,与运算 | 或运算 ~ 非运算
#Q查询和普通可以混用,但Q查询必须在前面
# ret = Book.objects.filter(Q(price = 30) | Q( name = "人工智能"))
# print("Q查询与或非运算:", ret);
ret = Book.objects.filter(Q(name="python基础"),price = 150.23)
print("Q查询混合:",ret);
#没有使用iterator,所有记录都到内存,可以重复使用
for r in ret:
print(r.name);
for r in ret:
print(r.name);
Django中iterator和exists
#使用exists(),查找记录是否存在,不会将数据查询到queryset
if ret.exists():
print("存在记录")
#使用iterator(),当querySet很大时,避免内存占用
ret = Book.objects.all().iterator();
for r in ret:
print(r.name);
#只能打印一遍
for r in ret:
print(r.name);
Django的Model补充
Modle的定义外键属性的参数。简单写法直接写表名,on_delete:删除时是否级联。也可以定义时,设置各种属性。
示例:
publish = models.ForeignKey(to="Publish",to_field="id",on_delete=models.CASCADE)
#to:设置外键表名
#to_field:设置外键关联栏位
#on_delete:设置删除时操作,
#models.CASCADE:级联删除;
#models.DO_NOTHING:删除时报错
#models.PROTECT:删除时保错
#models.SET_NULL:删除关联数据时,与之关联的变成NULL
#models.SET_DEFAULT:删除时,设置默认值
#models.SET:删除时,删除关联数据,设置成指定值,models.SET(指定值),或者models.SET(func())设置关联值为func()返回值。
#related_name:设置反向查找时使用的属性名,默认是表名_set代表对应表。
#related_query_name:设置反向查询的表名,表名__字段名
#limit_choices_to:筛选外键关联查询出的数据,只在admin中生效。例如:limit_choices_to={"id__gt" : 1},将id大于1的数据筛选出来,当admin添加数据时,设置关联字段值,会做筛选。
#db_constraint:False or True是否数据库中创建外键约束
#parent_link:False or True 在admin中是否显示关联数据
多对多关系建立额外属性设置:
使用ManyToManyField定义多对多关系
#进阶设置
author = models.ManyToManyField(
#关联表
to="Author",
#是否创建外键约束
db_constraint=True,
#设置第三张表名
db_table=None,
#through,不自动创建第三张表,指定自己创建的Book_Author表
through="Book_Author",
through_fields=["book","author"]
)
db_table:设置第三张数据关系表表名,默认是两个关联表:表1_表2
默认设置ManyToMany字段后,Django自动创建第三张关系表,但是这张表只能有三个字段,我们如果需要其他字段,需要自己建立第三张表。
示例:
class Book_Author(models.Model):
book = models.ForeignKey("Book",on_delete=models.CASCADE);
author = models.ForeignKey("Author",on_delete=models.CASCADE);
#设置多个字段联合唯一,设置多个字段作为主键
class Meta:
unique_together=[
("book","author")
]
through:None,ManyToMany创建第三张表时,将第三张表指定为自己创建的表。这里可以指定through:Book_Author,
through_fields:None,指定关联字段,through_field:[“book“,“author”]
表的自关联
多对多:表的ManyToManyField字段是自己本身。一对多也可以自关联,ForeignKeyField是字段本身。
示例:
class Book(models.Model):
name = models.CharField(max_length=20,verbose_name="名称");
price = models.FloatField();
b = models.ManyToManyField("Book");
select_related函数:
Book表和Publish表是一对多关系,一本书对应一个出版社,一个出版社对应多本书。其中publish是Book表中外键。
查询关联字段,一次性查询出来,执行SQL语句
book_list = Book.object.all()
#这里通过对象获取Publish表数据,这里会执行SQL语句
#如果循环获取,会执行多次SQL,效能极差
book_list.publish.name
#使用select_related(外键栏位),一次性连接查询出来,可以传入多个外键栏位
book_list = Book.object.select_related(“publish”)
prefetch_related函数:
#使用prefetch_related(外键栏位),一次性连接查询出来,可以传入多个外键栏位
book_list = Book.object.prefetch_related(“publish”)
only函数和defer函数:
使用only只取指定列,效果和values类似,但only返回结果QuerySet中依然是对象列表
book_list = Book.object.only(“id”,”name”)
使用defer不取指定列
book_list = Book.object.defer(“id”)
using函数:
通过using(“别名”),查询指定数据库。
在setting.py中,using(“default”)。如果有另外一个“default1”的数据库,我们就可以使用using(“default1”)查询另一个数据库。
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.sqlite3',
'NAME': os.path.join(BASE_DIR, 'db.sqlite3'),
}
}
extra函数:
#通过extra可以执行额外的子查询。
Book.objects.extra(select = {“new_id”: “select id from Book where id > %s”},select_params = (10,))
#where条件
Book.objects.extra(where = [“name=’tang’”,”age > 10”])
raw函数:
#使用raw函数直接执行sql语句,
Book.objects.raw(“select id name from book”);
# 使用參數为原生SQL赋值
Book.objects.raw(“select * from book where id > %s”,params=[10,])
#将获取的列名对应其他名
name ={“id’:”ID”,”name”:”名称”,”price”:”价格”}
Book.objects.raw(“select id name price from book”,translations=name)
#使用数据库指定,使用默认default数据库
Book.objects.raw(“select * from book”,using =”default”)
dates函数:
获取时间栏位部分信息
dates(self,field_name,kind,order=’ASC’)
kind参数:year:年 month:年-月 day:年-月-日
Date.objects.dates(“time”,year,”DESC”)
datetimes函数:
获取时间栏位部分信息,年月日时分秒;
Datetimes(self,field_name,kind,order,tz_info=None)
Kind参数:year(年),month(月),day(日),hour(时),minute(分),second(秒)
tzinfo:时区对象,pytz.timezone(“时区字符串”);
使用pip3 install pytz
import pytz
#显示时区字符串
pytz.all_timezones
none函数:
获取空的QuerySet对象。
bulk_create函数:
批量创建记录,
bulk_create(self,objs,batch_size=None)
objs:对象列表,批量创建记录
batch_size:最大批量数
objs[Book(name=”天下”),name=”传奇”]
Book.objects.bulk_create(objs,10);
get_or_create函数:
获取记录,如果没有创建后再获取。
obj,created = Book.objects.get_or_create(id=”2”,defaults={name=”test”,price=11})
update_or_create函数:
更新记录,如果记录存在就根据defaults参数更新,不存在就创建。
obj,created = Book.objects.update_or_create(id=”2”,defaults={name=”test”,price=11})
本文来自博客园,作者:渔歌晚唱,转载请注明原文链接:https://www.cnblogs.com/tangToms/articles/14158962.html

浙公网安备 33010602011771号