ORM模型介绍
原生SQL语句的不足
随着项目越来越大,若在代码中采用大量的SQL语句,那么就会出现如下问题:
- SQL语句重复利用率不高,越复杂的SQL语句条件越多,代码越长,且会出现很多相近的SQL语句。
- 很多SQL语句是在业务逻辑中拼出来的,若有数据库需要更改,就要去修改这些逻辑,这容易造成手工疏忽。
- 写SQL时容易忽略web安全问题,给未来造成隐患。如下为SQL语句注入:
```python select * from user where username = ‘juran’#’ and password = ‘’
select * from user where username = ‘juran’— ‘ and password = ‘’
select * from sqldb_book where id = -1 or 1=1
<a name="QfCM4"></a>
### ORM简介
ORM,全称Object Relational Mapping(对象关系映射),通过实例化对象的方法,完成关系型数据库的操作的技术,即ORM可以通过类的方式去操作数据库,不用再写原生的SQL语句,而是通过把表映射成类,把字段作为属性。<br />ORM在执行对象操作时,最终还是会把对应的操作转换为数据库原生语句。
- 数据库的表(table) --> 类(class)
- 记录(record,行数据)--> 对象(object)
- 字段(field)--> 对象的属性(attribute)
```python
"""models.py"""
from django.db import models
from datetime import datetime
# 创建一个模型,其对应数据库中的一张表
class Book(models.Model):
id = models.AutoField(primary_key=True)
name = models.CharField(max_length=20, null=False)
author = models.CharField(max_length=100)
price = models.FloatField()
add_time = models.DateTimeField(default=datetime.now)
"""views.py"""
# 一个模型的对象,对应数据库表中的一条数据
book = Book(name="Python",author='龟叔',price=89)
# 保存数据:save方法
book.save()
# 删除数据:delete方法
book.delete()
创建ORM模型
ORM模型一般都是放在app的 models.py
文件中。如果这个app的模型想要映射到数据库中,那么该app的名称,必须要放在 settings.py
的 INSTALLED_APP
中进行安装。
以下是写一个简单的书籍ORM模型。
from django.db import models
from datetime import datetime
class Book(models.Model):
id = models.AutoField(primary_key=True) # 主键id可省略,其会自动被创建
name = models.CharField(max_length=20, null=False)
author = models.CharField(max_length=20, null=False)
add_time = models.DateTimeField(default=datetime.now)
price = models.FloatField(default=0)
- 这个模型继承自
django.db.models.Model
,如果这个模型想要映射到数据库中,就必须继承自这个类。 - 在django中,若模型中未定义主键,那么django中会自动生成一个自动增长的int类型,名为id的主键。
- 表的名称格式:app名称_模型名称(小写形式)
- 类中定义的一个类属性,对应数据库中的一个字段,同时可以设置字段的数据类型和约束。
- 常见数据类型有:AutoField、CharField、DateTimeField、FloatField、IntegerField等
- 常见约束有:primary_key 主键、null 非空、default 默认值等
常见的字段类型
使用时需要引入django.db.models包,字段类型如下:
类型 | 描述 |
---|---|
AutoField | 自动增长的IntegerField,一般用于主键,通常可不指定主键,不指定时Django会自动创建名为id的自动增长型的主键。 |
IntegerField | 整数 |
DecimalField(max_digits=None, decimal_places=None) | 十进制浮点数。参数max_digits表示总位数。参数decimal_places表示小数位数。 |
FloatField | 浮点数。参数同上(没有DeciamlField精确) |
CharField(max_length=最大长度) | 字符串类型。参数max_length表示最大字符个数,必须设置该参数。 |
TextField | 大文本字段,一般超过4000个字符时使用。 |
DateField:([auto_now=False, auto_now_add=False]) | 日期。 1)参数auto_now表示每次保存对象时,自动设置该字段为当前时间,用于”最后一次修改”的时间戳,它总是使用当前日期,默认为false。 |
2) 参数auto_now_add表示当对象第一次被创建时自动设置当前时间,用于创建的时间戳,它总是使用当前日期,默认为false。
3)参数auto_now_add和auto_now是相互排斥的,组合将会发生错误。 |
| TimeField | 时间,参数同DateField。 |
| DateTimeField | 日期时间,参数同DateField。 |
| FileField | 上传文件字段 |
| ImageField | 继承于FileField,对上传的内容进行校验,确保是有效的图片。 |
| BooleanField | 布尔字段,值为True或False。 |
| NullBooleanField | 支持Null、True、False三种值。 |
常见的约束
约束 | 描述 |
---|---|
primary_key | 若为True,则该字段会成为模型的主键字段,默认值是False,一般作为AutoField的选项使用。 |
null | 空值。默认为False |
unique | 如果为True, 这个字段在表中必须有唯一值,默认值是False。 |
default | 设置默认值。 |
db_column | 字段的名称,如果未指定,则使用属性的名称。如果指定了,则生成表的时候,字段名就是设置的名字 |
db_index | 若值为True, 则在表中会为此字段创建索引,默认值是False。 |
blank | 如果为True,则该字段允许为空白,默认值是False。blank是后台管理页面表单验证范畴的 |
当修改模型类后,如果添加的选项不影响表的结构,则不需要重新做迁移,上面选项中 default
和 blank
不影响表结构。
映射模型到数据库
- 在
settings.py
中,配置DATABASES
数据库相关信息,并将模型所在的app注册到INSTALLED_APP
。 - 在app中的models.py中定义好模型,这个模型必须继承自
django.db.models.Model
。 - 生成迁移脚本文件:在终端,进入到Django虚拟环境,然后切换到项目所在目录,然后执行
python manage.py makemigrations
。 - 将迁移脚本文件映射到数据库:执行
python manage.py migrate
。 - 此时会在数据库生成表:app名称_模型名称(小写形式)
注:每次映射都会在数据库的django_migrations
表中记录。
ORM增删改查
def add_data(request):
car = Car(name='长城', model='皮卡')
car.save() # 保存数据
return HttpResponse('添加数据')
def query_data(request):
'''根据主键查询数据'''
# car = Car.objects.get(id=1)
car = Car.objects.get(pk=2) # pk意为主键,不受主键名称改变的影响
'''根据特定条件查询数据'''
h6 = Car.objects.filter(model='H6运动版') # 返回多条数据
print(h6)
'''查询全部数据'''
cars = Car.objects.all()
for car in cars:
print(car)
return HttpResponse('查询数据')
def change_data(request):
# h6 = Car.objects.filter(model='皮卡') # 'QuerySet' object has no attribute 'save'
h6 = Car.objects.get(pk=2)
h6.color = 'Silver'
h6.save()
return HttpResponse('修改数据')
def delete_data(request):
# h6 = Car.objects.filter(model='皮卡')
h6 = Car.objects.get(pk=1)
h6.delete()
return HttpResponse('删除数据')
注意:
- filter()方法查询的是多条数据,如返回的是
<QuerySet [<Car: 您查询的数据为 - name:哈弗, color:black, model:H6运动版>]>
,要先循环再取值。 - filter、all方法查询时,返回的是queryset对象,queryset对象没有save方法。