day_36:后端day07Django框架中的ORM数据库操作二

一。查询,官方参考地址:https://docs.djangoproject.com/zh-hans/3.2/ref/models/querysets/#queryset-api

1)选择字段查询

### 选择字段

- values(*fields, **kwargs) 返回一个QuerySet,这个QuerySet返回一个字典列表,而不是数据对象。参数*fields 指定了select中我们想要限制查询的字段。返回的字典中只会包含我们指定的字段。如果不指定,包含所有字段。

```python
Projects.objects.values('name')
```

- only(*fields) 返回一个QuerySet.参数*fields指定了select中我们想要限制查询的字段。注意,only一定包含主键字段。

```python
Projects.objects.only('name')
```

- defer(*fields) 返回一个QuerySet。参数*fields指定了select中我们想要排除的查询字段。注意,defer一定包含主键字段

```python
Projects.objects.defer('c_time')
```

 例子:

先进入django shell模块,导入对应模块:

Project.object.values():

 

Student.object.only():

 

Student.object.defer():

2)条件查询

### 条件查询

在`filter`,`exclude`,`get`中可以接收参数实现各种比较条件的查询。

- exact 

准确匹配.如果给的值是None,它会被解释成SQL NULL 看下面的案例

```python
Project.objects.get(id__exact=14)
Project.objects.get(id__exact=None)  
```

`id__exact=14`等价于`id = 14`,默认情况不带`exact`

- iexact 不分大小写的匹配。

```python
Blog.objects.get(name__iexact='beatles blog')
Blog.objects.get(name__iexact=None)
```

- in 

在一个给定的可迭代对象中,通常是一个列表,元组,或queryset。虽然不是经常用但是字符串也可以。

```python
Entry.objects.filter(id__in=[1, 3, 4])
Entry.objects.filter(headline__in='abc')
```

- gt 

大于

```python
    Entry.objects.filter(id__gt=4)
```

- gte 大于等于
- lt 小于
- lte 小于等于

- range 

范围区间

```python
Student.objects.filter(age__range=(18, 20))
```

 例子:

exact:

iexact:

in:

gt:

gte:

lt:

lte:

range:

3)条件组合查询

### 条件组合

- AND

使用 SQL `AND` 操作符将两个 `QuerySet` 组合起来。

以下的都是相同的

```python
Model.objects.filter(x=1) & Model.objects.filter(y=2)
Model.objects.filter(x=1, y=2)
from django.db.models import Q
Model.objects.filter(Q(x=1) & Q(y=2))
```

SQL 等价于:

```sql
SELECT ... WHERE x=1 AND y=2
```

- OR

使用 SQL `OR` 操作符将两个 `QuerySet` 组合起来。

以下的都是相同的:

```python
Model.objects.filter(x=1) | Model.objects.filter(y=2)
from django.db.models import Q
Model.objects.filter(Q(x=1) | Q(y=2))
```

SQL 等价于:

```sql
SELECT ... WHERE x=1 OR y=2
```

 例子:

AND:

方式一:

方式二:

方式三:

OR:

方式一:

方式二:

4)聚合查询

### 聚合查询

- count 统计数量

  ```
      # 统计所有学生的数量
      Students.objects.count()
      # 统计所有男生的数量
      Students.objects.filter(sex='男').count()
  ```

- Avg 平均值

  ```
      # 计算同学们的年龄平均值
      from django.db.models import Avg
      Students.objects.aggregate(age_avg=Avg('age'))
  ```

- Max 最大值

  ```
      # 找到最大年龄的学生
      from django.db.models import Max
      Students.objects.aggregate(Max('age'))
  ```

- Min 最小值

  ```
      # 找到最小年龄的学生
      from django.db.models import Min
      Students.objects.aggregate(Min('age'))
  ```

- Sum 求和

  ```
      # 计算缴费总金额
      from django.db.models import Sum
      Enroll.objects.aggregate(Sum('pay'))
  ```

 例子:

count:

统计所有可以去掉all()

过滤统计:

Avg(aggregate为聚合的方法):

Max:

Min:

Sum:

5)分组查询

### 分组

分组,聚合,需要结合values,annotate和聚合方法看下面的案例

