Python Web开发之Django ORM模型理论到实践 (二)

最近复习Django的基础,发现好多知识都淡忘了,因此写下这篇文章帮助自己更好地加深印象,并且希望能帮助到各位小伙伴儿😉😉。
本篇文章适合正在学习Django ORM基础的小伙伴儿,以及正在找工作的大佬面试使用。如果文章有写的不准确或需要改进的地方,还请各位大佬不吝赐教💞💞💞。
在此先感谢大家了😘😘😘

Python Web开发之Django ORM模型理论到实践 (二)

目录

前言

什么是 ORM?

数据库配置

Django 如何使用 mysql 数据库

定义模型 (实践)

创建 APP

创建学生模型类

迁移数据库

ORM 管理器对象

定义数据表

模型查询

a) 模型成员objects

b) 过滤器

c) 查询单个数据

d) 限制查询集

e) 字段查询

f) 比较运算符

g) 聚合函数

h) F对象/Q对象

模型字段定义属性

ORM模型练习

1.数据库准备

2.数据库迁移

3. 数据插入

4. 查询所有的学生信息

5. 查询所有女学生的姓名和出生日期

6. 查询所有的学生,按照id从大到小排序

7. 查询所有的学生信息,并序列化

8. 查询所有80后学生的姓名、性别和出生日期(筛选)

9. 查询名字中有王字的学生的姓名(模糊),like ‘%小%’, like ‘小%’,like ‘%小’

10. 获取id为1的信息,get()和filter()的使用

11. 获取所有学生(按照id降序)中第一个/最后一个学生信息

12. 查询id等于1,2的学生信息

ORM模型练习 (进阶)

1. 一对一

2. 一对多

3. 多对多

最后

相信小伙伴们对Django ORM以及有一定的了解, 更多干货请看这里:更多知识点总结

前言

Django对数据库提供了很好的支持,对不同的数据库,django提供了统一调用的API,我们可以根据不同的业务需求使用不同是数据库。Django中引入了ORM(Objects Relational Mapping)对象关系映射,Django 框架向我们提供了丰富的模块,避免程序员在开发的过程中重复”造轮子”,提高了开发者的工作效率。

什么是 ORM?

ORM (Object Realtional Mapping)即对象关系映射,它是一种基于关系型数据库的程序技术。ORM 允许你使用类和对象对数据库进行操作,这大大提高了对数据库的控制,避免了直接使用 SQL 语句对数据库进行操作。这种程序技术的底层主要是通过映射机制实现的,有兴趣的可以自己研究一下!

Web 开发中对数据库的操作是必不可少的,然而每种数据库的操作方式以及用法不尽相同。由于 Django 中 ORM 的存在,为我们操作不同种类的数据库提供了统一的方法,ORM 适配了多种常用的关系型数据库,例如 PostgreSQL、MySQL、Oracle、Sqlite3 等。

ORM 在业务逻辑层和数据库层之间充当了桥梁的作用。

ORM 是通过使用描述对象和数据库之间的映射的元数据,将程序中的对象自动持久化到数据库中。

Python Web开发之Django ORM模型理论到实践 (二)

使用 ORM 的好处:

  • 提高开发效率。
  • 不同数据库可以平滑切换。

使用 ORM 的缺点:

  • ORM 代码转换为 SQL 语句时,需要花费一定的时间,执行效率会有所降低。
  • 长期写 ORM 代码,会降低编写 SQL 语句的能力。

ORM 解析过程:

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

ORM 对应关系表:

Python Web开发之Django ORM模型理论到实践 (二)

如上图是 ORM 与数据库的映射关系图。ORM 把类映射成数据库中的表,把类的一个实例对象映射成数据库中的数据行,把类的属性映射成表中的字段,通过对象的操作对应到数据库表的操作,实现 了对象到 SQL、SQL 到对象转换过程。

Django 把表模型定义为 Model,他需要 继承自 django.db.models 中的 Model 类,只要是与数据表相关的操作,都需要继承这个类。同时ORM 对于数据库的的增删改查,也提供了一些简单的 API,例如 F 查询、Q 查询。

针对数据库中的字段类型,Django ORM 都有对应的 “xxxField” 来表述,见如下表格。

字段说明字段属性AutoFiled默然自增主键(Primary_key=Ture),Django 默认建立id字段为主键。CharFiled字符类型Max_length=32,字符长度需要明确IntgerFiled整型 intDateFiled年月日时间类型auto_now=True,数据被更新就会更新时间 ;auto_now_add=True,数据第一次参数时产生。DateTimeFiled年月日小时分钟秒时间类型auto_now=True,数据被更新就会更新时间; auto_now_add=True,数据第一次参数时产生。DecimalFiled混合精度的小数类型max_digits=3,限定数字的最大位数(包含小数位);decimal_places=2,限制小数的最大位数。BooleanFiled布尔字段,对应数据库 tinyint 类型数据长度只有1位。值为True或FalseTextFiled用于大文本

