Django ORM实战:模型字段与元选项配置,以及链式过滤与QF查询详解

简介: Django ORM实战:模型字段与元选项配置,以及链式过滤与QF查询详解

前言

    在Django框架中,数据是应用的核心。其强大的ORM(对象关系映射)系统使得数据操作变得直观且高效。本文将带您领略Django ORM的精髓,包括模型类字段与属性的设定、元选项的配置、以及增删改查等基础操作。特别地,我们将聚焦链式过滤条件和QF查询,让您轻松构建复杂查询。同时,深入介绍QuerySet,这个ORM的核心组件,带您领略其强大的数据处理能力。


提示:以下是本篇文章正文内容,下面案例可供参考

一、模型类字段

每一个字段都是Field基类的一个实例(Field类用来建立字段与数据库之间的映射)

1.BooleanField

True/False 字段,默认值为 None

BooleanField(**options)

2.CharField

字符串字段

CharField(max_length=None)
# max_length 设置最大的字符数长度限制

3.DateField

datetime.date实例表示的日期 2013-08-01

DateField(auto_now=False, auto_now_add=False,**options)
'''
auto_now: 该值为 True 时,每次在保存数据对象时,自动设置该字段为当前时间,也可以理解为自动更新最后一次修改时间
auto_now_add: 该值为 True 时,该字段设置在第一次数据对象创建时,可以记录当前字段创建的时间值
'''

注意:避免矛盾,auto_nowauto_now_adddefault不能同时出现,一个字段属性只能有其中一条设置,当设置了auto_now,或auto_now_add时,也会让该字段默认具有blank=True(字段可以为空)属性

4.DatetimeField

datetime.datetime实例表示的日期和时间

DatetimeField(auto_now=False, auto_now_add=False,**options)
# auto_now_add: 创时使用当前时间 注册时间
# auto_now: 修改时自动更新为当前时间 用户上次登陆,修改ip
# 和 DateField 具有相同的字段属性

5.DecimalField

Decimal实例表示的十进制浮点数类型

DecimalField(max_digits=None,decimal_places=None, **options)
'''
max_digits: 位数总数,包括小数点后的位数,必须大于 decimal_places 参数
decimal_places: 小数点后的数字数量,精度
'''

6.FloatField

使用float实例来表示的浮点数

FloatField(**options)

7.IntegerField

一个整数,范围由-21474836482147483647

IntegerField(**options)

二、字段属性

1.null

如果该值为True,将在数据库中将控制存储为NULL

# app/models.py下的模型类中
title = models.CharField(max_length=100,null=True)
# 允许title为空

2.blank

如果该值为True,则在验证时该字段值可以为空

null为数据库存储层面可以为空,而blank为表单验证层面可以填写空值

3.choices

一个二元组的列表或元组,元组中第一个值为真正在数据库中存储的值,第二个值为该选项的描述

class studentModel(models.Model):
  GENDER_CHOICES = [
        (1, '男'),
        (2, '女'),
        (3, '保密'),
    ]
    gender = models.IntegerField(verbose_name='性别', default=3, choices=GENDER_CHOICES)

4.db_column

数据库中用来表示该字段的名称,如果未指定,那么 Django 将会使用Field名作为字段名

5.db_index

当该值为True时,为该字段创建索引

6.default

为字段提供默认值

7.primary_key

设置该值为True时,该字段成为模型的主键字段,一个模型类同时只能有一个主键

如果一个表中不存在任意一个设置好的主键字段,django 会自动设置一个自增AutoField字段来充当主键,该值可以用pkid方式获取。主键的设置还意味着,null=Falseunique=True

8.unique

如果该值为True,代表这个数据在当前的表中有唯一值,这个字段还会在模型层验证存储的数据是否唯一

9.verbose_name

给字段的一个可读性更高的名称,如果没有设置该值,字段名中的下换线转换成空格,作为当前字段的数据库中名称


三、模型类元选项

    在模型类的Meta类中,可以提供一系列的元选项,可以方便对该模型类进行属性设置或约束等。

class TestTable(models.Model):
    class Meta:
        db_table= 'test'
        verbose_name_plural = '测试表'

1.abstract

代表当前模型类为抽象基类,不会创建真正的数据表,只是为了其他模型类继承使用

abstract = True

2.app_label

