ORM基础(orcad使用基础)
1、 什么吗是ORM
Tips:python也有自带的ORM框架sqlAlchemy。这里主要记录的是django中的ORM技术!
对象关系映射(Object Relational Mapping,简称ORM)模式是一种为了解决面向对象与关系数据库存在的互不匹配的现象的技术。
简单的说,ORM是通过使用描述对象和数据库之间映射的元数据,将程序中的对象自动持久化到关系数据库中。ORM在业务逻辑层和数据库层之间充当了桥梁的作用
2、 ORM的优劣
2.1、ORM的优势
ORM解决的主要问题是对象和关系的映射。它通常把一个类和一个表一一对应,类的每个实例对应表中的一条记录,类的每个属性对应表中的每个字段。
ORM提供了对数据库的映射,不用直接编写SQL代码,只需像操作对象一样从数据库操作数据。让软件开发人员专注于业务逻辑的处理,提高了开发效率。
简而言之如下的好处:
- 简化数据库操作。可以在不同数据库切换而不同修改代码。模型定义自动生成表格查询API事务操作数据库迁移减少sql注入风险测试方面
2.2、ORM的劣势
ORM的缺点是会在一定程度上牺牲程序的执行效率。
ORM用多了SQL语句就不会写了,关系数据库相关技能退化…
2.3、ORM只能映射数据库的表,不可以创建数据库哦
2.3、ORM的queryset语句就是代替sql语句
3、 Model模型中的ORM(创建表)
(3.1)基础单表
from django.db import models
class UserInfo(models.Model):
name = models.CharField(verbose_name="员工名字", max_length=100)
email = models.CharField(verbose_name="账号", max_length=100)
password = models.CharField(verbose_name="密码", max_length=100)
gender_choices = (
(1,'男'),
(2,'女')
)
gender = models.SmallIntegerField(verbose_name="性别",choices=gender_choices,null=True,blank=True)
age = models.IntegerField(verbose_name="年龄",null=True,blank=True)
#数字长度是10,小数点是后俩位,默认是0元,默认是0元
account = models.DecimalField(verbose_name="余额", decimal_places=2, max_digits=10, default=0)
#年月日,可为空,如果null=False , blank=False则是不可以为空,默认是不可以为空
entry_time = models.DateField(verbose_name="入职时间",null=True,blank=True)
# 年月日,时分秒
#auto_now_add大部分情况适用于'创建时间'字段的属性,其会在数据添加的时候,生成数据库系统当前时间
create_time = models.DateTimeField(verbose_name="创建时间", auto_now_add=True)
#大部分情况适用于'更新时间,修改时间'等字段的属性,其会在每次更新数据的时候,生成数据库系统当前时间
update_time = models.DateTimeField(verbose_name='更新时间', auto_now=True)
(3.2)俩表外键
- 表1:
from django.db import models
#部门表
class Department(models.Model):
#AutoField , 自定义逐渐自增id,默认可以不填写自动创建
id = models.BigAutoField(verbose_name="主键ID", primary_key=True)
#CharField类型必须加max_length
title = models.CharField(verbose_name="部门标题", max_length=100)
- 表2:
#员工表
class UserInfo(models.Model):
name = models.CharField(verbose_name="员工名字", max_length=100)
password = models.CharField(verbose_name="密码", max_length=100)
gender_choices = (
(1,'男'),
(2,'女')
)
gender = models.SmallIntegerField(verbose_name="性别",choices=gender_choices)
age = models.IntegerField(verbose_name="年龄")
account = models.DecimalField(verbose_name="余额", decimal_places=2, max_digits=10, default=0)
entry_time = models.DateField(verbose_name="入职时间")
create_time = models.DateTimeField(verbose_name="创建时间", auto_now_add=True)
update_time = models.DateTimeField(verbose_name='更新时间', auto_now=True)
#部门管理主键id,也就是定义外键 ; 名字虽然是depart 但是在mysql表中名字是depart_id,因为django内部帮忙加的_id;
# on_delete=models.CASCADE:级联操作,就是说,如果主键表中被参考字段更新,外键表中也更新,主键表中的记录被删除,外键表中改行也相应删除
# on_delete=models.DO_NOTHING 删除关联数据,什么也不做
# on_delete=models.PROTECT 删除关联数据,引发错误ProtectedError,保护作用,关联的表删除,会提醒不让删除
# on_delete=models.SET_NULL 删除关联数据,与之关联的值设置为null(前提FK字段需要设置为可空,一对一同理),前提是设置可以为空:null=True,blank=True
# on_delete=models.SET_DEFAULT 删除关联数据,与之关联的值设置为默认值(前提FK字段需要设置默认值,一对一同理)
depart = models.ForeignKey(to="Department", to_field='id', on_delete=models.CASCADE)
(3.3)俩表外键
from django.db import models
class ForeignKey(models.Model):
pass
class ForeignMany(models.Model):
pass
class Event(models.Model):
# 布尔型和NullBooleanField有区别,True/False,本类型不允许出现null。
c = models.BooleanField(default=True)
# 可以为null的布尔型
d = models.NullBooleanField(default=True) # 是否显示
# json类型
e = models.JSONField() # 事件明细
# UUID
f = models.UUIDField()
# 小整数 - 32768 ~ 32767
g = models.SmallIntegerField()
# 正小整数 0 ~ 32767
h = models.PositiveSmallIntegerField()
# 整数列(有符号的) -2147483648 ~ 2147483647
i = models.IntegerField()
# 正整数 0 ~ 2147483647
j = models.PositiveIntegerField()
# 长整型(有符号的) -9223372036854775808 ~ 9223372036854775807
k = models.BigIntegerField()
# 长整数,时间间隔,数据库中按照bigint存储,ORM中获取的值为datetime.timedelta类型
l = models.DurationField()
# 浮点型
m = models.FloatField()
# 金额型->100.12
n = models.DecimalField(max_digits=5, decimal_places=2)
# 二进制类型
o = models.BinaryField()
# 一对多
p = models.ForeignKey(to=ForeignKey, # 关联那张表
to_field='project_id', # 关联表的那个字段,可以不指定,不指定就和关联表的主键关联
db_constraint=False, # 是否生成外键约束(默认为True)
related_name="_project_id", # 反向查询名称
on_delete=models.PROTECT, # 关联删除选项
db_column='project_id', # 设置表中的名称
help_text='关联到Event表的project_id', # 说明字段,会显示在admin后台,不会同步到数据库
)
# 一对一,和一对多系统,只是默认加了unique=True
q = models.OneToOneField(to=ForeignKey, # 关联那张表
to_field='project_id', # 关联表的那个字段,可以不指定,不指定就和关联表的主键关联
db_constraint=False, # 是否生成外键约束(默认为True)
related_name="_project_id", # 反向查询名称
on_delete=models.PROTECT, # 关联删除选项
db_column='project_id', # 设置表中的名称
help_text='关联到Event表的project_id', # 说明字段,会显示在admin后台,不会同步到数据库
)
# 多对多
# 手动创建第三张表,虽然可以使用orm的查询方法,但不支持使用add(), set(), remove(), clear()
r = models.ManyToManyField(to='ForeignKey', # 关联那张表,也就是说和那张表关联
through='ForeignMany', # 自定义第三张表,可以不设置,不设置Django就自动生成第三张表
through_fields=('book', 'author') # 自定义第三张表中,那个二个字段管理主表和关联表,可以不设置
)
# 创建时间,创建数据记录的时候会把当前时添加到数据库。
s = models.DateTimeField(auto_now_add=True)
# 修改时间,每次更新数据记录的时候会更新该字段。
t = models.DateTimeField(auto_now=True)
class Meta:
# 模型在数据库中的表名默认是 APP名称_类名,可以通过db_table重新默认值,相当于指定模型在数据库中的表明
db_table = 'project_event'
注意:
(1)如果创建完类后,要执行如下命令在命令端,也就是映射和迁移的过程
python manage.py makemigrations app的名字(app名字可以不写,我基本都写)
python manage.py migrate
如果是在pycharm中,可以点击“工具” --- “运行manage.py任务”,这样就直接省去 python manage.py 了,直接输入 makemigrations app的名字 或 migrate就可以了。(本质上就是pycharm可以帮我们去执行manage.py文件)
(2)如果出现: "No migrations to apply" --- 翻译:没有要应用的迁移
那么就需要将migrations中的文件删除掉,然后在数据库中将表django_migrations中的对应app名字的记录删除掉,然后再执行:python manage.py makemigrations + 执行python manage.py migrate
(3)如果创建的表的话数据库中已经存在,那么就需要进行orm的反向映射,自行百度吧!
(3.4)小总结
1.所有字段都具有的参数
- 1. 更改字段名:db_colum=” “2. 设置主键:primary_key=True,默认为False3. 给字段设置别名(备注):verbose_name=” “4. 字段的唯一键属性:unique=True,设置之后,这个字段的没一条记录的每个值是唯一的5. 允许字段为空:null=True(数据库中字段可以为空),blank=True(网页表单提交内容可以为空),切记不可以将null设置为Fasle的同时还把blank设置为True。会报错的。6. 给字段建立索引:db_index=True7. 在表单中显示说明:help_text=” “8. 字段值不允许更改:editable=False,默认是True,可以更改。
2.个别字段才拥有的参数
- 1. CharField(max_length=100):字段长度为utf8编码的100个字符串2. DateField(unique_for_date=True):这个字段的时间必须唯一3. DateField(auto_now=True):对这条记录内容更新的时间4. DateField(auto_now_add=True):插入这条记录的时间5 .DecimalField(max_digits=4, decimal_places=2):前者表示整数和小数总共多少数,后者表示小数点的位数
3.关系型字段的参数
- on_delelte= 这个参数表示外键所关联的对象被删除的时候要进行什么操作,比如说一篇文章对应一个Python的分类,但是这个分类被你不小心删除了,那么这篇文章的分类应该会发生什么变化呢?主要有以下六种:CASCADE:模拟SQL语言中的ON DELETE CASCADE约束,将定义有外键的模型对象同时删除!(该操作为当前Django版本的默认操作!)PROTECT:阻止上面的删除操作,但是弹出ProtectedError异常SET_NULL:将外键字段设为null,只有当字段设置了null=True时,方可使用该值。SET_DEFAULT:将外键字段设为默认值。只有当字段设置了default参数时,方可使用。DO_NOTHING:什么也不做。SET():设置为一个传递给SET()的值或者一个回调函数的返回值。注意大小写。
4.自关联字段参数
需要在第一个参数中添加‘self’字符串,或写上它自己的表名(模型类名)。
5.关系字段
关系字段用于保存数据表之间的关系,包括ForeignKey, ManyToManyField等。
1、ForeignKey
ForeignKey(ForeignObject) # ForeignObject(RelatedField)
to, # 要进行关联的表名
to_field=None, # 要关联的表中的字段名称
on_delete=None, # 当删除关联表中的数据时,当前表与其关联的行的行为
- models.CASCADE,删除关联数据,与之关联也删除
- models.DO_NOTHING,删除关联数据,引发错误IntegrityError
- models.PROTECT,删除关联数据,引发错误ProtectedError
- models.SET_NULL,删除关联数据,与之关联的值设置为null(前提FK字段需要设置为可空)
- models.SET_DEFAULT,删除关联数据,与之关联的值设置为默认值(前提FK字段需要设置默认值)
- models.SET,删除关联数据,
a. 与之关联的值设置为指定值,设置:models.SET(值)
b. 与之关联的值设置为可执行对象的返回值,设置:models.SET(可执行对象)
def func():
return 10
class MyModel(models.Model):
user = models.ForeignKey(
to="User",
to_field="id"
on_delete=models.SET(func),)
related_name=None, # 反向操作时,使用的字段名,用于代替 【表名_set】 如: obj.表名_set.all()
related_query_name=None, # 反向操作时,使用的连接前缀,用于替换【表名】 如: models.UserGroup.objects.filter(表名__字段名=1).values('表名__字段名')
limit_choices_to=None, # 在Admin或ModelForm中显示关联数据时,提供的条件:
# 如:
- limit_choices_to={'nid__gt': 5}
- limit_choices_to=lambda : {'nid__gt': 5}
from django.db.models import Q
- limit_choices_to=Q(nid__gt=10)
- limit_choices_to=Q(nid=8) | Q(nid__gt=10)
- limit_choices_to=lambda : Q(Q(nid=8) | Q(nid__gt=10)) & Q(caption='root')
db_constraint=True # 是否在数据库中创建外键约束
parent_link=False # 在Admin中是否显示关联数据
2、OneToOneField
OneToOneField(ForeignKey)
to, # 要进行关联的表名
to_field=None # 要关联的表中的字段名称
on_delete=None, # 当删除关联表中的数据时,当前表与其关联的行的行为
###### 对于一对一 ######
# 1. 一对一其实就是 一对多 + 唯一索引
# 2.当两个类之间有继承关系时,默认会创建一个一对一字段
# 如下会在A表中额外增加一个c_ptr_id列且唯一:
class C(models.Model):
nid = models.AutoField(primary_key=True)
part = models.CharField(max_length=12)
class A(C):
id = models.AutoField(primary_key=True)
code = models.CharField(max_length=1)
3、ManyToManyField
ManyToManyField(RelatedField)
to, # 要进行关联的表名
related_name=None, # 反向操作时,使用的字段名,用于代替 【表名_set】 如: obj.表名_set.all()
related_query_name=None, # 反向操作时,使用的连接前缀,用于替换【表名】 如: models.UserGroup.objects.filter(表名__字段名=1).values('表名__字段名')
limit_choices_to=None, # 在Admin或ModelForm中显示关联数据时,提供的条件:
# 如:
- limit_choices_to={'nid__gt': 5}
- limit_choices_to=lambda : {'nid__gt': 5}
from django.db.models import Q
- limit_choices_to=Q(nid__gt=10)
- limit_choices_to=Q(nid=8) | Q(nid__gt=10)
- limit_choices_to=lambda : Q(Q(nid=8) | Q(nid__gt=10)) & Q(caption='root')
symmetrical=None, # 仅用于多对多自关联时,symmetrical用于指定内部是否创建反向操作的字段
# 做如下操作时,不同的symmetrical会有不同的可选字段
models.BB.objects.filter(...)
# 可选字段有:code, id, m1
class BB(models.Model):
code = models.CharField(max_length=12)
m1 = models.ManyToManyField('self',symmetrical=True)
# 可选字段有: bb, code, id, m1
class BB(models.Model):
code = models.CharField(max_length=12)
m1 = models.ManyToManyField('self',symmetrical=False)
through=None, # 自定义第三张表时,使用字段用于指定关系表
through_fields=None, # 自定义第三张表时,使用字段用于指定关系表中那些字段做多对多关系表
from django.db import models
class Person(models.Model):
name = models.CharField(max_length=50)
class Group(models.Model):
name = models.CharField(max_length=128)
members = models.ManyToManyField(
Person,
through='Membership',
through_fields=('group', 'person'),
)
class Membership(models.Model):
group = models.ForeignKey(Group, on_delete=models.CASCADE)
person = models.ForeignKey(Person, on_delete=models.CASCADE)
inviter = models.ForeignKey(
Person,
on_delete=models.CASCADE,
related_name="membership_invites",
)
invite_reason = models.CharField(max_length=64)
db_constraint=True, # 是否在数据库中创建外键约束
db_table=None, # 默认创建第三张表时,数据库中表的名称
4、 数据库Meta元信息
class UserInfo(models.Model):
nid = models.AutoField(primary_key=True)
username = models.CharField(max_length=32)
class Meta:
# 数据库中生成的表名称 默认 app名称 + 下划线 + 类名
db_table = "table_name"
# 联合索引
index_together = [
("pub_date", "deadline"),
]
# 联合唯一索引
unique_together = (("driver", "restaurant"),)
# admin中显示的表名称
verbose_name
# verbose_name加s
verbose_name_plural