数据库配置

Django 如何使用 mysql 数据库

  1. 进入mysql
mysql -u root -p
  1. 创建 MySQL 数据库( ORM 无法操作到数据库级别,只能操作到数据表)语法:
create database 数据库名称 default charset=utf8; # 防止编码问题,指定为 utf8

例如我们创建一个名为 test 数据库,编码指定为 utf8:

create database test default charset=utf8;
  1. 修改mysql配置

在项目的 settings.py 文件中找到 DATABASES 配置项,将其信息修改为:

DATABASES = {
    'default':
    {
        'ENGINE': 'django.db.backends.mysql',    # 数据库引擎
        'NAME': 'test', # 数据库名称
        'HOST': '127.0.0.1', # 数据库地址,本机 ip 地址 127.0.0.1
        'PORT': 3306, # 端口
        'USER': 'root',  # 数据库用户名
        'PASSWORD': '123456', # 数据库密码
    }
}
  1. gaojango 使用 pymysql 模块连接 mysql 数据库:
在与 settings.py 同级目录下的 __init__.py 中引入模块和进行配置
import pymysql
pymysql.install_as_MySQLdb()

定义模型 (实践)

创建 APP

Django 规定,如果要使用模型,必须要创建一个 app。我们使用以下命令创建一个 TestModel 的 app:

django-admin startapp TestModel

接下来在 settings.py 中找到INSTALLED_APPS这一项, 注册我们新建的app,如下:

INSTALLED_APPS = (
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',
    'TestModel',               # 添加此项
)

目录结构如下:

HelloWorld
|-- HelloWorld
|-- manage.py
...

|-- TestModel
|   |-- __init__.py
|   |-- admin.py
|   |-- models.py
|   |-- tests.py
|   -- views.py
</code></pre>
<h3><strong>创建学生模型类</strong></h3>
<p>重要概念: <strong>模型,表,属性,字段</strong></p>
<p>一个模型类在数据库中对应一张表,在模型类中定义的属性,对应模型对照表中的一个字段</p>
<p>修改 TestModel/models.py 文件,代码如下:</p>
<pre><code class="language-python">models.py
from django.db import models

class Student(models.Model):

    s_name = models.CharField(max_length=10)
    s_age = models.IntegerField()
    s_gender = models.BooleanField()

    class Meta:
        db_table = 'cd_student'
        ordering =[]

  ##  对象的默认排序字段,获取对象列表时使用,升序ordering['id'],降序ordering['-id']
</code></pre>
<h3>迁移数据库</h3>
<ul>
<li>生成迁移文件</li>
</ul>
<blockquote>
<p>python manage.py makemigrations</p>
</blockquote>
<p>注意:如果执行后并没有生成迁移文件,一直提示No changes detected这个结果的话,就要手动的去处理了。有两点处理方式:</p>
<p>1) 先删除掉__pycache__文件夹</p>
<p>2) 直接强制的去执行迁移命令,python manage.py makemigrations xxx (xxx就是app的名称)</p>
<p>3) 查看自动生成的数据库,查看表django_migrations,删掉app字段为xxx的数据(xxx就是app的名称)</p>
<ul>
<li>执行迁移生成数据库</li>
</ul>
<blockquote>
<p>python manage.py migrate</p>
</blockquote>
<p>注意: 生成迁移文件的时候,并没有在数据库中生成对应的表,而是执行migrate命令之后才会在数据库中生成表,</p>
<p>尽管我们没有在 models 给表设置主键,但是 Django 会自动添加一个 id 作为主键。</p>
<p>注意:以上是对数据库中所有的表进行迁移,当我们仅仅需要对部分表进行迁移时可以:</p>
<pre><code class="language-python">$ python3 manage.py migrate   #创建表结构

$ python3 manage.py makemigrations TestModel  #让 Django 知道我们在我们的模型有一些变更
$ python3 manage.py migrate TestModel   #创建表结构
</code></pre>
<h2>ORM 管理器对象</h2>
<h3>定义数据表</h3>
<p>现在有一张用户信息表 UserInfo,它有两个字段 name 和 password,可以定义如下:</p>
<pre><code class="language-python">from django.db import models
class UserInfo(models.Model):
      name = models.CharFiled(max_length=100)
      password = models.CharFiled(max_length=100)