当模型类被定义在了其他 app 下,这个属性用来描述当前表属于哪个 app 应用

app_label = "MyApp"

3.abstract

代表当前模型类为抽象基类,不会创建真正的数据表,只是为了其他模型类继承使用

abstract = True

4.db_table

    当前模型类所对应的表名,未设置时,django 默认将表名与 app 名由下划线组成,作为表名

    这个表名为真实在数据库中所使用的,所以该元选项的使用应在数据表创建之前

    如果在表已经存在的情况下去修改,会导致数据库内表与模型类表名不一致而查找不到报错

5.ordering

1.当前表中的数据存储时的排序规则,这是一个字段名的字符串,可以是一个列表或元组;

2.每一个字符串前可以使用"-“来倒序排序,使用”?"随机排序

3.ordering 排序规则的添加,也会增加数据库的开销

ordering = ['-birthday', 'age']
#先按照 birthday 倒序排序,再按照 age 字段进行排序。

6.verbose_name

一般设置该表展示时所用的名称,名称被自动处理为复数,字符串后加一个"s"

ordering = ['-birthday', 'age']
#先按照 birthday 倒序排序,再按照 age 字段进行排序。

7.verbose_name_plural

verbose_name功能相同,但是不会自动在字符串后加"s"以表复数

设置表的复数名称

8.ordering

1.当前表中的数据存储时的排序规则,这是一个字段名的字符串,可以是一个列表或元组;

2.每一个字符串前可以使用"-“来倒序排序,使用”?"随机排序

3.ordering 排序规则的添加,也会增加数据库的开销

ordering = ['-birthday', 'age']
#先按照 birthday 倒序排序,再按照 age 字段进行排序。

四、ORM增删改查

0.ORM的增删改查

#   增  
    1、obj = 模型类(属性=数据)  obj.save()
    2、模型类.objects.create(属性=数据)
#   查 
    模型类.objects.all()  模型类.objects.get() 模型类.objects.filter()
#   删  
   obj = 模型类.objects.get()
    obj.delete()
    模型类.objects.filter(属性=条件).delete()
#   改  
    obj = 模型类.objects.get()
    obj.属性=新值
    obj.save()
    模型类.objects.filter(属性=条件).update(属性=新值)
注意:
  1.增:save()没有返回值,create()一步到位
  2.查:all()、filter()、exclude()、get()、
  3.查找时的一些特殊字段的使用:
  order_by()
    Person.objects.order_by('age')
    Person.objects.all().order_by('-age')
  4.count():返回数据库中对应字段的个数,并且该函数永远不会引发异常
  5.values():返回一个查询集结果,但是迭代访问时返回的是字典,而不是数据实例对象
  models.Person.objects.all().values()
  models.Person.objects.values()
  6.链式过滤条件

1.增加数据

新建一个子应用 news

# news/models.py
from django.db import models
# Create your models here.
class newsModel(models.Model):
    title = models.CharField(max_length=100)
    content = models.TextField()
    visit_num = models.IntegerField(default=0)
    good_num = models.IntegerField(default=0)
    pub_date = models.DateTimeField(default='2024-5-30')
    def __str__(self):
        return self.title
    class Meta:
        db_table = 'news'
        verbose_name_plural = '新闻表'

创建对象:

# news/views
def addData(request):
    # 添加数据的两种方式
    # n1 = newsModel()
    # n1.title = "方式一:新闻标题"
    # n1.content = "方式一:新闻内容"
    # n1.save()
    n2 = newsModel.objects.create(title="方式二:新闻标题",content="方式二:新闻内容")
    return HttpResponse('{"message":"增加数据成功!"}',content_type="application/json")

2.查找对象

def queryData(request):
    # 1.查询所有,并返回结果集(以id为降序查询)
    # n1 = newsModel.objects.all().order_by('-id')
    # for i in n1:
    #     print(i.title)
    #     print(i.content)
    #     print(i.visit_num)
    #     print(i.good_num)
    #     print(i.pub_date)
    #     print("-"*16)
    # 2.使用get查询的时候,默认使用id,如果使用其他数据查询,保证数据唯一
    # try:
    #     n2 = newsModel.objects.get(id=2)
    # except Exception as e:
    #     print(e)
    # 3.返回的也是根据条件过滤的结果集(阅读量大于100,点赞量大于50)
    n3 = newsModel.objects.filter(visit_num__gt=100).filter(good_num__gt=50)
    for i in n3:
        print(i.title)
        print(i.content)
        print(i.visit_num)
        print(i.good_num)
        print(i.pub_date)
        print("-"*16)
    #4.查找符合条件以外的数据
    # n4 = newsModel.objects.exclude(good_num=0)
    return HttpResponse('{"message":"返回数据展示!"}',content_type="application/json")

