一,介绍Django ORM

  • Django 模型使用自带的 ORM。
  • 对象关系映射(Object Relational Mapping,简称 ORM )用于实现面向对象编程语言里不同类型系统的数据之间的转换。
  • ORM 在业务逻辑层和数据库层之间充当了桥梁的作用。
  • ORM 是通过使用描述对象和数据库之间的映射的元数据,将程序中的对象自动持久化到数据库中。
  • ORM可以创建,修改,删除数据库中的表(不需要写SQL语句),但是无法创建数据库。

    1.1 ORM 解析过程:

    • 1、ORM 会将 Python 代码转成为 SQL 语句。
    • 2、SQL 语句通过 pymysql 传送到数据库服务端。
    • 3、在数据库中执行 SQL 语句并将结果返回。

Django ORM(对象关系映射) - 图1
Django ORM(对象关系映射) - 图2

二,配置数据库

  • 在settings.py中保存了数据库的连接配置信息,Django默认初始配置使用sqlite数据库。
  • MySQL 是 Web 应用中最常用的数据库,选用mysql作为Django应用的数据库,则需要修改配置信息。

yuque_diagram.jpg

2.1 安装数据库驱动程序

Django第三方的数据库驱动程序有:PyMYSQL,MySQLdb,mysqlclient(推荐)

  1. (venv) F:\django项目\bookmanager> pip install mysqlclient

2.2 告诉Django 使用 pymysql 模块连接 mysql 数据库:

  1. import pymysql
  2. pymysql.install_as_MySQLdb()

2.3 修改DATABASES配置信息

  1. DATABASES = {
  2. 'default': { # 键必须是大写字母的字符串
  3. 'ENGINE': 'django.db.backends.mysql', #数据库引擎都在django.db.backends包中。
  4. 'HOST': '127.0.0.1', # 数据库主机
  5. 'PORT': 3306, # 数据库端口
  6. 'USER': 'root', # 数据库用户名
  7. 'PASSWORD': 'mysql', # 数据库用户密码
  8. 'NAME': 'book' # 指定数据库名字
  9. }
  10. }

2.4 在MySQL服务器中创建数据库

  1. create database book charset=utf8;