```python
# 查询男生女生多少人
Student.objects.values('sex').annotate(Count('sex'))  # annotate 默认按照主键分组
```

更多聚合参考[官方文档](https://docs.djangoproject.com/zh-hans/3.2/topics/db/aggregation/#aggregation)

 例子:

二。删除对象

## 删除对象

通常,删除方法被命名为 [`delete()`](https://docs.djangoproject.com/zh-hans/3.2/ref/models/instances/#django.db.models.Model.delete)。该方法立刻删除对象,并返回被删除的对象数量和一个包含了每个被删除对象类型的数量的字典。例子:

```python
p = Project.objects.get(pk=1)
p.delete()
```

 例子:

三。关联对象操作与多表查询

1。一对多关系

1)正向操作

一个模型如果有一个外键字段,通过这个模型对外键进行操作叫做正向

a.更新,修改

##### 更新,修改

>```python
># 1 通过属性赋值的方式
>s1 = Student(name='心蓝', age=18)
>s1.grade = g1
>s1.save()
># 2 通过主键的方式
>s2 = Student(name='小明', age=19)
>s2.grade_id = g2.id
>s2.save()
>```
>
>==注意,主表表数据要入库(也即是Grade对象要save()之后)之后,引用表才能创建==

ForeignKey字段的更新,和普通字段没有什么区别。

 例子:

b.删

##### 删

如果一个外键字段有null=True的设置(即,它允许空值),您可以指定None来删除关系。例如:

```
s1.grade = None
s1.save()
```

 例子:

c.查

##### 查

```
# 查询所有django班的学生
Student.objects.filter(grade__name='django框架') 
```

外键字段对象的属性可以通过两个下划线来获取。

 例子:

2)反向操作

#### 反向

一个模型如果被另外一个模型外键关联,通过这个模型对关联它的模型进行操作叫做反向

如果一个模型有一个ForeignKey,那么这个外键模型的实例将可以访问一个返回第一个模型的所有实例的管理器。默认情况下,这个管理器名为FOO_set,其中FOO是源模型名,小写。这个管理器返回queryset,可以按照前面重用查询一节中描述的那样对其进行过滤和操作。

==通过在定义字段的时候设置参数 related_name 可以替代上面的管理器名==

 例子:

FOO_set模式(如下的操作都是基于FOO_set的类型):

related_name模式(在model的表外键中重命名):

a.增

##### 增

