ORM
对象映射关系:把我们定义的对象(类),,映射到数据库的表中,Django的ORM, 是为了跟SQL语句有同样的表达能力
- DateTimeField:
True, Django会默认填充当前时间
- choices: 在admin中, 会提供一个下拉列表
数值型
| 字段 |
介绍 |
| AutoField int(11) |
自增主键: id = models.AutoField(primary_key=True) |
| BooleanField tinyint(1) |
布尔类型字段, 一般用来记录状态标记 |
| DecimalField decimal |
指定精确到多少位数: 666.66 => max_digits=5, decimal_places=2 |
| IntegerField int(11) |
同AutoFields一样, 但是不自增 |
| PositiveIntegerField |
同IntegerField, 但是只包含正整数 |
| SmallIntegerField smallint |
小整数时一般用到 |
字符型
| 字段 |
介绍 |
| CharField varchar |
基础的varchar类型 |
| URLField |
继承自CharField, 但是实现了对URL的特殊处理 |
| UUIDField char(32) |
除了PostgreSQL中使用的时UUID类型, 其他都是固定长度char(32), 用来存放生成的唯一ID |
| EmailField |
继承自CharField, 但是实现了对Email的特殊处理 |
| FileField |
继承自CharField, 但是实现了对文件的特殊处理 |
| TextField |
longtext 继承自FileField, 用来处理图片相关数据, 在展示上会有不同 |
日期类型
| 字段 |
介绍 |
| DateField |
对应MySQL中的data |
| DateTimeField |
对应MySQL中的datatime |
| TimeField |
对应MySQL中的data |
关系类型
用来关联两张表
多对多会创建一个中间表,来进行多对多的关联
| 字段 |
介绍 |
| ForeignKey |
|
| OneToOneField |
|
| ManyToManyField |
|
参数
| 字段 |
介绍 |
| null |
用于设定在数据库层面是否允许为空 |
| blank |
针对业务层面, 该值是否允许为空 |
| choices |
配置之后,在admin页面可以看到对应的可选项展示 |
| db_column |
指定Model中的某个字段对应数据库中的哪个字段 |
| db_index |
配置索引,作为查询条件的字段 |
| default |
默认值配置 |
| editable |
是否可编辑, 默认True。如果不想这个字段展示到页面上可以设置False |
| error_messages |
用来自定义字段值校验失败时的异常显示key(null、blank、invalid、incalid_choice、unique、unique_for_date) |
| help_text |
字段提示语,在页面对应字段的下方展示此配置 |
| primary_key |
主键,配置后,在页面对字段的下方会展示此配置 |
unique_for_date |
针对date的联合约束,不是数据库层面的约束 |
| unique_for_month |
针对月份的联合约束 |
| unique_for_year |
针对年份的联合约束 |
| verbose_name |
字段对应的展示文案 |
| validators |
自定义校验逻辑, 同form类似 |
QuerySet
本质是一个懒加载的对象
可以使用链式调用: posts = Post.objects.filter(status=1).filter(category_id=2)
posts = Post.objects.all() # 返回一个QuerySet对象,赋值给posts
available_posts = posts.filter(status=1) # 继续返回一个QuerySet对象,并赋值给available_posts
print(available_posts) # 此时根据上面的两个条件执行数据库查询操作,对应:select × from blog_post where status = 1;
支持链式调用的接口
| 接口 |
介绍 |
| all |
查询所有数据 |
| filter |
根据条件过滤数据 |
| exclude |
同filter, 只是相反的逻辑 |
| reverse |
把QuerySet中的结果倒叙排列 |
| distinct |
用来进行去重查询 |
| none |
返回空的QuerySet |
不支持链式调用
| 接口 |
介绍 |
| get |
条件查询,存在返回实例,不存则抛出DoesNotExist异常 |
| create |
直接常见一个Model对象 |
| get_or_create |
根据条件查找,没有,就使用create创建 |
| update_or_create |
同get_or_create, 只是用来更新操作 |
| count |
返回QuerySet有多少条数据 |
| latest |
返回最新的一条记录,但是需要在Meta中定义:get_latest_by = <用来排序的字段> |
| earliest |
同上,返回最早的一条数据 |
| first |
从当前QuerySet中获取第一条数据 |
| last |
从当前QuerySet中获取最后一条数据 |
exists |
返回True或False |
| blank_create |
同create,批量创建记录 |
| in_blank |
批量查询,接收两个参数:id_list, filed_name |
| update |
根据条件批量更新记录:Post.object.filter(owner_name=“asd”).update(title=“更新") |
| delete |
同update,根据条件批量删除数据,update和delete都会触发Django的signal |
| values |
当我们明确知道只需要返回某个字段的值:title_list = Post.obnjects.filter(id=1).values(“title”),返回包含dict的QuerySet |
| values_list |
同values, 但直接返回的是包含tuple的QuerySet |
title_list = Post.objects.filter(category_id=1).values_list("title", flat=True)
for title in title_list:
print(title)
进阶接口
- defer:把不需要展示的数据做延迟加载, 比如获取文章除正文外的其他字段:
posts = Post.objects.all().defer('content'), 这样拿到的记录中就不会包含content中的内容
posts = Post.objects.all().defer('content')
for post in posts: # 此时会执行数据库查询
print("post.content") # 此时会执行数据查询, 获取到content
- only: 和defer刚好相反, 如果想只获取title中的值,可以使用only
- select_related: 可以用来处理
一对多的关系
posts = Post.objects.all()
for post in posts: # 产生数据库查询
print(post.owner) # 产生额外的数据库查询
posts = Post.objects.all().select_related('category')
for post in posts: # 产生数据库查询, category数据也会一次性查询出来
print(post.category)
- prefetch_related: 针对
多对多的数据:
posts = Post.objects.all().prefetch_related('tag')
for post in posts: # 产生两条查询语句, 分别查询post 和 tag
print('post.tag.all()')
常用的字段查询
| 字段 |
介绍 |
| contains |
包含, 用来进行相似查询 |
| icontains |
同contains, 只是忽略大小写 |
| exact |
精确匹配 |
| iexact |
同 exact, 只是忽略大小写 |
| in |
指定某个集合: Post.objects.filter(id__in=[1,2])==> |
| gt |
> |
| gte |
>= |
| lt |
< |
| lte |
=< |
| startswith |
以某个字符串开头, |
| istartswith |
同, startswith, 只是忽略带小写 |
| endswith |
以某个字符串结尾, |
| iendswith |
同endswith, 只是忽略大小写 |
| rang |
范围查询, 多用于时间范围, :created_time_range=(“开始时间”, “结束时间”) |
##进阶查询
F: 执行数据库层面的计算, 从而避免出现竞争状态
post = Post.objects.get(id=1)
post.pv = post.pv + 1
post.save()
from django.db.models import F
post = Post.objects.get(id=1)
post.pv = F('pv') + 1
post.save()
Q : 或的关系: select * from tables where id=1 or id =10;
from django.db.models import Q
post = Post.objects.filter(Q(id=1) | Q(id=10))
post = Post.objects.filter(Q(id=1) & Q(id=10))
想得到某个分类下有多少篇文章
category = Category.objects.get(id=1)
posts_count = catecory.posts_count.count()
通过category.post_count访问, 把结果放到category
from django.db.models import Q
# 这相当于是给category动态增加了属性posts_count, (源于Count("post"))
catefories = Category.objects.annotate(post_count = Count("post"))
print(categoies[0].posts_count)
Sum: 同Count类似,aggregate, 只是他是用来做合计的, 比如计算所有文章加起来的访问量是多少:
from django.db.models import Sum
post.objects.aggregate(all_pv=Sum("pv")) # 输出结果: {"all_pv": 487}
评论区