三,Model类

  • 每个类都是django.db.models.Model的子类。
  • 模型(类)的每个字段(属性)代表数据表的某一列。
  • Django自动为你生成访问数据库的API。
  • 每个模型在Django中的存在形式为一个Python类。
  • 所有的模型类都在”子应用/models.py”文件中。Molde.py文件中导入**django.db.models**文件夹。
  • 每个模型类必须继承**models.Model**类,Model类中实现了save()等方法。在视图中调用模型类对象.save()等方法可以实现数据库操作
  • 类中创建的字段本质就是创建models文件中的字段相关的类对象,比如CharField类对象等。

    3.1 定义Model类

    ```python from django.db import models

Create your models here.

准备书籍列表信息的模型类

class BookInfo(models.Model):

  1. # 创建字段,字段类型...
  2. name = models.CharField(max_length=20, verbose_name='名称')
  3. pub_date = models.DateField(verbose_name='发布日期',null=True)
  4. readcount = models.IntegerField(default=0, verbose_name='阅读量')
  5. commentcount = models.IntegerField(default=0, verbose_name='评论量')
  6. is_delete = models.BooleanField(default=False, verbose_name='逻辑删除')
  7. class Meta:
  8. db_table = 'bookinfo' # 指明数据库表名
  9. verbose_name = '图书' # 在admin站点中显示的名称
  10. def __str__(self):
  11. """定义每个数据对象的显示信息"""
  12. return self.name
  13. # 准备人物列表信息的模型类

class PeopleInfo(models.Model): GENDER_CHOICES = ( (0, ‘male’), (1, ‘female’) ) name = models.CharField(max_length=20, verbose_name=’名称’) gender = models.SmallIntegerField(choices=GENDER_CHOICES, default=0, verbose_name=’性别’) description = models.CharField(max_length=200, null=True, verbose_name=’描述信息’) book = models.ForeignKey(BookInfo, on_delete=models.CASCADE, verbose_name=’图书’) # 外键 is_delete = models.BooleanField(default=False, verbose_name=’逻辑删除’)

  1. class Meta:
  2. db_table = 'peopleinfo'
  3. verbose_name = '人物信息'
  4. def __str__(self):
  5. return self.name
  1. <a name="r0ee6"></a>
  2. ## 3.2 Model类讲解
  3. - 模型类的父类是`**models.Model**`**,**Model类中实现了save(),clean()方法。
  4. - 创建字段时必须使用models包中field子包的字段类:如CharField,IntegerField等类
  5. - 默认情况下,Django 为每个模型提供一个自动递增的主键,其类型在每个应用程序中或在设置中`**AppConfig.default_auto_field**`全局 指定。如果想要自定义主键,那么需要使用在某一字段中添加`**primary_key=True**`**,**使其成为主键。
  6. - 不能调用Model.CharField(),因为CharField不是Model的子类,而是models下的一个类。
  7. 创建字段只需要关注字段的类型以及字段选项;
  8. <a name="xnN6k"></a>
  9. ### 3.2.1 通用且可选的字段属性
  10. 关系字段类型,普通字段类型都可以使用通用字段属性。
  11. | 选项 | 取值说明 |
  12. | --- | --- |
  13. | null | 默认为False,若为True,则字段允许为空值,数据库表现为NULL。 |
  14. | blank | 默认为False,若为True,则字段允许为空值,数据库将存储空字符串。 |
  15. | db_column | 默认为None,设置数据表的列名称,若不设置,则将字段名作为数据表的列名。 |
  16. | db_index | 默认为False,若为True,则以此字段来创建数据库索引。 |
  17. | db_tablespace | 默认为None,如果字段已创建索引,那么数据库的表空间名称将作为该字段的索引名。注意:部分数据库不支持表空间。 |
  18. | default | 默认为NOT_PROVIDED对象,设置字段的默认值。 |
  19. | primary_key | 默认为False,若为True,则将字段设置成主键。 |
  20. | unique | 值为True,代表这个字段在表中有唯一值,默认值为False |
  21. | unique_for_date | 默认为None,设置日期字段的唯一性。 |
  22. | unique_for_month | 默认为None,设置日期字段月份的唯一性。 |
  23. | unique_for_month | 默认为None,设置日期字段月份的唯一性。 |
  24. | choices | 默认为空列表,设置字段的可选值。 |
  25. | verbose_name | 默认为None,在Admin站点管理设置字段的显示名称。 |
  26. | validators | 默认为空列表,设置字段内容的验证函数。 |
  27. | help_text | 默认为空字符串,用于设置表单的提示信息 |
  28. | auto_created | 默认为False,若为True,则自动创建字段,用于一对一的关系模型。 |
  29. | error_messages | 默认为None,设置错误提示 |
  30. > null是数据库范畴的概念,blank是表单验证范畴的
  31. <a name="PrQce"></a>
  32. ### 3.2.2 普通字段类型(字段类型都是类)
  33. | 字段类 | 字段说明 | 字段独有的选项 |
  34. | --- | --- | --- |
  35. | AutoField | 主键自增字段 | |
  36. | BooleanField | 当没有设置字段的default时,字段的默认值为None | |
  37. | CharField | 字符串字段 | max_length(必需) |
  38. | DateField | 日期字段 | auto_now=False/True,auto_now_add=False |
  39. | DateTimeField | | |
  40. | EmailField | 本质为CharField,结合EmailValidator检查该值是否为有效邮件地址 | max_length=254,validator=EmailValidator |
  41. | FileField | | |
  42. | FilePathField | | |
  43. | GenericIPAddressField | IP地址字段 | |
  44. | FloatField | 浮点数字段 | |
  45. | IntegerField | 整数字段 | |
  46. | ImageField | 图像字段 | <br /> |
  47. | TextField | 文本字段 | |
  48. | TimeField | 时间字段,和DateField字段类似 | |
  49. | URLFileld | 保存URL的字段 | max_length默认为200 |
  50. | UUIDField | 存储唯一标识符的字段 | default = uuid.uuid4 |
  51. <a name="D84fY"></a>
  52. ### 3.2.3 关系字段类型
  53. ![](https://cdn.nlark.com/yuque/0/2022/jpeg/12372066/1655600843395-a3fc61b6-bbc7-487f-abec-73db2024a84e.jpeg)
  54. <a name="tBZgi"></a>
  55. #### 1. 多对一关系:ForeignField (外键)
  56. - 外键的定义在“多”的一方。
  57. - 外键字段类的参数:
  58. 1. 关联的模型,字符串表示,第一位置且不可省略的参数。关联自身,使用' self'(适用于所有关系字段);如果关联的对象在另一个子应用中,则字符串为:'" 子应用 . models . 模型类"
  59. 1. on_delete:值一般为django.db.models.CASCADE,和关联表的数据同步,外联的数据记录有改动,则本表也会自动发生改动。
  60. 1. to_field:默认情况下,外键都是关联到被关联数据表的主键字段上。如果指定这个参数,则可以关联到指定的字段上,但是该字段必须具有唯一性属性,即unique = True。
  61. <a name="doe1E"></a>
  62. #### 2. 多对多关系:ManyToManyField
  63. - 多对多的字段可以定义在任何一方。但是遵守原则:定义在符合人们思维的一方,不要同时都定义。
  64. - 在数据库后台,Django会额外创建一个用于体现多对多关系的中间表。
  65. - 建议多对多字段使用复数形式
  66. - 参数说明:
  67. 1. through:自定义多对多的额外关系表,参数的值为中间模型类。
  68. 1. through_fields:标识中间模型类中的多对多关系的字段,值为一个二元元组。仅在自定义中间模型类时使用。
  69. 1. db_table:在数据库中中间表的名称,不指定的话,使用默认值。
  70. 1. 通用选项中的null参数在多对多关系中失效。
  71. ```python
  72. from django.db import models
  73. class Person(models.Model):
  74. name = models.CharField(max_length=50)
  75. class Group(models.Model):
  76. name = models.CharField(max_length=128)
  77. members = models.ManyToManyField(
  78. Person,
  79. through='Membership',
  80. ## 自定义中间表
  81. through_fields=('group', 'person'),
  82. )
  83. class Membership(models.Model):
  84. # 这就是具体的中间表模型
  85. group = models.ForeignKey(Group, on_delete=models.CASCADE)
  86. person = models.ForeignKey(Person, on_delete=models.CASCADE)
  87. invite_time = models.ForeignKey(
  88. Person,
  89. on_delete=models.CASCADE,
  90. related_name="membership_invites",
  91. )
  92. invite_reason = models.CharField(max_length=64)