```
# 1.通过主表创建从表数据
new_student = g2.student_set.create(name='韩梅梅', age=16, sex=0) 
# 2.增加多条数据
g2.student_set.add(s1,s2,s3)
# 会将s1,s2,s3全部加入关联对象集合

 例子:

单个数据新增

 多个数据新增:

b.删除

##### 删除

```
# 1. 从相关对象中移除指定的模型对象
g.student_set.remove(s1, s2, ...)
# 2. 从相关对象中删除所有的 对象
g.student_set.clear()
```

 例子:

remove(这里只展示的是删除一个,多个的话就使用逗号隔开):

clear(清除所有数据): 

c.改

##### 改

```
# 替换对象集
g.student_set.set([s1, s2])
# 如果clear 可以调用 先clear再添加,如果过不行就直接添加
```

 例子:

 方式一:

主表中没有对应的外键id的数据:

主表中有对应外键id的数据:

d.查

##### 查

```
# 1. 查询所有
g.student_set.all()
# 2. 条件查询
g.student_set.filter(name='心蓝')
# 和objects一样的使用
```

 例子:

差主表所有数据:

差主表符合条件的数据:

2.多对多关系

### 多对多

多对多两端都可以获得另一端的自动API访问。该API的工作原理类似上面的'反向'一对多关系。

一个不同之处在于:定义ManyToManyField的模型使用该字段本身的属性名,而“反向”模型使用原始模型的小写模型名,加上“_set”(就像反向一对多关系一样)。下面这个例子更容易理解:

```python
# 先创建几个课程 c1, c2, c3
c1.students.add(s1, s2, s3)
s1.course_set.add(c1, c2, c3)
c1.students.all()
c1.students.filter(name='心蓝')
```

和ForeignKey一样ManyToMany也可以指定related_name。在上面的案例中,如果定义在Course中的ManyToManyField指定了related_name='courses',那么每一个Student对象都会有一个course的属性替代course_set.

和一对多关系的另一个区别是,除了模型实例之外,多对多关系上的add()、set()和remove()方法还接受主键值。例如,如果e1和e2是条目实例,那么这些set()调用的工作方式是相同的:

```python
s1.course_set.set([c1, c2, c3])
s1.course_set.set([c1.pk, c2.pk])
```

当多对多的关系指定了中间表的时候,还可以通过中间表象和普通的一对多关系一样操作。

看下面的案例:

```python
e = Enroll()
e.course = c1
e.student = s1
e.save()
```

你可能会问,既然这样,那指定中间表还要多对多字段干什么?因为查询非常方便,看下面的案例

```python
c1.students.all()
s1.course_set.all()
```

使用manaytomany之后,这两个表可以有反向的api直接相互访问。

 例子:

 反向创建:

正向创建:

反向查询:

多对多方法可以接受主键值:

操作enroll表:

 

3.一对一关系

### 一对一

一对一关系非常类似于多对一关系。如果您在模型上定义一对一字段,那么该模型的实例将可以通过模型的一个简单属性访问相关对象。例如:

```python
d1 = StudentDetail(num='2019020001', college='武汉理工大学')
s1.detail = d1
s1.save()
```

不同之处在于“反向”查询。一对一关系中的相关模型也可以访问一个Manager对象,但是这个Manager只表示一个对象,而不是对象的集合:

```
d1.student  # 返回一个student对象
```

如果没有给这个关系分配对象,Django将抛出一个DoesNotExist异常。

实例可以以与分配正向关系相同的方式分配到反向关系:

```
d2.student = s
```

 例子:

四。跨表查询

## 跨表查询

Django提供了一种强大而直观的方法,可以在查询中“跟踪”关系,在幕后自动处理SQL连接。要跨越关系,只需使用跨模型的相关字段的字段名,以双下划线分隔,直到您到达您想要的字段为止。

例如,查询男生都报名了什么课程

```python
Course.objects.filter(students__sex=1).distinct() 
```

这个关系要多深就可以有多深。

它也向后工作。要引用“反向”关系,只需使用模型的小写名称。

这个例子查询所有报名了‘python’课程的学员:

```python
Student.objects.filter(course__name__contains='python') 
```

我们在来一个例子:
查询所有报名了python的33期的学员

```python
Student.objects.filter(course__name__contains='python', grade__num__contains='33')
```

缴费小于3000的学员

```python
Student.objects.filter(enroll__pay__lt=3000)  
```

学员报名python课的班级有哪些

```python
Grade.objects.filter(student__course__name__contains='python').distinct() 
```

 例子:

1.查询所有男生都报名了什么课程,并去重:

未去重前:

 去重后:

2.查询报名"python测开"课程的所有学生信息(contains是模糊查询的意思)

3.查询报名"python测开"课程和班级名为"测开python"班级的学生信息:

4.查找缴费小于3000的学员

5.学员报名"python测开"课程的班级有哪些?

五。执行原声SQL

1.执行原生查询并返回模型实例

### 1. 执行原生查询并返回模型实例

在管理器上调用raw()方法用于执行远程SQL查询,就会返回模型实例:

```python
Manager.raw(raw_query, params=(), translations=None)
```

该方法接受一个原生 SQL 查询语句,执行它,并返回一个 `django.db.models.query.RawQuerySet` 实例。这个 `RawQuerySet` 能像普通的 `QuerySet`一样被迭代获取对象实例。

```python
for stu in Student.objects.raw('select * from crm_student'):
    print(stu)
```

 例子:

1.raw:

2.

2.直接执行自定义的SQL

### 2.直接执行自定义的SQL

```python
from django.db import connection

def my_custom_sql():
    with connection.cursor() as cursor:
        cursor.execute("select * from crm_student where age= %s", [18])
        row = cursor.fetchone()

    return row
```

 例子:

爱折腾的小测试
原文地址:https://www.cnblogs.com/newsss/p/15548659.html