5.Model层
1.ORM 简介
- ORM是MVC 框架中包括一个重要的部分,
- 它实现了数据模型与数据库的解耦,即数据模型的设计不需要依赖于特定的数据库,通过简单的配置就可以轻松更换数据库,这极大的减轻了开发人员的工作量,不需要面对因数据库变更而导致的无效劳动
- ORM 是 “对象 - 关系 - 映射” 的简称。
2.创建数据模型
1.创建名为 book 的 app,在 book下的 models.py 中创建模型:
from django.db import models
# Create your models here.
class Book(models.Model):
#创建的主键列属性为id,可以使用pk代替,pk全拼为primary key
id=models.AutoField(primary_key=True)
title=models.CharField(max_length=32)
state=models.BooleanField()
pub_date=models.DateField()
price=models.DecimalField(max_digits=8,decimal_places=2)
publish=models.CharField(max_length=32)
class Meta:
#自定义表名,Django默认以 小写app应用名_小写模型类 名为数据库表名。
db_table="my_book"
#让id和title这个组合变得唯一
#Django2.2之前
unique_together=('id','title')
#Django2.2之后
constraints=[
models.UniqueConstraint(fields=['id','title'],name='unique_user'),
#增加对书籍出版日期的约束,必须小于当前时间
models.CheckConstraint(check=models.Q(pub_date__gte=datatime.now()),name="time_gte_now")
]
注意:
1.字段名不允许使用连续的下划线,因为字段名称和比较运算符间使用两个下划线
1.字段类型
类型 | 举例 |
---|---|
AutoField | models.AutoField(primary_key=True) |
BooleanField | models.BooleanField(default=True) |
CharField | models.CharField(max_length=512, verbose_name="评论内容") |
TextField | models.TextField() |
DecimalField | models.DecimalField(max_digits=5,decimal_places=2) |
FloatField | models.FloatField() |
DateField | 在 Python 中用一个 datetime.date 实例表示 |
TimeField | 在 Python 中用 datetime.time 实例表示 |
DateTimeField | 在 Python 中用一个 datetime.datetime 实例表示 |
注意
1.
FloatField
内部使用 Python 的float
类型,而DecimalField
则使用 Python 的Decimal
类型2.DateField,TimeField, DateTimeField拥有相同的参数auto_now,auto_now_add
2.字段选项
选项 | 说明 |
---|---|
null | 默认值是False,数据库中存储不允许输入空值 |
blank | 默认值是False,表单验证不允许输入空值 |
db_column | 字这个字段要使用的数据库列名.如果没有给出列名,Django 将使用字段名 |
db_index | 默认值是False, 不会在表中为此字段创建索引 |
default | 字段的默认值 |
primary_key | 若为True,则该字段会成为模型的主键字段,默认值是False |
unique | 如果为True, 这个字段在表中必须有唯一值,默认值是False |
choices | 由二元组组成的一个可迭代对象(例如,列表或元组),用来给字段提供选择项. 如果设置了choices ,默认的表单将是一个选择框而不是标准的文本框,而且这个选择框的选项就是choices 中的选项。 |
verbose_name | 给字段起别名,默认Django会将字段的属性名自动创建,并将下划线转换成空格 |
on_delete | models.CASCADE(表示级联),models.SET_NULL(表示非级联) |
3.配置数据库
1.若想将模型转为 mysql 数据库中的表,需要在 settings.py中配置:
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.mysql',
'NAME':'orm', # 要连接的数据库,连接前需要创建好
'USER':'root', # 连接数据库的用户名
'PASSWORD':'', # 连接数据库的密码
'HOST':'127.0.0.1', # 连接主机,默认本级
'PORT':3306 # 端口 默认3306
}
}
2.确保配置文件中的 INSTALLED_APPS 中写入我们创建的 app 名称
INSTALLED_APPS = [
'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
"book"
]
3.最后通过两条数据库迁移命令即可在指定的数据库中创建表 :
# 数据库的迁移
python manage.py makemigrations
python manage.py migrate
# 迁移的回退
python manage.py migrate app的名称 aap中migrations中相应的迁移文件名
# 注意:之后别忘了手动删除 migrations 目录中的 0004 号迁移文件,从而完成回退动作
4.如果想打印 orm 转换过程中的 sql,需要在 settings 中进行如下配置:
LOGGING = {
'version': 1,
'disable_existing_loggers': False,
'handlers': {
'console':{
'level':'DEBUG',
'class':'logging.StreamHandler',
},
},
'loggers': {
'django.db.backends': {
'handlers': ['console'],
'propagate': True,
'level':'DEBUG',
},
}
}
问题1
启动项目报错:no module named MySQLdb 或者 Error loading MySQLdb module
import pymsql
pymsql.install_as_MySQLdb()
问题2
django.core.exceptions.ImproperlyConfigured: mysqlclient 1.4.0 or newer is required; you have 0.10.0
import pymsql
pymysql.version_info=(1,4,13,"final",0)
pymsql.install_as_MySQLdb()
原因分析:
MySQLclient目前只支持到 python3.4,因此如果使用的更高版本的 python,需要修改如下:通过查找路径
\site-packages\Django-2.0-py3.6.egg\django\db\backends\mysql 这个路径里的文件把注释掉就OK了
if version < (1, 3, 3):
raise ImproperlyConfigured("mysqlclient 1.3.3 or newer is required; you have %s" % Database.__version__)
4.单表增删改查
1.添加表纪录
book_obj=Book.objects.create(title="python葵花宝典",state=True,price=100,publish="苹果出版社",pub_date="2012-12-12")
2.删除表纪录
#使用delete()可以一次性删除多个对象,没有返回任何值
Blog.objects.filter(pk=1).delete()
注意
在 Django 删除对象时,会模仿 SQL约束ON DELETE CASCADE 的行为,换句话说,删除一个对象时也会删除与它相关联的外键对象.如果不想级联删除,可以将ForeignKey设置为:on_delete=models.SET_NULL
3.修改表纪录
#update()可以同时更新多条记录,返回一个整型数值,表示受影响的记录条数
Book.objects.filter(title__startswith="py").update(price=120)
4.查询表纪录
1.基本查询
方法 | 调用 |
---|---|
all | Book.objects.all() |
get | Book.objects.get(id=1) |
count | Book.objects.count() |
2.过滤查询
语法
Book.objects.filter(属性名称____过滤符=值)
名称 | 举例 |
---|---|
exact | id__exact=1 |
contains | title__contains=“python” |
startswith | title__startswith=“p” |
endswith | title__startswith=“典” |
isnull | title__isnull=“True” |
in | id__in=[1,2,3] |
gt,gte,lt,lte | id_gt=1 |
year,month,day,week_day,hour,minute,second | pub_date__year=1980 |
range | price_range=[100,200] |
3.extra方法
1.select提供简单数据
SELECT age, (age > 18) as is_adult FROM myapp_person;
Person.objects.all().extra(select={'is_adult': "age > 18"})
2.where提供查询条件
SELECT * FROM myapp_person WHERE first||last ILIKE 'jeffrey%';
Person.objects.all().extra(where=["first||last ILIKE 'jeffrey%'"])
3.table连接其它表
SELECT * FROM myapp_book, myapp_person WHERE last = author_last
Book.objects.all().extra(table=['myapp_person'], where=['last = author_last'])
4.params添参数
# 如果first_name中有SQL特定字符就会出现漏洞
first_name = 'Joe'
# 错误方法
Person.objects.all().extra(where=["first = '%s'" % first_name])
# 正确方法
Person.objects.all().extra(where=["first = '%s'"], params=[first_name])
5.select高级查询
#相关子查询,而且只能select一个值(a.id),否则报错:当没有用 EXISTS 引入子查询时,在选择列表中只能指定一个表达式
InnerMail.objects.extra(select={'status':'select a.id from letter_imail_status a where a.id=letter_innermail.id'})
def extra(self, select=None, where=None, params=None, tables=None,
order_by=None, select_params=None):
"""
Adds extra SQL fragments to the query.
"""
assert self.query.can_filter(), \
"Cannot change a query once a slice has been taken"
clone = self._clone()
clone.query.add_extra(select, select_params, where, params, tables, order_by)
return clone
5.其他操作
操作名称 | 关键字 | 举例 |
---|---|---|
切片 | first(): | articles = Article.objects.filter(created__year=2021).first() |
last(): | articles = Article.objects.filter(created__year=2021).last() | |
[:5] | articles = Article.objects.filter(created__year=2021)[:5] | |
排序 | order_by(字段名) | |
reverse(字段名) | ||
去重 | distinct() | Article.objects.filter(title__icontains=‘python’).distinct() |
exists() | Book.objects.all().exists() |
5.问题
jinja2模板中怎样使用csrf_token 值
<input type="hidden" name="csrfmiddlewaretoken" value="{{ csrf_token }}">
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 开发者必知的日志记录最佳实践
· SQL Server 2025 AI相关能力初探
· Linux系列:如何用 C#调用 C方法造成内存泄露
· AI与.NET技术实操系列(二):开始使用ML.NET
· 记一次.NET内存居高不下排查解决与启示
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· 没有Manus邀请码?试试免邀请码的MGX或者开源的OpenManus吧
· 园子的第一款AI主题卫衣上架——"HELLO! HOW CAN I ASSIST YOU TODAY
· 【自荐】一款简洁、开源的在线白板工具 Drawnix