</code></pre>
<p>通过以上代码,UserInfo 数据表就已经创建完成,我们对代码进行逐行解析:</p>
<ul>
<li>第 1 行,使用 from django.db import models 导入 models 模块;</li>
<li>第 2 行,使用 class 关键字对 UserInfo 表进行类定义,并继承了models 模块中的 Model 类;</li>
<li>第3、4 行,数据表中的字段 name 和 password 是 UserInfo 类的属性,name 和 password 字段类型都是 CharFiled,字段长度均是100。</li>
</ul>
<p>那么应该怎样对数据表进行操作呢?我们可以直接使用类名(即数据表名)来插入数据,下面是插入数据的一种方法:</p>
<pre><code class="language-python">UserInfo.objects.create(name='jay',password='abc123')
</code></pre>
<p>上面代码插入一条名字是"jay",密码是"abc123"的数据。读到这里,您可能会对" objects "产生疑问,所以在此处讲解一个重要的概念:每个继承自 <code>models.Model</code> 的模型类,都会有一个 objects 对象被同时继承下来,这个对象就叫做"管理器对象",数据库的增删改查可以用 objects 管理器对象来实现。</p>
<p>利用 ORM 插入数据有两种方式,上面已经介绍了一种,下面介绍第二种方法,也就是创建 UserInfo 的实例对象,然后调用 <code>save()</code>方法保存,代码如下:</p>
<pre><code class="language-python">Obj=UserInfo(name="jay",password="abc123")
Obj.name="john"
Obj.save()
</code></pre>
<p>上述代码中 name 属性值会被赋值为"john",最后调用 <code>save()</code>方法保存。</p>
<p>ORM 的增删改查称为 CURD 操作,下面列举几个常用语句:</p>
<pre><code class="language-python">UserInfo.objects.all()#查询表中的所有记录
UserInfo.objects.filter(name_contains='j')#查询表中name含有"j"的所有记录,被使用较多
UserInfo.objects.get(name="john")#有且只有一个查询结果,如果超出一个或者没有,则抛出异常
UserInfo.objects.get(name="john").delete()#删除名字为john的记录
UserInfo.objects.get(name="john").update(name='TOM')#更新数据表的name为TOM
</code></pre>
<p>模型查询</p>
<h3>a) 模型成员objects</h3>
<p>Django默认通过模型的objects对象实现模型数据查询</p>
<h3>b) 过滤器</h3>
<p>查询集表示从数据库获取的对象集合</p>
<p>查询集可以有多个过滤器</p>
<p>过滤器就是一个函数,基于所给的参数限制查询的结果</p>
<blockquote>
<p>从SQL角度来说,查询集合和select语句等价,过滤器就像where条件
Django有两种过滤器用于筛选记录</p>
</blockquote>
<ul>
<li>filter : 返回符合筛选条件的数据集</li>
<li>exclude : 返回不符合筛选条件的数据集</li>
</ul>
<p>多个filter和exclude可以连接在一起查询</p>
<p>当然还有如下这些过滤器:</p>
<blockquote>
<p>all() 返回所有数据
filter() 返回符合条件的数据
exclude() 过滤掉符合条件的数据
order_by() 排序
values() 一条数据就是一个字典,返回一个列表</p>
</blockquote>
<h3>c) 查询单个数据</h3>
<p>get():返回一个满足条件的对象。如果没有返回符合条件的对象,会应该模型类DoesNotExist异常,如果找到多个,会引发模型类MultiObjectsReturned异常</p>
<p>first():返回查询集中的第一个对象</p>
<p>last():返回查询集中的最后一个对象</p>
<p>count():返回当前查询集中的对象个数</p>
<p>exists():判断查询集中是否有数据,如果有数据返回True,没有返回False</p>
<h3>d) 限制查询集</h3>
<p>限制查询集,可以使用下表的方法进行限制,等同于sql中的limit</p>
<p>模型名.objects.all()[0:5] 小标不能为负数</p>
<h3>e) 字段查询</h3>
<p>对sql中的where实现,作为方法,filter(),exclude(),get()的参数</p>
<p>语法:属性名称__比较运算符 = 值</p>
<p>外键:属性名_id</p>
<p>注意:like语句中使用%表示通配符。比如sql语句查询 where name like '%xxx%',等同于filter(name_contains='xxx')</p>
<h3>f) 比较运算符</h3>
<p>contains:是否包含,大小写敏感</p>
<p>startswith,endswith:以values开头或者结尾,大小写敏感 以上的运算符前加上i(ignore)就不区分大小写了</p>
<p>isnull,isnotnull:是否为空。filter(name__isnull=True)</p>
<p>in:是否包含在范围内。filter(id__in=[1,2,3])</p>
<p>gt,gte,lt,lte:大于,大于等于,小于,小于等于。filter(age__gt=10)</p>
<p>pk:代表主键,也就是id。filter(pk=1)</p>
<h3>g) 聚合函数</h3>
<p>aggregate()函数返回聚合函数的值</p>
<p>Avg:平均值</p>
<p>Count:数量</p>
<p>Max:最大</p>
<p>Min:最小</p>
<p>Sum:求和</p>
<p>例如: Student.objects.aggregate(Max('age'))</p>
<h3>h) F对象/Q对象</h3>
<p><strong>F对象:</strong>可以使用模型的A属性与B属性进行比较</p>
<p>背景:在模型中有两个字段,分别表示学生成绩A与成绩B,要对成绩AB进行比较计算,就需要使用到F对象。</p>
<p>例如有如下例子1:</p>
<blockquote>
<p>班级中有女生个数字段以及男生个数字段,统计女生数大于男生数的班级可以如下操作:
grades = Grade.objects.filter(girlnum__gt=F('boynum'))</p>
</blockquote>
<p>F对象支持算数运算</p>
<p>grades = Grade.objects.filter(girlnum__gt=F('boynum') + 10)</p>
<p>例子2:</p>
<blockquote>
<p>查询python班下语文成绩超过数学成绩10分的学生
grade = Grade.objects.filter(g_name='python').first()
students = grade.student_set.all()
stu = students.filter(s_yuwen__gt= F('s_shuxue') + 10)</p>
</blockquote>
<p><strong>Q对象:</strong></p>
<p>Q()对象就是为了将过滤条件组合起来</p>
<p>当我们在查询的条件中需要组合条件时(例如两个条件"且"或者"或")时。我们可以使用Q()查询对象</p>
<p>使用符号&或者|将多个Q()对象组合起来传递给filter(),exclude(),get()等函数</p>
<p>Q()对象的前面使用字符"~"来代表意义"非"</p>
<p>例子1:​查询学生中不是12岁的或者姓名叫张三的学生</p>
<blockquote>
<p>student = Student.objects.filter(~Q(age=12) | Q(name='张三'))</p>
</blockquote>
<p>例子2:</p>
<p>查询python班语文小于80并且数学小于等于80的学生​</p>
<blockquote>
<p>grade = Grade.objects.filter(g_name='python').first() students = grade.student_set.all() stu = students.filter(~Q(s_yuwen__gte=80) & Q(s_shuxue__lte=80))</p>
</blockquote>
<p>​例子3:</p>
<p>查询python班语文大于等于80或者数学小于等于80的学生</p>
<blockquote>
<p>grade = Grade.objects.filter(g_name='python').first()
students = grade.student_set.all()
stu = students.filter(Q(s_yuwen__gte=80) | Q(s_shuxue__lte=80))</p>
</blockquote>
<p>模型字段定义属性</p>
<p>定义属性</p>
<blockquote>
<p><strong>概述</strong>
·django根据属性的类型确定以下信息
·当前选择的数据库支持字段的类型
·渲染管理表单时使用的默认html控件
·在管理站点最低限度的验证
·django会为表增加自动增长的主键列,每个模型只能有一个主键列,如果使用选项设置某属性为主键列后,则django不会再生成默认的主键列
·属性命名限制
·遵循标识符规则(不使用python预定义的标识符号,内置函数名,异常等。避免使用下划线等)
·由于django的查询方式,不允许使用连续的下划线</p>
</blockquote>
<p><strong>库</strong>
·定义属性时,需要字段类型,字段类型被定义在django.db.models.fields目录下,为了方便使用,被导入到django.db.models中
·使用方式
·导入from django.db import models
·通过models.Field创建字段类型的对象,赋值给属性</p>
<p><strong>逻辑删除</strong>
·对于重要数据都做逻辑删除,不做物理删除,实现方法是定义isDelete属性,类型为BooleanField,默认值为False</p>
<p><strong>字段类型</strong>
·AutoField
·一个根据实际ID自动增长的IntegerField,通常不指定如果不指定,一个主键字段将自动添加到模型中
·CharField(max_length=字符长度)
·字符串,默认的表单样式是 TextInput
·TextField
·大文本字段,一般超过4000使用,默认的表单控件是Textarea
·IntegerField
·整数
·DecimalField(max_digits=None, decimal_places=None)
·使用python的Decimal实例表示的十进制浮点数
·参数说明
·DecimalField.max_digits
·位数总数
·DecimalField.decimal_places
·小数点后的数字位数
·FloatField
·用Python的float实例来表示的浮点数
·BooleanField
·true/false 字段,此字段的默认表单控制是CheckboxInput
·NullBooleanField
·支持null、true、false三种值
·DateField([auto_now=False, auto_now_add=False])
·使用Python的datetime.date实例表示的日期
·参数说明
·DateField.auto_now
·每次保存对象时,自动设置该字段为当前时间,用于"最后一次修改"的时间戳,它总是使用当前日期,默认为false
·DateField.auto_now_add
·当对象第一次被创建时自动设置当前时间,用于创建的时间戳,它总是使用当前日期,默认为false
·说明
·该字段默认对应的表单控件是一个TextInput. 在管理员站点添加了一个JavaScript写的日历控件,和一个"Today"的快捷按钮,包含了一个额外的invalid_date错误消息键
·注意
·auto_now_add, auto_now, and default 这些设置是相互排斥的,他们之间的任何组合将会发生错误的结果
·TimeField
·使用Python的datetime.time实例表示的时间,参数同DateField
·DateTimeField
·使用Python的datetime.datetime实例表示的日期和时间,参数同DateField
·FileField
·一个上传文件的字段
·ImageField
·继承了FileField的所有属性和方法,但对上传的对象进行校验,确保它是个有效的image</p>
<p><strong>字段选项</strong>
·概述
·通过字段选项,可以实现对字段的约束
·在字段对象时通过关键字参数指定
·null
·如果为True,则该字段在数据库中是空数据,默认值是 False
·blank
·如果为True,则该字段允许为空白,默认值是 False
·注意
·null是数据库范畴的概念,blank是表单验证证范畴的
·db_column
·字段的名称,如果未指定,则使用属性的名称
·db_index
·若值为 True, 则在表中会为此字段创建索引
·default
·默认值
·primary_key
·若为 True, 则该字段会成为模型的主键字段
·unique
·如果为 True, 这个字段在表中必须有唯一值</p>
<p>ORM模型练习</p>
<p>在django中通过创建model去和数据库中的表进行一一映射,并且通过ORM封装 的处理方式去练习这一到习题,并写出如下的解题答案</p>
<h3>1.数据库准备</h3>
<p>在model中定义数据库,其中的性别,男的存1,女的存0。</p>
<blockquote>
<p>class Student(models.Model):
stuname = models.CharField(max_length=20)
stusex = models.BooleanField()
stubirth = models.DateField()
stutel = models.CharField(max_length=255)
class Meta:
db_table = 'student'</p>
</blockquote>
<h3>2.数据库迁移</h3>
<blockquote>
<p>python manage.py makemigrations
python manage.py migrate</p>
</blockquote>
<h3>3. 数据插入</h3>
<p>3.1 使用表单form提交post请求数据</p>
<blockquote></blockquote>
<p>3.2 获取post请求,获取请求数据,并且创建数据</p>
<ul>
<li>方法1:获取类对象进行save()保存</li>
</ul>
<blockquote>
<p>stu = Student()
stu.stuname = stuname
stu.stusex = sex
stu.stubirth = birth
stu.stutel = tel
stu.save()</p>
</blockquote>
<ul>
<li>方法2:使用create()方法</li>
</ul>
<blockquote>
<p>Student.objects.create(stuname=stuname,
stusex=sex,
stubirth=birth,
stutel=tel)</p>
</blockquote>
<ul>
<li>方法3:使用初始化</li>
</ul>
<blockquote>
<p>在Student模型中重构__init__()方法,添加如下代码
def <strong>init</strong>(self, name, birth=None, sex=None,tel=None):
super().<strong>init</strong>()
self.stuname = name
self.stubirth = birth
self.stusex = sex
self.stutel = tel
视图函数中定义创建学习信息的方法为:
stu = Student('小草', 18, 1, 12331244323)
stu.save()</p>
</blockquote>
<p>注意:重构__init__方法的时候,一定要使用super().<strong>init</strong>(),否则会报studen对象没有_state的属性。</p>
<h3>4. 查询所有的学生信息</h3>
<p>使用all()方法获取所有的数据</p>
<blockquote>
<p>Student.objects.all()</p>
</blockquote>
<h3>5. 查询所有女学生的姓名和出生日期</h3>
<blockquote>
<p>Student.objects.filter(stusex=0)
或者
Student.objects.exclude(stusex=1)</p>
</blockquote>
<p>其中:</p>
<p>filter():返回符合条件的数据</p>
<p>exclude():过滤掉符合条件的数据</p>
<h3>6. 查询所有的学生,按照id从大到小排序</h3>
<blockquote>
<p>Student.objects.all().order_by('-id')</p>
</blockquote>
<p>其中:</p>
<p>order_by('id'):表示按照id升序的排列</p>
<p>order_by('-id'):表示按照id降序的排列</p>
<h3>7. 查询所有的学生信息,并序列化</h3>
<blockquote>
<p>Student.objects.all().values()
Student.objects.all().values('s_name', 's_age')</p>
</blockquote>
<h3>8. 查询所有80后学生的姓名、性别和出生日期(筛选)</h3>
<blockquote>
<p>Student.objects.filter(stubirth__gte='1980-01-01',
stubirth__lte='1990-01-01')</p>
</blockquote>
<h3>9. 查询名字中有王字的学生的姓名(模糊),like '%小%', like '小%',like '%小'</h3>
<blockquote>
<p>Student.objects.filter(s_name__contains='小')
Student.objects.filter(s_name__startswith='小')
Student.objects.filter(s_name__endswith='小')</p>
</blockquote>
<h3>10. 获取id为1的信息,get()和filter()的使用</h3>
<blockquote>
<p>Student.objects.filter(id=1)
Student.objects.get(id=1)
Student.objects.get(pk=1)
get获取不到数据会直接报错, filter获取不到数据是返回空
stus = Student.objects.get(pk=5)
Student.objects.filter(id=5)
get只能返回一个数据,返回多个会报错
Student.objects.get(s_age=15) # 前提条件:数据库中s_age为15的数据有多条</p>
</blockquote>
<h3>11. 获取所有学生(按照id降序)中第一个/最后一个学生信息</h3>
<blockquote>
<h1>获取按照id降序的第一个学生信息</h1>
<p>Student.objects.all().order_by('-id')[0]
Student.objects.all().order_by('-id').first()
获取所有学生(按照id降序)中最后一个学生信息
Student.objects.all().order_by('-id').last()</p>
</blockquote>
<h3>12. 查询id等于1,2的学生信息</h3>
<blockquote>
<h1>select * from student where id in (1,2)</h1>
<p>stus = Student.objects.filter(id__in=[1,2])</p>
</blockquote>
<p>ORM模型练习 (进阶)</p>
<p>主要介绍模型的对应关系,一对一,一对多,以及多对多的关系。并且举例说明 模型对应关系描述如下: <strong>1:1 一对一 OneToOneField 1:N 一对多 ForeignKey M:N 多对多ManyToManyField</strong> 常见的几种数据关系,django都提供了很好的支持.</p>
<h3>1. 一对一</h3>
<p>1.1 模型</p>
<pre><code class="language-python">    创建学生的模型:
    class Student(models.Model):
        stu_name = models.CharField(max_length=6, unique=True)
        stu_sex = models.BooleanField(default=0)
        stu_birth = models.DateField()
        stu_delete = models.BooleanField(default=0)
        stu_create_time = models.DateField(auto_now_add=True)
        stu_operate_time = models.DateField(auto_now=True)
        stu_tel = models.CharField(max_length=11)
        stu_yuwen = models.DecimalField(max_digits=3, decimal_places=1, default=0)
        stu_shuxue = models.DecimalField(max_digits=3, decimal_places=1, default=0)

        class Meta:
            db_table = 'stu'

    创建学生拓展的模型:
    class StuInfo(models.Model):

        stu_addr = models.CharField(max_length=30)
        stu_age = models.IntegerField()
        stu = models.OneToOneField(Student)

        class Meta:
            db_table = 'stu_info'