查询中用到的一些字段:

a.order_by(*field)

默认情况下,数据表使用模型类中的 Meta 中指定的 ordering 选项进行排序

也可以通过使用 order_by 函数进行查询结果的排序

Person.objects.order_by('age')
Person.objects.all().order_by('-age')
b.count()

返回数据库中对应字段的个数,并且该函数永远不会引发异常

models.Person.objects.filter(age=20).count()
Person.objects.count()
c.order_by(*field)

默认情况下,数据表使用模型类中的 Meta 中指定的 ordering 选项进行排序

也可以通过使用 order_by 函数进行查询结果的排序

Person.objects.order_by('age')
Person.objects.all().order_by('-age')

注意:所以有时使用已生产好的结果集,通过len*函数获取长度,这种方式效率会更高;count方法的调用会导致额外的数据库查询

d.values(*fields)

返回一个查询集结果,但是迭代访问时返回的是字典,而不是数据实例对象

models.Person.objects.all().values()
models.Person.objects.values()

3.链式过滤条件

contains:

大小写敏感的匹配查询,也是 like,注意转换后查询条件的两侧都有%

Person.objects.filter(name__contains='好')

icontains:

大小写不敏感的匹配查询

Person.objects.filter(name__icontains='好')

range:

在某个范围内进行查询

Person.objects.filter(id__range=(1,6))

in:

在某个范围内进行查询

Person.objects.filter(id__in=(1,6))
Person.objects.filter(id__in=[1,6])

exact:

如果在查询过程中,没有提供查询类型(没有双下划线),那么查询类型就会被默认指定为exact,这是一种严格查找的方式,用来在数据库中查找和查询时的关键词参数完全一致的内容

Person.objects.filter(account='root')
Person.objects.filter(account__exact='root')

iexact:

忽略大小写的匹配

Person.objects.filter(account__iexact='root')
#匹配到的结果可能是 Root,ROot,ROOt,ROOT

startswith、endswith:

分别匹配开头和结尾,区分大小写

Person.objects.filter(passwd__startswith='admin')
# 匹配以 admin 开头的数据

istartswith、iendswith:

分别匹配开头和结尾,忽略大小写

Person.objects.filter(passwd__istartswith='admin')
匹配以不区分大小写的字符串 admin 为开头的数据

gte:

大于或等于

Person.objects.filter(reg_data__gte=datetime.date.today)

lte:

小于或等于

Person.objects.filter(reg_data__lte=datetime.date.today)

4.修改对象

def updateData(request):
    # 1.查询单个数据,进行修改(id = 1)
    n1 = newsModel.objects.get(id=1)
    n1.title = "修改后的新闻标题"
    n1.content = "修改后的新闻内容"
    n1.save()
    #2.通过过滤结果集,修改数据
    # n2 = newsModel.objects.filter(visit_num=0).update(visit_num=150)
    # n3 = newsModel.objects.filter(good_num=0).update(good_num=75)
    # print(n2)
    # print(n3)
    return HttpResponse('{"message":"修改数据成功!"}',content_type="application/json")

5.删除对象

def removeData(request):
    # 1.全部删除
    # newsModel.objects.all().delete()
    # 2.先get查询,再删除数据(id = 2)
    n1 = newsModel.objects.get(id=2)
    n1.delete()
    # 3.根据filter过滤,删除查询到的数据(点赞量等于0的数据)
    # n2 = newsModel.objects.filter(good_num=0).delete()
    # print(n2)
    return HttpResponse('{"message":"删除数据成功!"}',content_type="application/json")

6.ORM的Q、F查询

Q查询:

之前的查询都是对象的属性与常量值比较,两个属性怎么比较呢?

  • 使用F对象,被定义在django.db.models中。
  • 可以在F对象上使用算数运算。
