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

  1. <a name="QfCM4"></a>
  2. ### ORM简介
  3. ORM,全称Object Relational Mapping(对象关系映射),通过实例化对象的方法,完成关系型数据库的操作的技术,即ORM可以通过类的方式去操作数据库,不用再写原生的SQL语句,而是通过把表映射成类,把字段作为属性。<br />ORM在执行对象操作时,最终还是会把对应的操作转换为数据库原生语句。
  4. - 数据库的表(table) --> 类(class)
  5. - 记录(record,行数据)--> 对象(object)
  6. - 字段(field)--> 对象的属性(attribute)
  7. ```python
  8. """models.py"""
  9. from django.db import models
  10. from datetime import datetime
  11. # 创建一个模型,其对应数据库中的一张表
  12. class Book(models.Model):
  13. id = models.AutoField(primary_key=True)
  14. name = models.CharField(max_length=20, null=False)
  15. author = models.CharField(max_length=100)
  16. price = models.FloatField()
  17. add_time = models.DateTimeField(default=datetime.now)
  18. """views.py"""
  19. # 一个模型的对象,对应数据库表中的一条数据
  20. book = Book(name="Python",author='龟叔',price=89)
  21. # 保存数据:save方法
  22. book.save()
  23. # 删除数据:delete方法
  24. book.delete()

创建ORM模型

ORM模型一般都是放在app的 models.py 文件中。如果这个app的模型想要映射到数据库中,那么该app的名称,必须要放在 settings.pyINSTALLED_APP 中进行安装。

以下是写一个简单的书籍ORM模型。

  1. from django.db import models
  2. from datetime import datetime
  3. class Book(models.Model):
  4. id = models.AutoField(primary_key=True) # 主键id可省略,其会自动被创建
  5. name = models.CharField(max_length=20, null=False)
  6. author = models.CharField(max_length=20, null=False)
  7. add_time = models.DateTimeField(default=datetime.now)
  8. 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是后台管理页面表单验证范畴的

当修改模型类后,如果添加的选项不影响表的结构,则不需要重新做迁移,上面选项中 defaultblank 不影响表结构。

映射模型到数据库

  1. settings.py 中,配置 DATABASES 数据库相关信息,并将模型所在的app注册到INSTALLED_APP
  2. 在app中的models.py中定义好模型,这个模型必须继承自 django.db.models.Model
  3. 生成迁移脚本文件:在终端,进入到Django虚拟环境,然后切换到项目所在目录,然后执行 python manage.py makemigrations
  4. 将迁移脚本文件映射到数据库:执行 python manage.py migrate
  5. 此时会在数据库生成表:app名称_模型名称(小写形式)

注:每次映射都会在数据库的django_migrations表中记录。

ORM增删改查

  1. def add_data(request):
  2. car = Car(name='长城', model='皮卡')
  3. car.save() # 保存数据
  4. return HttpResponse('添加数据')
  5. def query_data(request):
  6. '''根据主键查询数据'''
  7. # car = Car.objects.get(id=1)
  8. car = Car.objects.get(pk=2) # pk意为主键,不受主键名称改变的影响
  9. '''根据特定条件查询数据'''
  10. h6 = Car.objects.filter(model='H6运动版') # 返回多条数据
  11. print(h6)
  12. '''查询全部数据'''
  13. cars = Car.objects.all()
  14. for car in cars:
  15. print(car)
  16. return HttpResponse('查询数据')
  17. def change_data(request):
  18. # h6 = Car.objects.filter(model='皮卡') # 'QuerySet' object has no attribute 'save'
  19. h6 = Car.objects.get(pk=2)
  20. h6.color = 'Silver'
  21. h6.save()
  22. return HttpResponse('修改数据')
  23. def delete_data(request):
  24. # h6 = Car.objects.filter(model='皮卡')
  25. h6 = Car.objects.get(pk=1)
  26. h6.delete()
  27. return HttpResponse('删除数据')

注意:

  • filter()方法查询的是多条数据,如返回的是<QuerySet [<Car: 您查询的数据为 - name:哈弗, color:black, model:H6运动版>]>,要先循环再取值。
  • filter、all方法查询时,返回的是queryset对象,queryset对象没有save方法。