中间模型类中添加了除“group”、“person”之外的字段

  1. 一对一关系:OneToOneField

3.2.4 元类Meta

元类型Meta含有的选项:

abstract 若设为True,则该模型为抽象模型,不会在数据库里创建数据表。
app_label 属性值为字符串,将模型设置为指定的项目应用,比如将index的models.py定义的模型A指定到其他App里。
db_table 属性值为字符串,设置模型所对应的数据表名称。
db_teblespace 属性值为字符串,设置模型所使用数据库的表空间。
get_latest_by 属性值为字符串或列表,设置模型数据的排序方式。
managed 默认值为True,支持Django命令执行数据迁移;若为False,则不支持数据迁移功能。
order_with_respect_to 属性值为字符串,用于多对多的模型关系,指向某个关联模型的名称,并且模型名称必须为英文小写。比如模型A和模型B,模型A的一条数据对应模型B的多条数据,两个模型关联后,当查询模型A的某条数据时,可使用get_b_order()和set_b_order()来获取模型B的关联数据,这两个方法名称的b为模型名称小写,此外get_next_in_order()和get_previous_in_order()可以获取当前数据的下一条和上一条的数据对象。
_b_order() 获取模型B的关联数据,这两个方法名称的b为模型名称小写,此外get_next_in_order()和get_previous_in_order()可以获取当前数据的下一条和上一条的数据对象
ordering 属性值可以是元组、列表或者查询表达式,每一个元组或列表的元素都是一个字段名,默认是正序排序,如果给字段名前添加一个“-”符号则会按照倒序排序;如果在字段名前面加“?”,就会随机提取数据。
proxy 若设为True,则为模型创建代理模型,即克隆一个与模型A相同的模型B。
required_db_features 属性值为列表,声明模型依赖的数据库功能。比如[‘gis_enabled’],表示模型依赖GIS功能。
select_on_save 数据新增修改算法,通常无须设置此属性,默认值为False。
indexes 属性值为列表,定义数据表的索引列表。
unique_together 属性值为元组,多个字段的联合唯一,等于数据库的联合约束。
verbose_name 属性值为字符串,设置模型直观可读的名称并以单数形式表示。
verbose_name_plural 与verbose_name相同,以复数形式表示。如果没有指定verbose_name_plural,Django会自动生成,形式为verbose_name + “s”。
label 只读属性,属性值为app_label.object_name,如index的模型PersonInfo,值为index.PersonInfo。
label_lower 与label相同,但其值为字母小写,如index.personinfo。
  1. from django.db import models
  2. class Customer(models.Model):
  3. first_name = models.CharField(max_length=100)
  4. last_name = models.CharField(max_length=100)
  5. class Meta:
  6. indexes = [
  7. models.Index(fields=['last_name', 'first_name']),
  8. models.Index(fields=['first_name'], name='first_name_idx'),
  9. ]

3.2.5 Manager类

Manager是Django模型最重要的属性,它赋予模型类操作数据库的能力。默认情况下,Django会为每一个模型提供一个叫作objects的Manager实例对象。Manager属性只能通过模型类访问,即:**模型类 . objects **

  1. 更改Manager实例对象的名称。更改实例对象名称只需要在模型类中实例化一个Manager对象并赋值给变量,那么在操作数据库时就不能使用objects了。 ```go class Student(models.Model): … perple = models.Manager()
  1. 2. 自定义Manager类:需要继承`**models.Manager**`类,自定义Manager类主要是添加额外的Manager方法,或者修改Manager返回值QuerySet
  2. 3. 默认管理器:
  3. 1. 模型类的父类的默认管理器
  4. 1. Meta类中使用`**default_manager_name**`来指定默认管理器。
  5. 1. 模型类中创建的第一个管理器对象。
  6. ```python
  7. class AbstractBase(models.Model):
  8. # ...
  9. objects = CustomManager()
  10. class Meta:
  11. abstract = True
  12. class ChildA(AbstractBase):
  13. # ...
  14. # This class has CustomManager as the default manager.
  15. pass
  16. class ChildB(AbstractBase):
  17. # ...
  18. # An explicit default manager.
  19. default_manager = OtherManager()