from django.db.models import F
F('属性名')  # 注意:属性名是字符串形式
1.查询阅读量大于评论量的图书
Book.objects.filter(bread__gt=F('bcomment'))
2.查询阅读量是评论量2倍的图书
Book.objects.filter(bread=F('bcomment')*2)
3.查询阅读量比评论量多100的图书
Book.objects.filter(bread=F('bcomment')+100)

F查询:

  • 多个过滤器逐个调用表示逻辑与and关系,同sql语句中where部分的and关键字。
  • 如果需要实现逻辑或or的查询,需要使用Q对象结合逻辑运算符Q对象被义在django.db.models中。
  • Q对象可以使用&|连接,&表示逻辑与,|表示逻辑或。
from django.db.models import Q
Q(属性名__运算符=值)  # 注意: 属性名不是字符串,不能加引号
1.查询id阅读量大于20且id小于3的图书
Book.objects.filter(bcomment__gt=20).filter(id__lt=3)  # 多个过滤器连续操作
Book.objects.filter( Q(bcomment__gt=20) & Q(id__lt=3) )  # 使用Q对象和逻辑运算符
2.查询阅读量大于20,或编号小于3的图书
Book.objects.filter( Q(bcomment__gt=20) | Q(id__lt=3) )  # 只能使用Q对象

7.QuerySet

查询结果集:表示从数据库中获取的对象集合。

当调用如下过滤器方法时,Django会返回查询集(而不是简单的列表):

  • all():返回所有数据。
  • filter():返回满足条件的数据。
  • exclude():返回满足条件之外的数据。
  • order_by():对结果进行排序。
# 1.惰性查询-懒加载
# 2.缓存
queryset[0].name
queryset[0:2]

注意:创建结果集的过程不涉及任何数据库的操作,查询工作是惰性的,在上面的查询方式中,查询代码不会实际访问数据库,只有查询集在真正使用时,django 才会访问数据库

相关文章
|
3天前
|
关系型数据库 MySQL 数据库
数据迁移脚本优化过程:从 MySQL 到 Django 模型表
在大规模的数据迁移过程中,性能问题往往是开发者面临的主要挑战之一。本文将分析一个数据迁移脚本的优化过程,展示如何从 MySQL 数据库迁移数据到 Django 模型表,并探讨优化前后的性能差异。
|
4天前
|
JSON API 数据格式
Django REST framework序列化器详解:普通序列化器与模型序列化器的选择与运用
Django REST framework序列化器详解:普通序列化器与模型序列化器的选择与运用
|
4天前
|
关系型数据库 MySQL 数据库
Django与MySQL:配置数据库的详细步骤
Django与MySQL:配置数据库的详细步骤
|
1天前
|
关系型数据库 MySQL 数据库
『Django』模型入门教程-操作MySQL
一个后台如果没有数据库可以说废了一半。日常开发中大多数时候都在与数据库打交道。Django 为我们提供了一种更简单的操作数据库的方式。 在 Django 中,模型(Model)是用来定义数据库结构的类。每个模型类通常对应数据库中的一个表,类的属性对应表中的列。通过定义模型,Django 的 ORM(Object-Relational Mapping)可以将 Python 对象映射到数据库表,并提供一套 API 来进行数据库操作。 本文介绍模型的用法。
|
4天前
|
JSON 前端开发 API
Django API开发实战:前后端分离、Restful风格与DRF序列化器详解
Django API开发实战:前后端分离、Restful风格与DRF序列化器详解
|
4天前
|
JSON 搜索推荐 数据库
Django REST framework数据展示技巧:分页、过滤与搜索的实用配置与实践
Django REST framework数据展示技巧:分页、过滤与搜索的实用配置与实践
|
4天前
|
JSON 缓存 数据库
Django ORM的QuerySet:解锁数据库交互的魔法钥匙
Django ORM的QuerySet:解锁数据库交互的魔法钥匙
|
4天前
|
中间件 开发者 C++
Django中间件探索:揭秘中间件在Web应用中的守护角色与实战应用
Django中间件探索:揭秘中间件在Web应用中的守护角色与实战应用
|
4天前
|
前端开发 Python
Django框架中Ajax GET与POST请求的实战应用
Django框架中Ajax GET与POST请求的实战应用
|
4天前
|
存储 安全 数据库
Django ORM深度游:探索多对一、一对一与多对多数据关系的奥秘与实践
Django ORM深度游:探索多对一、一对一与多对多数据关系的奥秘与实践