</code></pre>
<p>1.2 通过学生拓展表去获取学生信息</p>
<pre><code class="language-python"></code></pre>
<pre><code>stuinfo = StuInfo.objects.all().first()
student = stuinfo.stu
</code></pre>
<pre><code>注意:通过拓展表去获取学生的信息的话,语法如下;
    学生拓展表的单条对象.关联字段,即可获取到学生表的数据
</code></pre>
<p>1.3 通过学生获取人信息1</p>
<pre><code class="language-python"></code></pre>
<pre><code>stu = Student.objects.all().first()
stuInfo = stu.stuinfo
</code></pre>
<pre><code>注意:通过学生获取关联表的数据的话,语法如下:
    学生对象.关联的表名,即可获取到关联表的数据
</code></pre>
<p>1.3.1 通过学生获取人信息2</p>
<pre><code class="language-python">在关联字段OneToOneField中加入参数related_name='xxx'
</code></pre>
<pre><code>在
stu = Student.objects.all().first()
stuInfo = stu.xxx
</code></pre>
<pre><code>注意:通过学生获取关联表的数据的话,语法如下:
    学生对象.关联的字段中定义的related_name参数,即可获取到关联表的数据
</code></pre>
<p>1.4 设置对应关系的字段为保护模式 :</p>
<pre><code class="language-python">models.CASCADE                      默认值
models.PROTECT                  保护模式
models.SET_NULL                 置空模式
models.SET_DETAULT          置默认值
models.SET()     删除的时候吃重新动态指向一个实体访问对象元素
on_delete = models.PROTECT

