ORM是通过使用描述对象和数据库之间映射的元数据,将程序中的对象自动持久化到关系数据库中。
1.ORM的优势
ORM解决的主要问题是对象和关系的映射。它通常将一个类和一张表一一对应,类的每个实例对应表中的一条记录,类的每个属性对应表中的每个字段。
ORM提供了对数据库的映射,不用直接编写SQL代码,只需操作对象就能对数据库操作数据。
让软件开发人员专注于业务逻辑的处理,提高了开发效率。
2.ORM的劣势
ORM的缺点是会在一定程度上牺牲程序的执行效率。
ORM的操作是有限的,也就是ORM定义好的操作是可以完成的,一些复杂的查询操作是完成不了。
ORM用多了SQL语句就不会写了,关系数据库相关技能退化…
3.ORM总结:
ORM只是一种工具,工具确实能解决一些重复,简单的劳动。这是不可否认的。
但我们不能指望某个工具能一劳永逸地解决所有问题,一些特殊问题还是需要特殊处理的。
但是在整个软件开发过程中需要特殊处理的情况应该都是很少的,否则所谓的工具也就失去了它存在的意义。
1.字段
1.1常用字段
AutoField
自增的整形字段,必填参数primary_key=True,则成为数据库的主键。无该字段时,django自动创建。
一个model不能有两个AutoField字段。
IntegerField
一个整数类型。数值的范围是 -2147483648 ~ 2147483647。
CharField
字符类型,必须提供max_length参数。max_length表示字符的长度。
DateField
日期类型,日期格式为YYYY-MM-DD,相当于Python中的datetime.date的实例。
参数:
- auto_now:每次修改时修改为当前日期时间。
- auto_now_add:新创建对象时自动添加当前日期时间。
auto_now和auto_now_add和default参数是互斥的,不能同时设置。
DatetimeField
日期时间字段,格式为YYYY-MM-DD HH:MM[:ss[.uuuuuu]][TZ],相当于Python中的datetime.datetime的实例。
1.2自定义字段
1.3字段参数
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'), ]
)
2.查询的方法(13个)
序号 | 方法 | 用法 |
---|---|---|
1 | all() | 查询所有结果 |
2 | get(**kwargs) | 返回与所给筛选条件相匹配的对象,返回结果有且只有一个,如果符合筛选条件的对象超过一个或者没有都会抛出错误。 |
3 | filter(**kwargs) | 它包含了与所给筛选条件相匹配的对象 |
4 | exclude(**kwargs) | 它包含了与所给筛选条件不匹配的对象 |
5 | values(*field) | 返回一个ValueQuerySet——一个特殊的QuerySet,运行后得到的并不是一系列model的实例化对象,而是一个可迭代的字典序列. 括号内指定字段,默认获取所有字段的名和值,如果指定字段则获取指定字段的名和值,并按照指定的顺序显示. |
6 | values_list(*field) | 它与values()非常相似,它返回的是一个元组序列,(values返回的是一个字典序列)只有values中的值,没有名,也可以指定字段,按照顺序显示. |
7 | order_by(*field) | 对查询结果排序,可以写多个字段 默认升序,加负号是降序 |
8 | reverse() | 对查询结果反向排序,请注意reverse()通常只能在具有已定义顺序的QuerySet上调用(在model类的Meta中指定ordering或调用order_by()方法)。 |
9 | distinct() | 从返回结果中剔除重复纪录(如果你查询跨越多个表,可能在计算QuerySet时得到重复的结果。此时可以使用distinct(),注意只有在PostgreSQL中支持按字段去重。) |
10 | count() | 返回数据库中匹配查询(QuerySet)的对象数量 |
11 | first() | 返回第一条记录,可以取代get,没有的时候就是None |
12 | last() | 返回最后一条记录 |
13 | exists() | 如果QuerySet包含数据,就返回True,否则返回False,可以用在filter后面 |
分类:
返回QuerySet对象的方法有
特殊的QuerySet
- values() 返回一个可迭代的字典序列
- values_list() 返回一个可迭代的元祖序列
返回具体对象的
- get()
- first()
- last()
返回布尔值的方法有:
- exists()
返回数字的方法有
- count()
3.单表查询-双下划线
models.Tb1.objects.filter(id__lt=10, id__gt=1) # 获取id大于1 且 小于10的值
models.Tb1.objects.filter(id__lte=10, id__gte=1) #大于等于1,小于等于10的
models.Tb1.objects.filter(id__exact=1) #等于1
models.Tb1.objects.filter(id__in=[11, 22, 33]) # 获取id等于11、22、33的数据
models.Tb1.objects.exclude(id__in=[11, 22, 33]) # not in
__isnull=True
models.Tb1.objects.filter(name__contains="ven") # 获取name字段包含"ven"的,like
models.Tb1.objects.filter(name__icontains="ven") # icontains大小写不敏感
models.Tb1.objects.filter(id__range=[1, 3]) # id范围是1到3的,等价于SQL的bettwen and 闭合[1,3]
类似的还有:startswith,istartswith(忽略大小写的), endswith, iendswith
date字段还可以:
models.Class.objects.filter(first_day__year=2017)
4.ForeignKey操作
正向查询
book_obj.publisher 关联的对象
反向查询
默认用obj.表名_set管理对象 如果指定了related_name=“books”,则直接用obj.books管理对象
# 查询出出版社出版的所有书籍
# 不指定 related_name='books'
print(pub_obj.book_set,type(pub_obj.book_set))
print(pub_obj.book_set.all())
# 指定related_name='books'
print(pub_obj.books,type(pub_obj.books))
print(pub_obj.books.all())
基于字段的查询
models.Book.objects.filter(publisher__name=“沙河出版社”)跨表
# 基于字段的查询
ret = models.Book.objects.filter(publisher__name='老男孩出版社')
# 不指定related_name
ret = models.Pubisher.objects.filter(book__title='太亮教开车')
# 指定related_name=books
ret = models.Publisher.objects.filter(books__title='太亮教开车')
# 指定related_query_name='book'
ret = models.Publisher.objects.filter(book__title='太亮教开车')
print(ret)
# 外键字段可以为null 才有remove和clear 只能写对象
pub_obj = models.Publisher.objects.get(id=1)
# pub_obj.books.remove(models.Book.objects.get(id=1))
# pub_obj.books.clear()
pub_obj.books.create(title='太亮的产后护理')
5.多对多的操作
# 基于对象的查询
# 正向
author_obj = models.Author.objects.get(id=2)
#
print(author_obj.books,type(author_obj.books))
print(author_obj.books.all())
# 反向
book_obj = models.Book.objects.get(id=1)
# 不指定related_name='authors'
print(book_obj.author_set.all())
# 指定related_name='authors'
print(book_obj.authors.all())
# set 设置多对多关系
author_obj.books.set([])
author_obj.books.set([1,2,3]) # 要关联对象的ID [ 对象的id,对象的id]
author_obj.books.set(models.Book.objects.all()) # 要关联对象 [ 对象,对象]
# add 添加多对多的关系 不改变原有的关联对象,直接添加
author_obj.books.add(1) # 要关联对象的ID
author_obj.books.add(models.Book.objects.get(id=2)) # 要关联对象
# remove() 删除多对多的关系
author_obj.books.remove(1) # 要关联对象的id
author_obj.books.remove(models.Book.objects.get(id=2)) # 要关联对象
# clear() # 清空当前对象的多对多的关系
author_obj.books.clear()
# create()
author_obj.books.create(title='太亮教抛光',)#在book表中创建一条title='太亮教抛光'的数据,并关联到这个author_obj
book_obj.authors.create(name='alex')#在author中创建一个alex作者,并关联到book_obj
6.聚合
aggregate()
是QuerySet
的一个终止子句,意思是说,它返回一个包含一些键值对的字典。后面不能再跟别的语句
键的名称是聚合值的标识符,值是计算出来的聚合值。键的名称是按照字段和聚合函数的名称自动生成出来的。
用到的内置函数:
from django.db.models import Avg, Sum, Max, Min, Count
ret = models.Book.objects.aggregate(max=Max('price')) # max是别名,结果中的key 得到的是{ }
print(models.Book.objects.aggregate(Avg("price"), Max("price"), Min("price")))
print(models.Book.objects.all().aggregate(Avg("price"), Max("price"), Min("price")))
#两个效果是一样的
7.分组
annotate前没有指定values,默认按照前面的对象分组,
如果指定了values,按照values分组.
# 统计出每个出版社卖的最便宜的书的价格
# 方法一 以出版社的id进行分组
ret=models.Publisher.objects.all().annotate(Min('book__price')).values()
for i in ret:
print(i)#不加values() 拿到的是对象 加values后拿到的是键值对 all()加不加都可以
# 方法二 values指定以什么字段进行分组,后面的values不能写其他额外的字段
ret=models.Book.objects.values('publisher__name').annotate(min=Min('price')).values('min')
for i in ret:
print(i)
8.F查询
F的作用 :动态的获取某个字段的值
from django.db.models import F
# 动态地获取字段的值
#筛选kucun>sale的book
ret= models.Book.objects.filter(kucun__gt=F('sale')).values()
#sale=原来的2倍
models.Book.objects.all().update(sale=F('sale')*2) # update更新指定字段
9.Q查询
Q
对象可以使用~
操作符取反 ,&
与 和|
或 操作符以及使用括号进行分组来编写任意复杂的Q
对象
from django.db.models import Q
ret = models.Book.objects.filter(Q(~Q(id__lt=3) | Q(id__gt=5))&Q(id__lt=4))
print(ret)
10.事务
一系列操作要同时成功执行,或都不执行,保证原子性操作。同生共死
from app01 import models
from django.db import transaction
try:
with transaction.atomic():
models.Publisher.objects.create(name='新华出版社1')
int('aaa')
models.Publisher.objects.create(name='新华出版社2')
models.Publisher.objects.create(name='新华出版社2')
except Exception as e:
print(e)
11.在Python脚本中调用Django环境
import os
if __name__ == '__main__':
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "BMS.settings")
import django
django.setup()
from app01 import models
books = models.Book.objects.all()
print(books)