django ORM简介
O(objects):类和对象。R(Relation):关系,关系数据库中的表格。M(Mapping):映射。
Django ORM框架的功能:
- 建立模型类和表之间的对应关系,允许我们通过面向对象的方式来操作数据库。
- 根据设计的模型类生成数据库中的表格。
- 通过方便的配置就可以进行数据库的切换。
数据库的配置
Django可以配置使用sqlite3,mysql,oracle,postgresql等数据库。Django默认使用的是sqlite3数据库,settigs.py里面:
#使用sqlite3数据库
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.sqlite3',#默认使用的数据库引擎是sqlite3,项目自动创建
'NAME': os.path.join(BASE_DIR, 'db.sqlite3'),#指定数据库所在的路径
}
}
Django项目也可以配置使用mysql数据库,使用如下配置:
#mysql数据库
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.mysql',#表示使用的是mysql数据库的引擎
'NAME': 'db1', #数据库的名字,可以在mysql的提示符下先创建好
'USER':'root', #数据库用户名
'PASSWORD':'', #数据库密码
'HOST':'', #数据库主机,留空默认为"localhost"
'PORT':'3306', #数据库使用的端口
}
}
配置好数据库的信息后还必须安装数据库的驱动程序,Django默认导入的mysql的驱动程序是MySQLdb,然而MySQLdb对于py3支持不全,所以这里使用PyMySQL。
pip install pymysql
在项目名文件下的__init__.py文件中写入如下配置:
import pymysqlpymysql.install_as_MySQLdb()
创建数据库表结构文件
对应app目录下的models.py
1、生成一个简单的数据库表:
在未指定primary_key的情况下,Django会默认创建一个id自增字段作为主键。
from django.db import models
class Account(models.Model):
account_name = models.CharField(max_length=20)
account_id = models.IntegerField(primary_key=True)
balance = models.DecimalField(max_digits=2, decimal_places=2)
2、执行命令生成到数据库
python manage.py makemigrations
python manage.py migrate # 生成数据表
数据库字段
AutoField(Field) - int自增列,必须填入参数 primary_key=True
BigAutoField(AutoField) - bigint自增列,必须填入参数 primary_key=True
SmallIntegerField(IntegerField): - 小整数 -32768 ~ 32767
PositiveSmallIntegerField(PositiveIntegerRelDbTypeMixin, IntegerField) - 正小整数 0 ~ 32767
IntegerField(Field) - 整数列(有符号的) -2147483648 ~ 2147483647
PositiveIntegerField(PositiveIntegerRelDbTypeMixin, IntegerField) - 正整数 0 ~ 2147483647
BigIntegerField(IntegerField): - 长整型(有符号的) -9223372036854775808 ~ 9223372036854775807
BooleanField(Field) - 布尔值类型
NullBooleanField(Field): - 可以为空的布尔值
CharField(Field) - 字符类型
- 必须提供max_length参数, max_length表示字符长度
TextField(Field) - 文本类型
EmailField(CharField): - 字符串类型,Django Admin以及ModelForm中提供验证机制
IPAddressField(Field) - 字符串类型,Django Admin以及ModelForm中提供验证 IPV4 机制
GenericIPAddressField(Field) - 字符串类型,Django Admin以及ModelForm中提供验证 Ipv4和Ipv6
- 参数:
protocol,用于指定Ipv4或Ipv6, 'both',"ipv4","ipv6"
unpack_ipv4, 如果指定为True,则输入::ffff:192.0.2.1时候,可解析为192.0.2.1,开启刺功能,需要protocol="both"
URLField(CharField) - 字符串类型,Django Admin以及ModelForm中提供验证 URL
SlugField(CharField) - 字符串类型,Django Admin以及ModelForm中提供验证支持 字母、数字、下划线、连接符(减号)
CommaSeparatedIntegerField(CharField) - 字符串类型,格式必须为逗号分割的数字
UUIDField(Field) - 字符串类型,Django Admin以及ModelForm中提供对UUID格式的验证
FilePathField(Field) - 字符串,Django Admin以及ModelForm中提供读取文件夹下文件的功能
- 参数:
path, 文件夹路径
match=None, 正则匹配
recursive=False, 递归下面的文件夹
allow_files=True, 允许文件
allow_folders=False, 允许文件夹
FileField(Field) - 字符串,路径保存在数据库,文件上传到指定目录
- 参数:
upload_to = "" 上传文件的保存路径
storage = None 存储组件,默认django.core.files.storage.FileSystemStorage
ImageField(FileField) - 字符串,路径保存在数据库,文件上传到指定目录
- 参数:
upload_to = "" 上传文件的保存路径
storage = None 存储组件,默认django.core.files.storage.FileSystemStorage
width_field=None, 上传图片的高度保存的数据库字段名(字符串)
height_field=None 上传图片的宽度保存的数据库字段名(字符串)
DateTimeField(DateField) - 日期+时间格式 YYYY-MM-DD HH:MM[:ss[.uuuuuu]][TZ]
DateField(DateTimeCheckMixin, Field) - 日期格式 YYYY-MM-DD
TimeField(DateTimeCheckMixin, Field) - 时间格式 HH:MM[:ss[.uuuuuu]]
DurationField(Field) - 长整数,时间间隔,数据库中按照bigint存储,ORM中获取的值为datetime.timedelta类型
FloatField(Field) - 浮点型
DecimalField(Field) - 10进制小数
- 参数:
max_digits,小数总长度
decimal_places,小数位长度
BinaryField(Field)- 二进制类型
数据库字段参数
null 数据库中字段是否可以为空
db_column 数据库中字段的列名
default 数据库中字段的默认值
primary_key 数据库中字段是否为主键
db_index 数据库中字段是否可以建立索引
unique 数据库中字段是否可以建立唯一索引
unique_for_date 数据库中字段【日期】部分是否可以建立唯一索引
unique_for_month 数据库中字段【月】部分是否可以建立唯一索引
unique_for_year 数据库中字段【年】部分是否可以建立唯一索引
verbose_name Admin中显示的字段名称
blank Admin中是否允许用户输入为空
editable Admin中是否可以编辑
help_text Admin中该字段的提示信息
choices Admin中显示选择框的内容,用不变动的数据放在内存中从而避免跨表操作
如:gf = models.IntegerField(choices=[(0, '何穗'),(1, '大表姐'),],default=1)
error_messages 自定义错误信息(字典类型),从而定制想要显示的错误信息;
字典健:null, blank, invalid, invalid_choice, unique, and unique_for_date
如:{'null': "不能为空.", 'invalid': '格式错误'}
validators 自定义错误验证(列表类型),从而定制想要的验证规则
from django.core.validators import RegexValidator
from django.core.validators import EmailValidator,URLValidator,DecimalValidator,\
MaxLengthValidator,MinLengthValidator,MaxValueValidator,MinValueValidator
如:
test = models.CharField(
max_length=32,
error_messages={
'c1': '优先错信息1',
'c2': '优先错信息2',
'c3': '优先错信息3',
},
validators=[
RegexValidator(regex='root_\d+', message='错误了', code='c1'),
RegexValidator(regex='root_112233\d+', message='又错误了', code='c2'),
EmailValidator(message='又错误了', code='c3'), ]
)
数据库Meta元信息
class UserInfo(models.Model):
nid = models.AutoField(primary_key=True)
username = models.CharField(max_length=32)
class Meta:
# 数据库中生成的表名称 默认 app名称 + 下划线 + 类名
db_table = "table_name"
# 联合索引
index_together = [
("pub_date", "deadline"),
]
# 联合唯一索引
unique_together = (("driver", "restaurant"),)
# admin中显示的表名称
verbose_name
# verbose_name加s
verbose_name_plural
关系字段
1、ForeignKey
ForeignKey(ForeignObject) # ForeignObject(RelatedField)
to, # 要进行关联的表名
to_field=None, # 要关联的表中的字段名称
on_delete=None, # 当删除关联表中的数据时,当前表与其关联的行的行为
- models.CASCADE,删除关联数据,与之关联也删除
- models.DO_NOTHING,删除关联数据,引发错误IntegrityError
- models.PROTECT,删除关联数据,引发错误ProtectedError
- models.SET_NULL,删除关联数据,与之关联的值设置为null(前提FK字段需要设置为可空)
- models.SET_DEFAULT,删除关联数据,与之关联的值设置为默认值(前提FK字段需要设置默认值)
- models.SET,删除关联数据,
a. 与之关联的值设置为指定值,设置:models.SET(值)
b. 与之关联的值设置为可执行对象的返回值,设置:models.SET(可执行对象)
def func():
return 10
class MyModel(models.Model):
user = models.ForeignKey(
to="User",
to_field="id"
on_delete=models.SET(func),)
related_name=None, # 反向操作时,使用的字段名,用于代替 【表名_set】 如:obj.表名_set.all()
related_query_name=None, # 反向操作时,使用的连接前缀,用于替换【表名】 如:models.UserGroup.objects.filter(表名__字段名=1).values('表名__字段名')
limit_choices_to=None, # 在Admin或ModelForm中显示关联数据时,提供的条件:
# 如:
- limit_choices_to={'nid__gt': 5}
- limit_choices_to=lambda : {'nid__gt': 5}
from django.db.models import Q
- limit_choices_to=Q(nid__gt=10)
- limit_choices_to=Q(nid=8) | Q(nid__gt=10)
- limit_choices_to=lambda : Q(Q(nid=8) | Q(nid__gt=10)) & Q(caption='root')
db_constraint=True # 是否在数据库中创建外键约束
parent_link=False # 在Admin中是否显示关联数据
2、OneToOneField
OneToOneField(ForeignKey)
to, # 要进行关联的表名
to_field=None # 要关联的表中的字段名称
on_delete=None, # 当删除关联表中的数据时,当前表与其关联的行的行为
###### 对于一对一 ######
# 1. 一对一其实就是 一对多 + 唯一索引
# 2.当两个类之间有继承关系时,默认会创建一个一对一字段
# 如下会在A表中额外增加一个c_ptr_id列且唯一:
class C(models.Model):
nid = models.AutoField(primary_key=True)
part = models.CharField(max_length=12)
class A(C):
id = models.AutoField(primary_key=True)
code = models.CharField(max_length=1)
3、ManyToManyField
ManyToManyField(RelatedField)
to, # 要进行关联的表名
related_name=None, # 反向操作时,使用的字段名,用于代替 【表名_set】 如:obj.表名_set.all()
related_query_name=None, # 反向操作时,使用的连接前缀,用于替换【表名】 如:models.UserGroup.objects.filter(表名__字段名=1).values('表名__字段名')
limit_choices_to=None, # 在Admin或ModelForm中显示关联数据时,提供的条件:
# 如:
- limit_choices_to={'nid__gt': 5}
- limit_choices_to=lambda : {'nid__gt': 5}
from django.db.models import Q
- limit_choices_to=Q(nid__gt=10)
- limit_choices_to=Q(nid=8) | Q(nid__gt=10)
- limit_choices_to=lambda : Q(Q(nid=8) | Q(nid__gt=10)) & Q(caption='root')
symmetrical=None, # 仅用于多对多自关联时,symmetrical用于指定内部是否创建反向操作的字段
# 做如下操作时,不同的symmetrical会有不同的可选字段
models.BB.objects.filter(...)
# 可选字段有:code, id, m1
class BB(models.Model):
code = models.CharField(max_length=12)
m1 = models.ManyToManyField('self',symmetrical=True)
# 可选字段有: bb, code, id, m1
class BB(models.Model):
code = models.CharField(max_length=12)
m1 = models.ManyToManyField('self',symmetrical=False)
through=None, # 自定义第三张表时,使用字段用于指定关系表
through_fields=None, # 自定义第三张表时,使用字段用于指定关系表中那些字段做多对多关系表
from django.db import models
class Person(models.Model):
name = models.CharField(max_length=50)
class Group(models.Model):
name = models.CharField(max_length=128)
members = models.ManyToManyField(
Person,
through='Membership',
through_fields=('group', 'person'),
)
class Membership(models.Model):
group = models.ForeignKey(Group, on_delete=models.CASCADE)
person = models.ForeignKey(Person, on_delete=models.CASCADE)
inviter = models.ForeignKey(
Person,
on_delete=models.CASCADE,
related_name="membership_invites",
)
invite_reason = models.CharField(max_length=64)
db_constraint=True, # 是否在数据库中创建外键约束
db_table=None, # 默认创建第三张表时,数据库中表的名称
数据库基本操作
#创建一个书的类,继承models类
class Book(models.Model):
#用models类创建书的名字,类型为字符串,CharField相当于mysql语句中的varchar,字段最长为32
title = models.CharField(max_length=32)
#创建书的价格,类型为浮点型,小数点前最长4位,小数点后最长2位
price = models.DecimalField(max_digits=6, decimal_places=2)
#创建书的出版社信息,其与出版社的外键关系为一对多,所以用外键
publish = models.ForeignKey(Publish)
#创建书的出版日期,类型为日期
publication_date = models.DateField()
#创建书的类型信息,为字符串类型,最长为20
classification=models.CharField(max_length=20)
#创建书的作者信息,书籍与作者的关系为多对多,所以使用many-to-many
authors = models.ManyToManyField("Author")
1、增
1.1一对一信息的创建
a、使用create方式
方式一: Publish.objects.create("name"="人民出版社",city="北京"}
方式二: Publish.objects.create(**{"name":"文艺出版社","city":"上海"}}
b、使用save方式
方式一:
book1=Book(title="python",price="88",publish_id="1",publication_date="2017-06-18")
book1.save()
方式二:
author1=Author(name="jerry")
author1.save()
1.2一对多的信息的创建(Foreignkey)
方式一:
#获取出版社对象
publish_obj=Publish.objects.get(id=4)
#将出版社的对象绑定到书籍的记录中
Book.objects.create(
title="python",
price=48.00,
publication_date="2017-07-12",
publish=publish_obj,
)
方式二:
#直接把出版社的id号插入到书籍的记录中
Book.objects.create(
title="python",
price=48.00,
publish_id=2,
publication_date="2017-06-18",
)
1.3多对多信息的创建(ManyToManyField())
a、为一本书添加多个作者
author1=Author.objects.get(id=1)#获取id号为1的作者对象
author2=Author.objects.filter(name="tom")#获取名字为"tom"的作者对象
book1=Book.objects.get(id=2)#获取id号为2的书籍对象
book1.authors.add(author1,author2)#为书籍对象添加多个作者对象
也可以用这种方式:
book1.authors.add(*[author1,author2])#为书籍对象添加作者对象的列表
book1.authors.remove(*[author1,author2])#删除指定书籍的所有作者
b、为一个作者添加多本书
author_obj = Author.objects.filter(name="jerry")#获取名字为"jerry"的作者对象
book_obj=Book.objects.filter(id__gt=3)#获取id大于3的书籍对象集合
author_obj.book_set.add(*book_obj)#为作者对象添加书籍对象集合
author_obj.book_set.remove(*book_obj)#删除指定作者对象所有的书籍
使用models.ManyToManyField()会自动创建第三张表
1.4手动创建多对多的作者与书籍信息表
class Book2Author(models.Models):
author=models.ForeignKey("Author")#为作者指定Author这张表做为外键
book=models.ForeignKey("Book")#为书籍指定Book这张表做为外键
author_obj=models.Author.objects.filter(id=3)[0]#获取Author表中id为3的作者对象
book_obj=models.Book.objects.filter(id=4)[0]#获取Book表中id为4的书籍对象
方式一:
obj1=Book2Author.objects.create(author=author_obj,book=book_obj)
obj1.save()
方式二:
obj2=Book2Author(author=author_obj,book=book_obj)obj2.save()
2、删
Book.objects.filter(id=1).delete()
3、改
3.1使用save方法将所有属性重新设定一遍,效率低
author1=Author.objects.get(id=3)#获取id为3的作者对象
author1.name="jobs"#修改作者对象的名字
author1.save()#把更改写入数据库
3.2使用update方法直接设置对就的属性
Publish.objects.filter(id=2).update(name="北京出版社")
注意:update()是QuerySet对象的一个方法,get返回的是一个model对象,其没有update方法.
filter返回的是一个QuerySet对象,filter里可以设定多个过滤条件
4、查
查询数据使用QuerySet API。QuerySet是惰性执行的,创建Query Set不会访问数据库,只有在访问具体查询结果的时候才会访问数据库。
4.1查询方法:
filter(**kwargs) 包含了与所给筛选条件相匹配的对象
all() 查询所有结果
get(**kwargs) 返回与所给筛选条件相匹配的对象,返回结果有且只有一个,如果符合筛选条件的对象超过一个或者没有都是报错
values(*field) 返回一个ValueQuerySet,运行后得到的并不是一系列model的实例化对象,而是一个可迭代的字典序列
exclude(**kwargs) 包含了与所给的筛选条件不匹配的对象
order by(*field) 对查询结果排序
reverse() 对查询结果反向排序
distinct() 从返回结果中剔除重复记录
values_list(*field) 与values()非常相似,返回一个元组序列,values返回一个字典序列
count() 返回数据库中匹配的记录的数量
first() 返回数据库中匹配的对象的第一个对象
last() 返回数据库中匹配的对象的最后一个对象
exists() 判断一个对象集合中是否包含指定对象,包含返回True,不包含返回False
exclude() 排除满足条件的对象
annotate() 使用聚合函数
dates() 根据日期获取查询集
datetimes() 根据时间获取查询集
none() 创建空的查询集
union() 并集
intersection() 交集
difference() 差集
select_related() 附带查询关联对象
prefetch_related() 预先查询
extra() 附加SQL查询
defer() 不加载指定字段
only() 只加载指定的字段
using() 选择数据库
select_for_update() 锁住选择的对象,直到事务结束。
raw() 接收一个原始的SQL查询
1.filter():
filter(**kwargs)
返回满足查询参数的对象集合。
查找的参数(**kwargs)应该满足下文字段查找中的格式。多个参数之间是和AND的关系。
Student.objects.filter(age__lt=10)#查询满足年龄小于10岁的所有学生对象
2.exclude():
exclude(**kwargs)
返回一个新的QuerySet,它包含不满足给定的查找参数的对象
Student.objects.exclude(age__gt=20, name='lin')#排除所有年龄大于20岁且名字为“lin”的学员集
3.annotate():
nnotate(args, *kwargs)
使用提供的聚合表达式查询对象。
表达式可以是简单的值、对模型(或任何关联模型)上的字段的引用或者聚合表达式(平均值、总和等)。
annotate()的每个参数都是一个annotation,它将添加到返回的QuerySet每个对象中。
关键字参数指定的Annotation将使用关键字作为Annotation 的别名。匿名参数的别名将基于聚合函数的名称和模型的字段生成。只有引用单个字段的聚合表达式才可以使用匿名参数。其它所有形式都必须用关键字参数。
例如,如果正在操作一个Blog列表,你可能想知道每个Blog有多少Entry:
\>>> from django.db.models import Count
\>>> q = Blog.objects.annotate(Count('entry'))
\# The name of the first blog
\>>> q[0].name
'Blogasaurus'
\# The number of entries on the first blog
\>>> q[0].entry__count
42
4.order_by():
order_by(*fields)
默认情况下,根据模型的Meta类中的ordering属性对QuerySet中的对象进行排序
Student.objects.filter(school="阳关小学").order_by('-age', 'name')
上面的结果将按照age降序排序,然后再按照name升序排序。"-age"前面的负号表示降序顺序。升序是默认的。要随机排序,使用"?",如下所示:
Student.objects.order_by('?')
- reverse():
reverse()
反向排序QuerySet中返回的元素。第二次调用reverse()将恢复到原有的排序。
如要获取QuerySet中最后五个元素,可以这样做:
my_queryset.reverse()[:5]
这与Python直接使用负索引有点不一样。Django不支持负索引。
6.distinct():
distinct(*fields)
去除查询结果中重复的行。
默认情况下,QuerySet不会去除重复的行。当查询跨越多张表的数据时,QuerySet可能得到重复的结果,这时候可以使用distinct()进行去重。
- values():
values(fields, *expressions)
返回一个包含数据的字典的queryset,而不是模型实例。
每个字典表示一个对象,键对应于模型对象的属性名称。如:
\# 列表中包含的是Student对象
\>>> Student.objects.filter(name__startswith='Lin')
<QuerySet [<Student: Lin Student>]>
\# 列表中包含的是数据字典
\>>> Student.objects.filter(name__startswith='Lin').values()
<QuerySet [{'id': 1, 'name': 'Linxiao', 'age': 20}]>
另外该方法接收可选的位置参数*fields,它指定values()应该限制哪些字段。如果指定字段,每个字典将只包含指定的字段的键/值。如果没有指定字段,每个字典将包含数据库表中所有字段的键和值。如下:
\>>> Student.objects.filter(name__startswith='Lin').values()
<QuerySet [{'id': 1, 'name': 'Linxiao', 'age': 20}]>
\>>> Blog.objects.values('id', 'name')
<QuerySet [{'id': 1, 'name': 'Linxiao'}]>
8.values_list():
values_list(*fields, flat=False)
与values()类似,只是在迭代时返回的是元组而不是字典。每个元组包含传递给values_list()调用的相应字段或表达式的值,因此第一个项目是第一个字段等。像这样:
\>>> Student.objects.values_list('id', 'name')
获取数据表的全部数据记录:
Account.objects.all()
返回值可以进行切片,但不支持负索引。或者使用:
Account.objects.get(field_name=val)
示例:
Account.objects.get(account_name='john')
或者使用过滤器查询多条记录:
Account.objects.filter(accounnt_name=val)
严格等于
Account.objects.filter(account_name__iexact=val)
忽略大小写
Account.objects.filter(account_name__contains=val)
名称中包含val
Account.objects.filter(account_name__icontains=val)
忽略大小写,包含
Account.objects.filter(account_name__regex=val)
正则表达式
Account.objects.filter(account_name__iregex=val)
正则表达式,忽略大小写
与filter相反exclude用于返回不满足条件的查询结果。
Account.objects.exclude(account_name__contains=val)
filter与exclude可以进行链式查询
Account.objects.exclude(account_name__contains='john').exlucde(balance=0)
对于查询结果可以使用distinct()去重或者使用order_by(field)进行排序。
Account.objects.filter(account_name__regex=val).distinct()
Account.objects.filter(account_name__regex=val).oreder_by('balance')
使用reverse()方法可以反转结果集中的元素顺序,调用两次将会恢复原顺序。
从SQL 的角度,QuerySet和SELECT 语句等价,过滤器是像WHERE 和LIMIT 一样的限制子句。
like:
__exact 精确等于 like 'aaa'
__iexact 精确等于 忽略大小写 ilike 'aaa'
__contains 包含 like '%aaa%'
__icontains 包含,忽略大小写 ilike '%aaa%',但是对于sqlite来说,contains的作用效果等同于icontains。
in:
__in
查询在某一范围的书
Book.objects.filter(publish__in=[10, 20, 30])
is null / is not null:
__isnull 判空
Book.objects.filter(name__isnull=True) // 查询用户名为空的书
Publish.objects.filter(name__isnull=False) // 查询用户名不为空的书
不等于/不包含于:
Book.objects.filter().excute(publishe=10) // 查询出版社不为10的书
Book.objects.filter().excute(publish__in=[10, 20]) // 查询出版社不在 [10, 20] 的书
其他常用模糊查询:
__startswith 以…开头
__istartswith 以…开头 忽略大小写
__endswith 以…结尾
__iendswith 以…结尾,忽略大小写
__range 在…范围内
__year 日期字段的年份
__month 日期字段的月份
__day 日期字段的日
4.2双下划线(__)查询
a、双下划线(__)之单表条件查询
例子:
table1.objects.filter(id__lt=10,id__gt=1)#获取id小于10,且大于1的记录
table1.objects.filter(id__in=[11,22,33,44])#获取id在[11,22,33,44]中的记录
table1.objects.exclude(id__in=[11,22,33,44])#获取id不在[11,22,33,44]中的记录
table1.objects.filter(name__contains="content1")#获取name中包含有"contents"的记录(区分大小写)
table1.objects.filter(name__icontains="content1")#获取name中包含有"content1"的记录(不区分大小写)
table1.objects.filter(id__range=[1,4])#获取id在1到4(不包含4)之间的的记录
b、双下划线(__)之多表条件查询
正向查找(条件)之一对一查询
#查询书名为"python"的书的id号
res3=Book.objects.filter(title="python").values("id")
print(res3)
正向查找(条件)之一对多查询
#查询书名为"python"的书对应的出版社的地址
res4=Book.objects.filter(title="python").values("publisher__city")
print(res4)
#查询"aaa"作者所写的所有的书的名字
res5=Book.objects.filter(author__name="aaa").values("title")
print(res5)
#查询"aaa"作者所写的所有的书的名字(与上面的用法没区别)
res6=Book.objects.filter(author__name="aaa").values("title")
print(res6)
反向查找之一对多查询
#查询出版了书名为"python"这本书的出版社的名字
res7=Publisher.objects.filter(book__title="python").values("name")
print(res7)
#查询写了书名为"python"的作者的名字
res8=Publisher.objects.filter(book__title="python").values("book__authors")
print(res8)
反向查找之多对多查询
#查询所写的书名为"python"的作者的名字
res9=Author.objects.filter(bool__title="python").values("name")
print(res9)
条件查询即与对象查询对应,是指filter,values等方法中的通过__来明确查询条件
4.3F查询和Q查询
F查询专门取对象中某列值的操作,F的作用:用来批量修改数据的
#导入F
from django.db.models import F
#把table1表中的num列中的每一个值在的基础上加10
table1.objects.all().update(num=F("num")+10)
Q构建搜索条件, Q的作用:Q是用来做条件查询的
#导入Q
from django.db.models import Q
Q对象可以对关键字参数进行封装,从而更好的应用多个查询
#查询table2表中以"aaa"开头的所有的title列
q1=table2.objects.filter(Q(title__startswith="aaa")).all()
print(q1)
Q对象可以组合使用&,|操作符,当一个操作符是用于两个Q对象时,会产生一个新的Q对象
#查找以"aaa"开头,或者以"bbb"结尾的所有title
Q(title__startswith="aaa") | Q(title__endswith="bbb")
Q对象可以用"~"操作符放在表达式前面表示否定,也可允许否定与不否定形式的组合
#查找以"aaa"开头,且不以"bbb"结尾的所有title
Q(title__startswith="aaa") & ~Q(title__endswith="bbb")
Q对象可以与关键字参数查询一起使用,Q对象放在关键字查询参数的前面
查询条件:
#查找以"aaa"开头,以"bbb"结尾的title且书的id号大于4的记录
Q(title__startswith="aaa") | Q(title__endswith="bbb"),book_id__gt=4
实例
1、Django的ORM中如何判断查询结果是否为空,判断django中的orm为空
result= Booking.objects.filter()
方法一 .exists()
if result.exists():
print "QuerySet has Data"
else:
print "QuerySet is empty"
方法二 .count()==0
if result.count() == 0:
print "empty"
方法三
if result:
print "QuerySet has Data"
else:
print "QuerySet is empty"
总结:
QuerySet.exists() > QuerySet.count()==0 > QuerySet
2、模板中显示数据库内容的方法
a、创建数据库
from django.db import models
from django.db import models
class Business(models.Model):
caption = models.CharField(max_length=32)
code = models.CharField(max_length=32)
class Host(models.Model):
nid = models.AutoField(primary_key=True)
hostname = models.CharField(max_length=32,db_index=True)
ip = models.GenericIPAddressField(protocol='both',db_index=True)
port = models.IntegerField()
business = models.ForeignKey(to='Business',to_field='id',on_delete=models.CASCADE)
business.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<h1>业务线列表(对象)</h1>
<ul>
{% for row in v1 %}
<li>{{ row.id }}-{{ row.caption }}-{{ row.code }}</li>
{% endfor %}
</ul>
<h1>业务线列表(字典)</h1>
<ul>
{% for row2 in v2 %}
<li>{{ row2.id }}-{{ row2.caption }}</li>
{% endfor %}
</ul>
</body>
</html>
host.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<h1>主机列表(对象)</h1>
<table border="1">
<tread>
<tr>
<th>主机ID</th>
<th>IP</th>
<th>端口</th>
<th>业务线名称</th>
</tr>
</tread>
<tbody>
{% for row in v1 %}
<tr>
<td>{{ row.hostname }}</td>
<td>{{ row.ip }}</td>
<td>{{ row.port }}</td>
<td>{{ row.business.caption }}</td>
</tr>
{% endfor %}
</tbody>
</table>
<h1>主机列表(字典)</h1>
<table border="1">
<tread>
<tr>
<th>主机ID</th>
<th>主机名</th>
<th>业务线ID</th>
<th>业务线名称</th>
</tr>
</tread>
<tbody>
{% for row in v2 %}
<tr>
<td>{{ row.nid }}</td>
<td>{{ row.hostname }}</td>
<td>{{ row.business__id }}</td>
<td>{{ row.business__caption }}</td>
</tr>
{% endfor %}
</tbody>
</table>
<h1>主机列表(元祖)</h1>
<table border="1">
<tread>
<tr>
<th>主机ID</th>
<th>主机名</th>
<th>业务线ID</th>
<th>业务线名称</th>
</tr>
</tread>
<tbody>
{% for row in v3 %}
<tr>
<td>{{ row.0 }}</td>
<td>{{ row.1 }}</td>
<td>{{ row.2 }}</td>
<td>{{ row.3 }}</td>
</tr>
{% endfor %}
</tbody>
</table>
</body>
</html>
views.py
from django.shortcuts import render,HttpResponse
from app01 import models
def business(request):
# 第一种方式(是个对象)
v1 = models.Business.objects.all()
# 第二种方式,只取id和caption(是个字典)
v2 = models.Business.objects.all().values('id','caption')
return render(request,'business.html',{'v1':v1,'v2':v2})
def host(request):
#总共三种方式,对象,字典,列表
v1 = models.Host.objects.all()
v2 = models.Host.objects.filter(nid__gt=0).values('nid','hostname','business__id','business__caption')
v3 = models.Host.objects.filter(nid__gt=0).values_list('nid','hostname','business__id','business__caption')
return render(request,'host.html',{'v1':v1,'v2':v2,'v3':v3})