</code></pre>
<p>修改on_delete参数
models.OneToOneField('Student', on_delete=models.SET_NULL, null=True)</p>
<pre><code>在删除student对象的时候,stuinfo的关联字段会设置为空null=True,如下命令去删除student的数据:
</code></pre>
<p>Student.objects.filter(id=1).delete()</p>
<pre><code></code></pre>
<p>1.5 定义on_delete=models.PROTECT</p>
<pre><code class="language-python">p =  Student.objects.all().first()
p.delete()

注意:这个时候去执行该业务逻辑的方法的时候会报错
</code></pre>
<h3>2. 一对多</h3>
<p>2.1 模型</p>
<pre><code class="language-python"></code></pre>
<pre><code>定义一个班级类还有学生类,实现一对多的关系:
先定义班级类
Class Grade(models.Model):
    g_name = models.CharField(max_length=16)

定义student
    class Student:
        s_name = models.CharField(max_length=10)
        s_age = models.IntegerField(default=1)
        s_grade = models.ForeignKey(Grade, on_delete=PROTECT)
</code></pre>
<pre><code></code></pre>
<p>2.2 获取数据</p>
<p>语法:通过一获取多的数据</p>
<p>公式: <strong>一的对象.多的模型名小写_set</strong></p>
<p>然后在获取数据all(), get(), filter() 等等</p>
<p>如下先通过学生去获取班级信息:</p>
<blockquote>
<p>stu = Student.objects.first()
stu.s_grade</p>
</blockquote>
<p>重点:定义了related_name字段以后,只能通过related_name去反向获取数据,在也不能通过_set方法去获取数据了</p>
<p>2.3 数据查询,正查/反查</p>
<pre><code class="language-python">查询id=4的学生的班级名称
stu = Student.objects.get(id=4)
grade = stu.s_grade