3.3 模型类迁移到数据库

  • 模型类迁移到数据库是为了利用**ORM**将模型类映射成数据库系统中的数据库和数据库表。
  • 对模型类做了修改后,删除原有的迁移文件,然后重新进行迁移。
  1. 生成迁移文件:使用**makemigrations**将model.py文件打包放到单独的迁移文件中去。

    1. python manage.py makemigrations
  2. **migrate**调用三方库mysqlclient将迁移文件运行生成**mysql**的数据库和数据库表文件。

    1. python manage.py migrate

    3.4 数据的增删改查

    对于数据的增删改查操作,我们除了使用Model自身的save(),delete(),clean(),还可以使用Manager类的实例对象来进行操作。

    3.4.1 添加数据

    添加数据两种方法:

    • 创建模型类对象,执行对象的**save()**方法保存到数据库中去;
    • 通过**模型类.objects.create()**进行保存; ```sql 通过创建模型类对象,执行对象的save()方法保存到数据库中。

from book.models import BookInfo,PeopleInfo book = BookInfo( … name=’python入门’, … pub_date=’2010-1-1’ … ) book.save() # 由于继承了 book

  1. ```python
  2. PeopleInfo.objects.create(
  3. ... name='itheima',
  4. ... book=book
  5. ... )
  6. <PeopleInfo: itheima>

3.4.2 修改数据

修改数据有两种方法:

  • 修改模型类对象的属性,然后执行**save()**方法;
  • 使用**模型类.objects.filter().update()**,返回受影响的行数。

    1. >>> person = PeopleInfo.objects.get(name='itheima')
    2. >>> person.name = 'itcast'
    3. >>> person.save()
    4. >>> person
    5. <PeopleInfo: itcast>
    1. >>> PeopleInfo.objects.filter(name='itcast').update(name='传智播客')
    2. 1

    3.4.3 删除数据

    删除也有两种方法:

  • 模型类对象的**delete()**方法

  • **模型类.objects.filter().delete()**
    1. >>> person = PeopleInfo.objects.get(name='传智播客')
    2. >>> person.delete()
    3. (1, {'book.PeopleInfo': 1})
    4. 2)模型类.objects.filter().delete()
    1. >>> BookInfo.objects.filter(name='python入门').delete()
    2. (1, {'book.BookInfo': 1, 'book.PeopleInfo': 0})

    3.4.4 查询数据

  1. 基础条件查询:使用Manager对象的方法[ get(),all(),count(), filter(),exclude()]
    1. **模型类.objects.get()/all()/count()** ```python

      BookInfo.objects.get(id=1)

BookInfo.objects.get(pk=2)

BookInfo.objects.get(pk=20) Traceback (most recent call last): File ““, line 1, in File “/home/python/.virtualenvs/py3_django_1.11/lib/python3.5/site-packages/django/db/models/manager.py”, line 85, in manager_method return getattr(self.get_queryset(), name)(args, *kwargs) File “/home/python/.virtualenvs/py3_django_1.11/lib/python3.5/site-packages/django/db/models/query.py”, line 380, in get self.model._meta.object_name book.models.DoesNotExist: BookInfo matching query does not exist.

BookInfo.objects.all()

, , , ]>

BookInfo.objects.count() 4 ```

  1. 过滤查询:实现SQL中的where功能,包括filter过滤多个结果,exxclude排除掉符合条件剩下的结果,get过滤单一结果。过滤条件的使用,这三个方法都相同。

过滤条件的表达式:

  1. 属性名称__比较运算符=值
  2. # 属性名称和比较运算符间使用两个下划线,所以属性名不能包括多个下划线
  3. 比较运算符有:
  4. 1. exact : 等于
  5. 2. contains : 是否包含字符串
  6. a. startwithendwith:以指定值开头或结尾
  7. 3. isnull: 是否为null
  8. 4. in : 是否包含在范围内
  9. 5. 比较查询:
  10. gt: 大于(great then
  11. gte: 大于等于(great then equal
  12. lt : 小于(less then
  13. lte: 小于等于(less then equal
  14. exclude():不等于
  15. 6. 日期查询:
  16. year,month,day,week_day,hour,minute,second
  1. F和Q对象

  2. 关联查询

  3. 查询集