Django model 使用
环境信息
- Python 3.10
- Django 4.1
在 Project/App 的 models.py
文件中创建 model
,当 model 定义完成,Django 会自动生产一个后台管理接口,允许认证用户添加、更改和删除对象,只需在管理站点上注册模型即可 [1]
创建 model
在 Project/App 的 models.py
文件中创建 model
from django.db import models |
对修改后的 model
进行 migrate
,以使在数据库中变更更改。
python manage.py makemigrations |
model 注册到后台
在 Project/App 的 admin.py
文件中注册 model
from django.contrib import admin |
更多有关 admin 配置方法,请参考 Django admin 配置
model 基本操作
增
假设 model 为 Publish
,新增数据 [2]
create 方式新增数据
Publish.objects.create("name"="人民出版社",city="北京") |
save 方式新增数据
book1=Book(title="python",price="88",publish_id="1",publication_date="2017-06-18") |
为了避免重复创建数据表中已存在的条目,Django 还提供了 get_or_create
方法。它会返回查询到的或新建的模型对象实例,还会返回这个对象实例是否是刚刚创建的。
obj, created = Article.objects.get_or_create(title="My first article", body="My first article body") |
update_or_create 方式更新或者添加数据
update_or_create
是使用给定的 kwargs
更新对象的一种方便方法,必要时创建一个新对象。defaults
是用来更新对象的 (field, value)
对的字典。defaults
中的值可以是可调用对象。
返回 (object, created)
的元组,其中 object
是创建或更新的对象,created
是一个布尔值,指定是否创建了一个新对象。 [3]
obj, created = models.RawDomains.objects.update_or_create(id=id, domain=domain, defaults=d) |
以上示例中,先使用 id=id, domain=domain
的条件查询(筛选)数据,如果筛选出 1 条数据,则对此数据使用 defaults
中定义的对象进行更新,如果没有筛选出数据,则创建数据。
存在 Foreignkey 的表新增数据
通过绑定对象的方式新增
获取出版社对象 |
直接通过 Foreignkey 对应记录的 id 号新增数据
直接把出版社的id号插入到书籍的记录中 |
ManyToManyField 的表新增数据
为一本书添加多个作者
author1=Author.objects.get(id=1) # 获取id号为1的作者对象 |
也可以使用以下方法
book1.authors.add(*[author1,author2]) # 为书籍对象添加作者对象的列表 |
为一个作者添加多本书
author_obj = Author.objects.filter(name="jerry") # 获取名字为"jerry"的作者对象 |
删
Book.objects.filter(id=1).delete() |
改
使用 save 方法将所有属性重新设定一遍,效率较低
author1=Author.objects.get(id=3) # 获取id为3的作者对象 |
使用 update 方法直接设置对应的属性
Publish.objects.filter(id=2).update(name="北京出版社") |
update()
是QuerySet
对象的一个方法,get
返回的是一个 model 对象,其没有update
方法
查
查询数据使用 QuerySet
API。 QuerySet
是惰性执行的,创建 Query Set
不会访问数据库,只有在访问具体查询结果的时候才会访问数据库。
查询方法
方法 | 方法说明 | 举例 |
---|---|---|
filter(**kwargs) |
包含了与所给筛选条件相匹配的对象,返回 QuerySet ,相当于 SQL 中的 WHERE |
|
all() |
查询所有结果 ,等同于 SQL 语句 SELECT * FROM |
|
get(**kwargs) |
返回与所给筛选条件相匹配的对象,返回结果有且只有一个,如果符合筛选条件的对象超过一个或者没有都是报错 | |
values(*field) |
只取指定列 ,返回 QuerySet ,此列表由字典 {'列名': '列值'} 组成 |
models.AwsZoneInfo.objects.all().values('code') |
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 查询 |
values(*field) 和 values_list(*field) 使用示例
values(*field)
获取 QuerySet 中指定列的值,会返回一个由字典 {'列名1': '列值1', '列名2': '列值2', ...}
组成的 QuerySet
>> models.AwsZoneInfo.objects.all().values('code') |
values_list(*field)
获取 QuerySet 中指定列的值,会返回一个由元组 ('列值1', '列值2', ...)
组成的 QuerySet
>> models.AwsZoneInfo.objects.all().values_list('code','name') |
model 类型使用说明
OneToOneField
一对一表中,子表从母表中选出一条数据一一对应,母表中选出来一条就少一条,子表不可以再选择母表中已被选择的那条数据 [4]
常见用法
示例如下:
from django.db import models |
User 实例中使用 Profile 实例的属性
假如需要在 User 对象中,调用和 User 实例关联的 Profile 对象的属性,可以通过以下方法实现
user = User.objects.get(id=1) |
需要注意的是,如果 user
没有与之关联的 Profile
实例,那么 user
就没有 profile
属性,上述代码会报错:models.User.profile.RelatedObjectDoesNotExist: User has no profile
可以通过以下方式处理异常 [5]
user = User.objects.get(id=1) |
父表插入记录后,子表自动插入相关联的记录
实例代码如下:
域名信息 |
为了在 Django 中实现 RawDomains
新增记录后,DomainProjectInfo
自动关联对应条目的需求,可以使用 Django 的信号机制。具体来说,可以监听 RawDomains
模型的 post_save
信号,每当有新的 RawDomains
记录被保存后,自动创建一个对应的 DomainProjectInfo
记录并建立关联。
以下是具体实现步骤:
定义信号接收器
首先,在你的应用中创建一个新的文件
signals.py
(如果还没有的话),在这个文件中定义一个函数来作为信号的接收器。这个函数将在RawDomains
记录被成功创建或保存后被自动调用。from django.db.models.signals import post_save
from django.dispatch import receiver
from .models import RawDomains, DomainProjectInfo, Project
@receiver(post_save, sender=RawDomains)
def create_domain_project_info(sender, instance, created, **kwargs):
if created: # 检查是不是新创建的记录
# 这里你可以根据需要来设定默认值,比如默认的项目ID
default_project_id = 234 # 假设已存在的默认项目ID
DomainProjectInfo.objects.create(
domain=instance,
project_id=default_project_id,
type_id=3, # 示例默认值,根据实际情况调整
status_id=5,
)这个信号接收器会在每次
RawDomains
模型的post_save
事件发生时被调用。如果是新创建的RawDomains
记录(created=True
),它会自动创建一个对应的DomainProjectInfo
实例,并设置一些默认值。确保信号被正确连接
为了确保你的信号接收器被正确地挂接,你需要在应用的配置类中导入这些信号。修改你应用的
apps.py
文件,确保ready
方法如下所示:from django.apps import AppConfig
class YourAppNameConfig(AppConfig):
name = 'your_app_name' # 请确保这里使用你的实际应用名称
verbose_name = '你的应用的可读名称'
def ready(self):
import your_app_name.signals # 替换your_app_name为你的应用的实际名称
完成以上步骤后,每当 RawDomains
模型添加新记录时,Django 会自动创建一个相关联的 DomainProjectInfo
记录。根据你的具体模型字段和逻辑需要调整示例代码中的默认值设置。
可选择的字段
要定义在给定选项中选择值的字段,可以通过在模型类中使用 choices
参数来配置可选字段。choices
参数需要传递一个元组的列表,其中每个元组表示一个可选择的选项。每个元组由 2 个值组成,第一个值是数据库中存储的值,第二个是在表单中显示的标签。
class Mymodel(models.Model): |
查询给定的 QuerySet 是否属于某个 model
在 Django 中,可以使用以下方法来检查一个 QuerySet
是否是特定 model 的实例
queryset.model == models.Mymodel |
如果对象 queryset
中的所有对象都是 Mymodel
的实例,返回 True
。如果 queryset
中有任何一个对象不是 Mymodel
的实例,返回 False
字符串格式的 QuerySet 转换为 QuerySet 对象
假如有以下字符串,内容和 QuerySet 内容一致,只是类型为字符串
queryset_string |
要将示例中的 queryset_string
类型从 str
转换为 QuerySet
对象,主要步骤如下
import re |
手动执行 migrate
有时候使用 python manage.py migrate
执行数据库迁移会出错,可能需要重建数据库重新执行 migrate 操作,在不方便如此做的情况下,可以选择手动执行迁移操作。
使用以下命令,根据想要迁移的文件生成实际在数据库中执行的 sql 语句。命令中
0008_table_alter
为要迁移的文件名(不用带完整路径(myapp_name/migrations/
) 和文件名后缀(.py
)),否则会报错:CommandError: Cannot find a migration matching 'myapp_name/migrations/0008_table_alter.py' from app 'myapp_name'. Is it in INSTALLED_APPS?
python manage.py sqlmigrate myapp_name 0008_table_alter
--
-- Create model Domain
--
CREATE TABLE `myapp_name_domain` (`id` bigint AUTO_INCREMENT NOT NULL PRIMARY KEY, `name` varchar(10) NOT NULL UNIQUE);
--
-- Alter field owner on domainproject
--
--
-- Add field usage to domainproject
--
ALTER TABLE `myapp_name_domainproject` ADD COLUMN `usage_id` bigint DEFAULT 1 NOT NULL , ADD CONSTRAINT `myapp_name_doma_usage_id_43803979_fk_domains_c` FOREIGN KEY (`usage_id`) REFERENCES `myapp_name_domainusage`(`id`);
ALTER TABLE `myapp_name_domainproject` ALTER COLUMN `usage_id` DROP DEFAULT;在数据库中执行打印出的 sql
常见错误
str returned non-string
后台添加对象失败,原因说明
remaining elements truncated
django.db.models.query.QuerySet
类型的对象,长度超过 20 时,20 个之后的内容会显示为 remaining elements truncated
,如果值变为了字符串类型,最后一项默认变成了 remaining elements truncated
。因此在 django.db.models.query.QuerySet
类型或类似类型的数据会转为 str
的场景下下,要将其处理成 list
类型
脚注
- 1.设计模型 ↩
- 2.执行查询 ↩
- 3.update_or_create ↩
- 4.一对一关联 ↩
- 5.RelatedObjectDoesNotExist ↩