查询id=1的班级的所有学生
grade = Grade.objects.filter(id=1).first()
stus = grade.student_set.all()
</code></pre>
<p>2.4 练习题</p>
<ul>
<li>获取python班下的所有学生的信息</li>
</ul>
<blockquote>
<p>gs = Grade.objects.filter(g_name='python')[0]
allstu = gs.student_set.all()</p>
</blockquote>
<ul>
<li>获取python班下语文成绩大于80分的女学生</li>
</ul>
<blockquote>
<p>gs = Grade.objects.filter(g_name='python')[0]
allstu = gs.student_set.filter(stu_yuwen__gte=80)</p>
</blockquote>
<ul>
<li>获取python班下语文成绩超过数学成绩10分的男学生</li>
</ul>
<blockquote>
<p>gs = Grade.objects.filter(g_name='python')[0]
allstu = gs.student_set.filter(stu_yuwen__gte=F('stu_shuxue') + 10)</p>
</blockquote>
<ul>
<li>获取出生在80后的男学生,查看他们的班级</li>
</ul>
<blockquote>
<p>gs = Grade.objects.filter(g_name='python')[0]
allstu = gs.student_set.filter(stu_birth__gte='1980-01-01', stu_birth__lte='1990-01-01')</p>
</blockquote>
<h3>3. 多对多</h3>
<p><strong>3.1 M:N 模型</strong></p>
<blockquote>
<p>定义购物车,用户的例子实现多对多:</p>
</blockquote>
<pre><code>1. 创建用户模型:
class GoodsUser(models.Model):
u_name = models.CharField(max_length=32)
2. 创建商品模型:
class Goods(models.Model):
g_name = models.CharField(max_length=32)
g_user = models.ManyToManyField(User)
</code></pre>
<p><strong>3.2 多对多表结构</strong></p>
<blockquote>
<p>多对多关系:
1. 生成表的时候会多生成一张表(实际会有三张表)
2. 生成的表是专门用来维护关系的
3. 生成的表是使用两个外键来维护多对多的关系
4. 两个一对多的关系来实现多对多的实现
5. 删除一个表的数据的话,中间关联表也要删除相关的信息</p>
</blockquote>
<p>3.3 中间表数据的增(add)删(remove)</p>
<blockquote>
<h1>id=4的用户添加两个商品(id=1,2)</h1>
<p>g_user = GoodsUser.objects.get(id=4)
c1 = Goods.objects.get(id=1)
c2 = Goods.objects.get(id=2)
g_user.goods_set.add(c1)
g_user.goods_set.add(c2)</p>
</blockquote>
<p>删除id=4的用户的商品中id=1的商品
g_user.goods_set.remove(c1)</p>
<p><strong>3.4 练习题</strong></p>
<p>3.4.1 获取第一个用户购买了那些商品</p>
<blockquote>
<p>
gu = GoodsUser.objects.all().first()
allstu = gu.goods_set.all()


