官网位置:
字段类型
不同的字段类型,同步到数据库中就是不同的数据类型,且能通过新增或编辑时,可通过clean_fields()自查
BooleanField
—代表True(1) 或者 False (0)- 参数有default
- 数据库中存的是1 和0
IntegerField
--整形 对应mysql 为intBigIntField
— 长的数字,如电话号码那么长DecimalField
—类似python中的浮点型AutoField
–自增如果没有指定主键primary_key=True,django会自动写一个如下,所以自己也可以重新命名一个自增id id = models.AutoField(max_length=191, primary_key=True)
CharField
在mysql中对应是 varchar,所以要指定长度 name= models.CharField(max_length=200)
TextField
– 和上类似,比如的文件,考虑存在其他地方,这里存路径,如图片常存的是urlEmailField
在数据库里也是varchar,同时,django还提供了对email的校验和约束
DateField
DateTimeField
—常用- auto_now_add
- auto_now
create_time = models.DateTimeField(auto_now_add=True) 表示创建时,会更新这个时间 update_time = models.DateTimeField(auto_now=True) 表示更新时,会更新这个时间
字段约束/选项
除了以上已经介绍的primary_key ,时间类型的 auto_now_add 和 auto_now,还有
null
默认为False, 如果为True, 当前字段可以为NULL. ,python中可以写字段=None
blank
代表空白字符`""`, 默认为False, 如果是True, 允许不传,会默认存 空字符串
unique
默认为False, 如果为True, 重复记录会报错
default
db_column
用来定义该字段在数据库里的字段名如 student_id = models.AutoField(primary_key=True, db_column="id"),在数据库里的字段不是sudent_id
命令的调试
如在同步数据库(生成迁移文件,执行迁移时),报错,但又不知道具体原因
python manage.py makemigrations
python manage.py migrate
- 修改manage.py进行debug调试;先打印下参数是什么,然后写成固定的参数,然后再manage.py中debug方式运行
print(sys.argv) # sys.argv = ['manage.py', 'migrate'] execute_from_command_line(sys.argv)
修复migrations
- 更改
migrations
中的文件解决问题;- 执行
python manage.py migrate
命令其实是按顺序执行未同步的migrations.如:案例中第一个迁移文件中是('name', models.CharField(max_length=200)), 生成了第二个正确的迁移文件中是('name', models.CharField(max_length=191)), 但迁移时,执行第一个文件时仍然报错,所以还是要直接改迁移文件,而不是生成迁移文件
- 执行
- 直接删除
migrations
文件推倒重来django
会在数据表django_migrations
中创建同步记录- 删除对应的同步记录
- 如果有创建表的记录, 需要删除表
内嵌类Meta
通过一个内嵌类Meta来定义元数据, 元数据又被称为中介数据, 用于描述数据得数据.
简单地讲, Meta就是通过属性来描述model对象, 为其提供额外得功能.
-
abstract
将当前模型类转换成抽象类, 当进行migrate的时候会被忽略.
因为migrate是对实体表进行修改, 而抽象是一个虚的概念, 所以不存在实体.
如下:同步数据库时,不会生成这个表class Person(models.Model): name = models.CharField(max_length=191) email = models.EmailField() update_time = models.DateTimeField(auto_now=True) create_time = models.DateTimeField(auto_now_add=True) null_test = models.CharField(max_length=200, null=True) blank_test = models.CharField(max_length=200, blank=True) class Meta: abstract = True
-
app_label
指定当前model从属于哪个已经注册的应用
使用场景一般为应用只编写视图层来处理业务逻辑. 模型层统一由一个models模块来管理, 所以要区分所属应用
-
db_table
自定义表名, 如果不指定表名则默认为
应用名_模型名
-
managed
默认为True, 如果为False, 当前migrate会忽略该模型.
- 虽然设置了managed为False, 但是如果没有主键的化, 依然会自动创建主键.
很多公司都会由专人DBA来管理数据库.
独立开发流程: 创建模型-> migrate
公司合作开发流程: dba建表->创建模型
-
ordering
设置排序字段, 默认排序规则为升序
-
-
表示降序ordering = ['-order_date'] ordering = ['-pub_date', 'author']
-
?
表示随机的意思ordering = ['?']
-
-
get_lastest_by
设置获取最后一条记录的排序规则
如 指定为get_latest_by 如get_latest_by=[“id”]
在orm操作中,reader.objects.latest() 获取的最后一个,就是id的最后一个 -
indexes
设置索引
class Meta: indexes = [ models.Index(fields=['last_name', 'first_name']), models.Index(fields=['first_name'], name='first_name_idx'), ]
-
unique_together
多字段唯一性约束
unique_together = ("driver", "restaurant")
模型继承
一个模型可以继承于另外两个模型,要注意,如果两个父模型有冲突字段,建议直接子模型中重新定义一个
class BorrowRecord(Student, Book):
pass
一些实例方法
-
自定义输出实例,可以定义
__str__方法
def __str__(self): return f"id:{self.id}, {self.question_text}"
-
刷新当前记录
.refresh_from_db()
refresh_from_db
-
字段自验证
.clean_fields()
新增或者更新时用比如EmailField调用clean_fields会验证当前格式是否正确
如果某个字段不自检,就这么写 reader.clean_fields(exclude=['字段名1'])
-
字段唯一性验证
.validate_unique()
,新增或更新时用,比如字段有1.可以所有单个字段,如一个字段有unique=True, 新增或编辑时重复了,就会提示already exists 但其实即使不校验也能新增成功 2. 还能校验组合唯一性(其实是用在这个地方) # 在meta中设置唯一性字段 unique_together = ['name', 'email'] #表示不能有 name 和email 都一样的 如果新增的都一样了,加上下面这句话,就会保存不成功了(感觉不要exclude排除参数也行) reader.validate_unique(exclude=['null_test', 'create_time', 'update_time', 'id'])
django.setup() 初始化一个django环境,便于orm操作练习
原始的是在控制台中console中输入python manage.py shell ,然后再执行orm操作
现在可以这么写,我是新建一个test文件夹,然后新建一个py文件,名字随便写
import os
import random
import django
if __name__ == "__main__":
# 设置环境变量
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "mysite.settings") # mysite表示项目名字
django.setup()
from myblog.models import Reader
print(Reader.objects.all())
- 除了把命令写在main中,也可以在上面封装函数,然后main里面调用
- debug运行时的知识点扩展
-
还可以通过debug的方式运行,然后在控制台console中里面也能运行命令如.objects.all()
-
右键选择evaluate express 也能进行执行,或者输入一个变量
-
django自带的单元测试 TestCase
- 在每个应用下有一个自带的tests,新建一个类继续TestCase(继承了uinttest的)
- 方法命名时,要已test开头
- 运行
- python manage.py test
- python manage.py test sign # 指定应用
- python manage.py test sign.tests.*** # 指定应用下的test.py文件 的 类名为** 的
- 效果:不会在数据库里操作
from django.test import TestCase
from myblog.models import Reader
# Create your tests here.
class ReaderTest(TestCase):
def setUp(self) -> None:
Reader.objects.create(name="猪", email="taoke@qq.com")
def test_create_reader(self):
Reader.objects.create(name="狗", email="taoke@qq.com")
QuerySet—CRUD
Create
和update ,都是用save()
reader = Reader(
name='值',
email=f'值',
int_test=5
)
reader.save()
Create方式2
或者使用 模型名称.objects.create(**kws)
Reader.objects.create(name="haha",email="taoke@qq.com")
-
Retrieve
(查询)Django的
orm
时一条执行链, 而不是单个语句Reader.objects.all().filter(id__gt=300).order_by("name", "id")
orm尽量使用一些简单的接口
如果查询需求比较复杂, 尽量使用SQL
-
all()—获取的是QuerySet 列表
获取表中所有记录
如果表非常大, 一定要小心使用.
-
get()
通过指定条件, 获取一条数据, 如果有多条, 则会报错
Reader.objects.get(name="name_99") 或者 pk=1 查询的是唯一不会报错,
reader = Reader.objects.get(name="name_0") # 查询的不是唯一会报错
-
filter()—获取的是querySet 列表
匹配满足条件的记录, 类似于
SQL
中的WHERE
语句reader_array = Reader.objects.filter(name="name_0")
-
比较
Reader.objects.filter(id__gte=300)
>=
-----gte
>
--------gt
<=
-------lte
<
--------lt
-
模糊匹配
类似于
WHERE 字段 LIKE '%xx%'
__startswith
__endswith
__icontains
-
-
exlude
与
filter
逻辑取反 -
限制返回的记录数
相当于
SQL
中的limit
reader_array[:5] 但是查询逻辑不是limit那样只会查到前面,
-
latest()
# 需要在models, Meta中指定get_latest_by 如get_latest_by=["id"],如果不指定,调方法时会报错 Reader.objects.latest()
-
order_by 排序
Reader.objects.all().order_by("name", "id")
-
-
Update
-
save
reader.email = "test@163.com" reader.save()
-
-
Delete
如果想对整张表进行清除, 还是truncate table命令更快
-
delete
reader.delete()
-
高级
-
RAW
遇到复杂的场景, 需要使用
SQL
语句通过Reader._meta.db_table来获取记录所在表
queryset = Reader.objects.raw(f"select * from {Reader._meta.db_table} limit 1") list(queryset)
-
指定数据库
-
在settings配置该数据库,
DATABASES = { 'default': { 'ENGINE': 'django.db.backends.mysql', 'NAME': 'polls', 'USER': 'root', 'PASSWORD': 'qwe369', 'HOST': '127.0.0.1', 'PORT': '3306' }, 'person': { 'ENGINE': 'django.db.backends.mysql', 'NAME': 'person', 'USER': 'root', 'PASSWORD': 'qwe369', 'HOST': '127.0.0.1', 'PORT': '3306' } }
-
使用参数using
新增或更新时:reader.save(using='person')
查询时:Reader.objects.using('person').all()
-
-
事务
-
基于HTTP请求的事务
- 在
settings
中要设置ATOMIC_REQUESTS
为True
from django.db import transaction @transaction.atomic def my_view(request): 表达式...
- 在
-
基于视图具体逻辑的事务
from django.db import transaction def viewfunc(request): 表达式 with transaction.atomic(): 表达式A 表达式B ...
-