3.4.2 获取指定商品的购买用户信息

> `
g = Goods.objects.filter(id=1)[0]
g.g_user.all()

最后

文章到这里就先结束了,后面还会持续更新,希望能帮助到各位大佬。如果文章有需要改进的地方还请大佬斧正🎉🎉🎉。
制作不易,希望能得到各位小伙伴儿的支持😘😘😘。
再次感谢大家了🤞🤞🤞。

相信小伙伴们对Django ORM以及有一定的了解, 更多干货请看这里: 更多知识点总结

Python Web开发之Django ORM模型理论到实践 (二)

Original: https://blog.csdn.net/weixin_47649808/article/details/125107913
Author: Bevis_OTL
Title: Python Web开发之Django ORM模型理论到实践 (二)

原创文章受到原创版权保护。转载请注明出处:https://www.johngo689.com/737086/

转载文章受原作者版权保护。转载请注明原作者出处!

(0)

大家都在看

  • Python基础学习笔记6

    文章目录 一、模块的简介与自定义模块 二、主程序运行的方式 三、Python中的包 四、Python中常用的内置模块 * 4.1 random模块 4.2 time模块 五、第三方…

    Python 2023年9月18日
    038
  • pytest配置文件合集(一)———–conftest.py应用

    配置文件: 配置文件一般存在项目的根目录下,官方文档介绍了四种配置文件,每种文件有各自的用处。 pytest.ini:主配置文件,最常用,优先级最高tox.ini :可以理解为py…

    Python 2023年9月11日
    051
  • 20个超级有用的 JavaScript 技巧

    今天,我整理了20个很实用的 JavaScript 开发技巧,希望这些技巧能够帮助你的学习与开发工作。 1. 初始化一个数组 如果你想初始化一个指定长度的一维数组并指定默认值,你可…

    Python 2023年9月29日
    025
  • 瑞吉外卖实战项目全攻略——第二天

    瑞吉外卖实战项目全攻略——第二天 该系列将记录一份完整的实战项目的完成过程,该篇属于第二天 案例来自B站黑马程序员Java项目实战《瑞吉外卖》,请结合课程资料阅读以下内容 该篇我们…

    Python 2023年10月18日
    047
  • FIR与IIR数字滤波器的比较

    IIR数字滤波器的设计原理:IIR数字滤波器设计是通过设计模拟滤波器来实现数字滤波器的设计;模拟滤波器的设计是通过设计三个低通滤波器模板来实现的;低通滤波器是通过给定的边界频率(通…

    Python 2023年8月2日
    043
  • python 推导式

    作用 推导式:将列表、集合、字典的生成逻辑用[]、{}封起来[逻辑最后 逻辑1 逻辑2] 例子 >>> [x*2 for x in range(12) if x!…

    Python 2023年6月12日
    074
  • 基于tensorfolw与matplotlib实现的二元梯度下降法预测模型

    最近嘛,在学tensorflow,就学到了梯度下降法,也用3D网格画图,途中遇到了不少问题,踩了一些坑,于是准备记录下来,其中有tensorflow的张量运算问题(和numpy的有…

    Python 2023年9月1日
    047
  • darknet训练yolov7-tiny(AlexeyAB版本)

    抵扣说明: 1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。 Original: https://blo…

    Python 2023年10月8日
    025
  • 玩转GDAL一文带你深入Windows下FileGDB驱动支持

    前言 了解GDAL的朋友一定知道,GDAL3.5以下(含)默认配置下是只支持gdb文件的读的,是不支持写的。更要命的是,默认的OpenFileGDB在读取时,如果我们在矢量文件中设…

    Python 2023年10月9日
    048
  • 「组合数学」隔离区

    本题是组合数学中的卡特兰数问题,此处给出了用分治思想推出卡特兰数递推公式的分析思路. 题目来源:(未知) 我们先来看一下这题的题面. 题面 题目描述 西安发生新冠疫情了。不少人进了…

    Python 2023年10月15日
    042
  • Python 爬虫 爬取酷我音乐

    一、第三方库 requests >>> pip install requests 二、开发环境 版 本: python 3.8 编辑器:pycharm 2021….

    Python 2023年5月24日
    0109
  • 【移动安全】—apk反编译基础及静态分析

    作者名:Demo不是emo 主页面链接:主页传送门创作初心: 一切为了她座右铭:不要让时代的悲哀成为你的悲哀专研方向:网络安全,数据结构每日emo: ctf被大佬吊打的一天,裂开 …

    Python 2023年11月6日
    038
  • 编译llvm源码

    起因 最近几天因为公司服务器的libstdc++.so版本太低,导致我想用clangd进行代码不全的时候没法运行,因为官网上的clangd 14二进制包需要glibc2.28的东西…

    Python 2023年6月3日
    054
  • chatGPT代码写的有点好啊,程序员要失业了?

    最近,这个聊天机器人有点火啊,是OpenAI推出的chatGPT,它能够回答各种各样的问题,还能生成代码,修复bug。 ChatGPT 是一个基于对话的原型 AI 聊天机器人,12…

    Python 2023年11月4日
    036
  • Python3获取5000个元素的单字符表

    此前考虑过一个问题,有没有办法获取到python里面所有定义好的单字符的表,比如我们获取5000个不一样的单字符,但是常用的 chr(number)的方法里面包含了太多的非字母条目…

    Python 2023年11月2日
    033
  • 『 MySQL篇 』:MySQL表的CURD操作

    📢 MySQL 系列专栏持续更新中 …MySQL专栏 ​ 目录 * – 目录 – + * 一、SQL语句 * – – S…

    Python 2023年11月7日
    046
亲爱的 Coder【最近整理,可免费获取】👉 最新必读书单  | 👏 面试题下载  | 🌎 免费的AI知识星球