Django之模型定义与ORM操作

Django型与ORM

Django模型(Model)是一个Python类,它定义了和数据库表格中的字段对应的属性和方法。

在Django ORM中,模型通过继承django.db.models.Model来创建,每个模型对应数据库中的一张表,而模型的属性则对应表格中的字段。

通过定义模型,开发人员可以使用Python代码操作数据库,而无需直接编写SQL语句。

在这里插入图片描述

搭建基础项目环境

创建项目

django-admin startproject demo

创建应用

python manager.py startapp user

settings.py配置文件中注册应用

INSTALLED_APPS = [
    # 添加应用
    'user.apps.UserConfig'
]

配置MySQL

Django对各种数据库提供了很好的支持,包括:PostgreSQL、MySQL、SQLite、Oracle。Django为这些数据库提供了统一的调用API。这里使用MySQL数据库

Django默认初始配置使用sqlite数据库。

DATABASES = {
    
    
    'default': {
    
    
        'ENGINE': 'django.db.backends.sqlite3',
        'NAME': BASE_DIR / 'db.sqlite3',
    }
}

安装MySQL驱动

使用MySQL数据库首先需要安装驱动程序

pip install PyMySQL

配置DATABASES信息

修改DATABASES节点配置信息,主要是指定数据库引擎、主机地址、端口、用户名、密码、数据库名称等信息

DATABASES = {
    
    
    'default': {
    
    
        'ENGINE': 'django.db.backends.mysql',
        'HOST': '127.0.0.1',  # 数据库主机
        'PORT': 3306,  # 数据库端口
        'USER': 'root',  # 数据库用户名
        'PASSWORD': '123456',  # 数据库用户密码
        'NAME': 'demo'  # 数据库名字
    }
}

在MySQL中创建数据库

create database demo charset=utf8;

配置Django的ORM

配置Django的ORM以mysqldb的方式调用PyMySQL。只需要在Django的工程同名子目录的__init__.py文件中进行配置

import pymysql

pymysql.install_as_MySQLdb()

在这里插入图片描述

模型类

定义模型类

模型类被定义在"应用/models.py"文件中。

类名:通常使用大写字母开头的单词表示数据表名,例如class User(models.Model)。

属性:每个属性都对应数据库表格中的一个字段,例如CharField、IntegerField等,还可以自定义字段类型。

方法:模型类可以定义很多方法,用于实现数据操作逻辑,例如增删改查等。

Meta类:Meta类是用于定义模型元信息的类,比如指定表格名称、排序方式、关联表格等。
from django.db import models


# Create your models here.
class UserInfo(models.Model):
    GENDER_CHOICES = (
        (0, '未知'),
        (1, '男'),
        (2, '女')
    )

    # 创建字段 = 字段类型 字段宽度 字段说明 字段默认值
    name = models.CharField(max_length=5, verbose_name='姓名')
    age = models.IntegerField(default=0, verbose_name='年龄')
    gender = models.SmallIntegerField(choices=GENDER_CHOICES, default=0, verbose_name='性别')
    create_date = models.DateField(verbose_name='创建日期', null=True)
    is_delete = models.BooleanField(default=False, verbose_name='逻辑删除')

    # 模型类如果未指明表名,Django默认以小写app应用名_小写模型类名为数据库表名
    class Meta:
        db_table = 'user'  # 指明数据库表名
        verbose_name = '用户信息'  # 在admin站点中显示的名称

    # 定义每个数据对象的显示信息
    def __str__(self):
        return self.name


class Address(models.Model):
    description = models.CharField(max_length=100, null=True, verbose_name='详细地址')
    user = models.ForeignKey(UserInfo, on_delete=models.CASCADE, verbose_name='用户')  # 外键 对应数据库字段user_id

    class Meta:
        db_table = 'address'
        verbose_name = '地址信息'

    def __str__(self):
        return self.description

创建表结构

1.生成迁移文件,让 Django 知道模型有一些变更

python manage.py makemigrations

2.创建表结构,同步到数据库中

python manage.py migrate

字段类型

Django模型中的字段类型用来定义数据库表格中的数据类型。

类型 说明
AutoField 自动增长的IntegerField,通常不用指定,不指定时Django会自动创建属性名为id的自动增长属性
BooleanField 布尔字段,值为True或False
NullBooleanField 支持Null、True、False三种值
CharField 字符串,参数max_length表示最大字符个数
TextField 大文本字段,一般超过4000个字符时使用
IntegerField 整数
DecimalField 十进制浮点数, 参数max_digits表示总位数, 参数decimal_places表示小数位数
FloatField 浮点数
DateField 日期
参数auto_now表示每次保存对象时,自动设置该字段为当前时间,默认为False
参数auto_now_add表示当对象第一次被创建时自动设置当前时间,默认为False
参数auto_now_add和auto_now是相互排斥的,组合将会发生错误
TimeField 时间,参数同DateField
DateTimeField 日期时间,参数同DateField
FileField 上传文件字段
ImageField 继承于FileField,对上传的内容进行校验,确保是有效的图片

可选项配置

在Django模型中,每个字段类型都可以设置一些可选项来控制其行为和属性。

选项 说明
null 如果为True,表示允许为空,默认值是False
blank 如果为True,则该字段允许为空白,默认值是False
db_column 字段的名称,如果未指定,则使用属性的名称
db_index 若值为True, 则在表中会为此字段创建索引,默认值是False
default 默认
primary_key 若为True,则该字段会成为模型的主键字段,默认值是False,一般作为AutoField的选项使用
unique 如果为True, 这个字段在表中必须有唯一值,默认值是False

外键

Django中外键(ForeignKey)是模型之间关联的一种方式。它定义了一个指向另一个模型的关系,使用其他模型的主键作为外键。

在设置外键时,需要通过on_delete选项指明主表删除数据时,对于外键引用表数据如何处理,在django.db.models中包含了可选常量:

常量 说明
CASCADE 级联 删除主表数据时连通一起删除外键表中数据
PROTECT 保护 通过抛出ProtectedError异常,来阻止删除主表中被外键应用的数据
SET_NULL 设置为NULL,仅在该字段null=True允许为null时可用
SET_DEFAULT 设置为默认值,仅在该字段设置了默认值时可用
SET() 设置为特定值或者调用特定方法
DO_NOTHING 不做任何操作,如果数据库前置指明级联性,此选项会抛出IntegrityError异常

Address模型定义了一个外键字段,它指向 UserInfo模型。参数 on_delete=models.CASCADE 定义了当关联的 UserInfo 对象被删除时,与其相关联的 Address对象应该如何处理(删除与之关联的所有 Address对象)

class UserInfo(models.Model):
    name = models.CharField(max_length=5, verbose_name='姓名')

class Address(models.Model):
    description = models.CharField(max_length=100, null=True, verbose_name='详细地址')
    user = models.ForeignKey(UserInfo, on_delete=models.CASCADE, verbose_name='用户')

shell工具

Django的shell工具是一个交互式Python环境,用于执行Django应用程序中的各种操作。使用shell工具,我们可以在命令行中直接访问Django的模型和查询集API,并对它们进行测试、调试和探索。

启动shell工具非常简单,只需要在Django项目的根目录中运行以下命令即可:

python manage.py shell
(py3) D:\WorkSpace\Python\demo>python manage.py shell
Python 3.9.5 (tags/v3.9.5:0a7dcbd, May  3 2021, 17:27:52) [MSC v.1928 64 bit (AMD64)] on win32
Type "help", "copyright", "credits" or "license" for more information.
(InteractiveConsole)
>>>

进入shell环境,就可以使用Python交互式解释器来执行各种操作

# 导入Person模型
from myapp.models import UserInfo

# 创建一个新的人员记录
user = UserInfo(name='John', age=25)
user.save()

# 查询所有年龄小于30岁的人员
user = UserInfo.objects.filter(age__lt=30)

增、删、改

增加

save:通过创建模型类对象,执行对象的save()方法保存到数据库中

>>> from user.models import UserInfo
>>> user = UserInfo(name='Jack', age=20, gender=1, create_date='2023-01-09', is_delete=False)
>>> user.save()
>>> user
<UserInfo: Jack>
>>>

create:通过模型类.objects.create()保存

>>> from user.models import UserInfo
>>> UserInfo.objects.create(name='Jack', age=20, gender=1, create_date='2023-01-09', is_delete=False)
<UserInfo: Jack>
>>>

修改

save:修改模型类对象的属性,然后执行save()方法

>>> user = UserInfo.objects.get(id=1)
>>> user.name='小白'
>>> user.save()
>>> user
<UserInfo: 小白>
>>> 

update:使用模型类.objects.filter().update(),会返回受影响的行数

>>> UserInfo.objects.filter(name='小白').update(name='Jack')
1
>>>

删除

模型类对象delete方法

>>> user = UserInfo.objects.get(id=1)
>>> user.delete()
(1, {
    
    'user.UserInfo': 1})
>>>

模型类.objects.filter().delete()

>>> UserInfo.objects.filter(name='Jack').delete()
(1, {
    
    'user.UserInfo': 1})
>>>

查询

基础条件查询

基本查询

get:查询单一结果,如果不存在会抛出模型类.DoesNotExist异常

>>> UserInfo.objects.get(id=1)

all:查询多个结果

>>> UserInfo.objects.all()
<QuerySet [<UserInfo: Jack>, <UserInfo: 小白>]>
>>>

count:查询结果数量

>>> UserInfo.objects.count()
2
>>>

过滤查询

过滤条件查询,提供三个方法,其用法基本一致

filter:查询符合条件的数据

exclude:查询不符合条件的数据

get:查询符合条件的返回模型类对象,符合条件的对象只能为一个,如果符合筛选条件的对象超过了一个或者没有一个都会抛出错误
UserInfo.objects.filter(name='Django')

UserInfo.objects.exclude(name='Django')

UserInfo.objects.get(name='Django')

比较运算符

等值查询

exact:判断是否相等
>>> UserInfo.objects.get(id=1)
<UserInfo: Jack>
>>> UserInfo.objects.get(id__exact=1)
<UserInfo: Jack>
>>>

模糊查询

contains:是否包含

startswith、endswith:以指定值开头或结尾
>>> UserInfo.objects.filter(name__contains='Ja')
<QuerySet [<UserInfo: Jack>, <UserInfo: Jack>]>
>>> UserInfo.objects.filter(name__startswith='Ja')
<QuerySet [<UserInfo: Jack>, <UserInfo: Jack>]>
>>>

注意:

1.属性名称和比较运算符间使用两个下划线分割,因此属性名不能包括多个下划线

2.以上运算符都区分大小写,在这些运算符前加上i表示不区分大小写,如iexact、icontains、istartswith、iendswith

空查询

isnull:是否为null
>>> UserInfo.objects.filter(name__isnull=True)
<QuerySet []>

范围查询

in:是否包含在范围内

查询ID为1或3的数据

>>> UserInfo.objects.filter(id__in=[1,3])
<QuerySet [<UserInfo: Jack>, <UserInfo: Jack>]>

比较查询

gt:大于 (greater then)
gte:大于等于 (greater then equal)
lt:小于 (less then)
lte:小于等于 (less then equal)
不等于:使用exclude()过滤器
>>> UserInfo.objects.filter(id__gt=4)

日期查询

year、month、day、week_day、hour、minute、second:对日期时间类型的属性进行运算。

>>> UserInfo.objects.filter(create_date__year=2023)
<QuerySet [<UserInfo: Jack>, <UserInfo: 小白>, <UserInfo: Jack>]>
>>> UserInfo.objects.filter(create_date__gt='2022-01-01')
<QuerySet [<UserInfo: Jack>, <UserInfo: 小白>, <UserInfo: Jack>]>
>>>

聚合函数

聚合函数是一种查询结果的汇总计算方法。聚合函数可以将多个查询结果合并为一个单一的结果。Django提供了多个内置聚合函数

Avg():返回给定字段的平均值
Count():返回匹配查询条件的结果数
Max():返回给定字段的最大值
Min():返回给定字段的最小值
Sum():返回给定字段的总和

使用aggregate()过滤器调用聚合函数

>>> from django.db.models import Sum
>>> UserInfo.objects.aggregate(Avg('age'))

使用count时一般不使用aggregate()过滤器,count函数返回值是一个数字

UserInfo.objects.count()

排序

使用order_by对结果进行排序

默认升序

>>> UserInfo.objects.all().order_by('id')

降序

按照降序排序,在字段前使用 -(减号)标识

>>> UserInfo.objects.all().order_by('-id')

基本关联查询

由一到多的访问语法:一对应的模型类对象.多对应的模型类名小写_set

查询一个用户对应的多个地址信息

>>> from user.models import UserInfo
>>> user = UserInfo.objects.get(id=1)
>>> user.address_set.all()
<QuerySet [<Address: 某省某城市某区1>, <Address: 某省某城市某区2>]>

由多到一的访问语法: 多对应的模型类对象.多对应的模型类中的关系类属性名

查询一个地址对应的用户

>>> from user.models import Address
>>> address = Address.objects.get(id=1)
>>> address.user
<UserInfo: Jack1>
>>>

访问一端对应的模型类关联对象的id语法: 多对应的模型类对象.关联类属性_id

查询一个地址对应用户的id值

>>> address = Address.objects.get(id=1)
>>> address.user_id
4

关联过滤查询

由多模型类条件查询一模型类数据: 关联模型类名小写__属性名__条件运算符=值

查询用户信息,并且地址信息包含’四川省’

>>> user = UserInfo.objects.filter(address__description__contains='四川省')
>>> user 

由一模型类条件查询多模型类数据: 一模型类关联属性名__一模型类属性名__条件运算符=值

查询Jack用户的所有地址信息

>>> address = Address.objects.filter(user__name='Jack')
>>> address

注意:如果没有"__运算符"部分,表示等于。

F对象

F对象可以在查询中对数据库字段进行操作,允许使用数据库本身的运算符来比较两个字段并对它们进行操作

导入F对象

from django.db.models import F

语法格式:

F(属性名)

查询id值大于等于age字段值

UserInfo.objects.filter(id__gt=F('age'))

更新查询中所有行中一个字段的值,使其等于另一个字段

UserInfo.objects.all().update(money=F('age'))

在F对象上使用算数运算

UserInfo.objects.filter(id__gt=F('age') / 2)

Q对象

Q对象是用于构造复杂查询的工具。它可以将多个条件组合成一个复杂的查询,并且可以与其他查询操作符一起使用。

导入Q对象

from django.db.models import Q

逻辑或

Q对象用于实现逻辑或的查询。

语法:

Q(属性名__运算符=)

Q对象可以使用&、|连接

&:表示逻辑与

|:表示逻辑或

Q对象也可以使用~操作符,表示非not

>>> UserInfo.objects.filter(~Q(id=2))

查询id值大于5,或则id小于10

UserInfo.objects.filter(Q(id__gt=5)|Q(id__lt=10))

逻辑与

多个过滤器逐个调用表示逻辑与关系,同sql语句中where部分的and关键字

查询id值大于5,并且id小于10

>>> UserInfo.objects.filter(id__gt=5,id__lt=10)
>>> UserInfo.objects.filter(id__gt=5).filter(id__lt=3)

查询姓名是F或者姓名是Q的用户,且年龄在18岁以上

>>> UserInfo.objects.filter(Q(name='F') | Q(name='Q'), age__gte=18)

查询集QuerySet

概念

查询集(QuerySet)是一种表示数据库中一组数据的对象。它是从模型中检索出来的数据集合,并且可以进行过滤、排序、限制等操作。

查询集,也称查询结果集、QuerySet,表示从数据库中获取的对象集合。

查询集可以含有零个、一个或多个过滤器。过滤器基于所给的参数限制查询的结果。从SQL的角度讲,查询集与select语句等价,过滤器像where、limit、order by子句。

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

all():返回所有数据

filter():返回满足条件的数据

exclude():返回满足条件之外的数据

order_by():对结果进行排序

判断一个查询集中是否有数据

exists():判断查询集中是否有数据,如果有则返回True,没有则返回False

查询集支持链式调用,对查询集可以再次调用过滤器进行过滤

>>> user = UserInfo.objects.filter(age__gt=15).order_by('create_date')
>>>> user.exists()
True
>>> user
<QuerySet [<UserInfo: Jack1>, <UserInfo: Jack2>, <UserInfo: Jack3>, <UserInfo: Jack4>]>

访问查询集

for user in users:
    print(user.name, user.age)

获取前五个人的查询集

users = UserInfo.objects.all()[:5]

两大特性

1.惰性执行

创建查询集不会访问数据库,直到调用数据时,才会访问数据库,调用数据的情况包括迭代、序列化、与if合用

当执行如下语句时,并未进行数据库查询,只是创建了一个查询集

# 只创建查询集,并未进行数据库查询
>>> users = UserInfo.objects.all()

# 真正进行数据库查询
for user in users:
    print(user.name)

2.缓存

使用同一个查询集,第一次使用时会发生数据库的查询,然后Django会把结果缓存下来,再次使用这个查询集时会使用缓存的数据,减少了数据库的查询次数。

情况1:如下两个查询集,无法重用缓存,每次查询都会与数据库进行一次交互,增加了数据库的负载。

>>> [user.id for user in UserInfo.objects.all()]
[1, 2, 3, 4]
>>> [user.id for user in UserInfo.objects.all()]
[1, 2, 3, 4]

情况2:经过存储后,可以重用查询集,第二次使用缓存中的数据。

>>> users =UserInfo.objects.all()
>>> [user.id for user in users]
[1, 2, 3, 4]
>>> [user.id for user in users]
[1, 2, 3, 4]

限制查询集

限制操作是非常常见的查询集操作之一,在Django中非常方便易用。无论是切片、跳过、获取第一个/最后一个对象还是计算结果数,都可以轻松地实现。这些操作通常是通过Python的切片语法来实现的。

可以对查询集进行取下标或切片操作,等同于sql中的limit和offset子句。查询集进行切片后返回一个新的查询集,不会立即执行查询。

如果获取一个对象,直接使用[0],等同于[0:1].get(),但是如果没有数据,[0]引发IndexError异常,[0:1].get()如果没有数据引发DoesNotExist异常。

获取第1、2项,限制为前2个人

>>> users = UserInfo.objects.all()[0:2]
>>> users
<QuerySet [<UserInfo: Jack1>, <UserInfo: Jack2>]>

使用first()和last()方法来获取查询集中的第一个和最后一个对象

与切片不同,first()和last()方法只返回一个结果,而不是返回整个查询集。

UserInfo.objects.order_by('age').first()

UserInfo.objects.order_by('age').last()

分页

在Django中,可以使用Paginator类来进行分页。

#查询数据
>>> users = UserInfo.objects.all().order_by("id")
#导入分页类
>>> from django.core.paginator import Paginator
#创建分页实例
>>> paginator=Paginator(users,2)
#获取指定页码的数据
>>> page_num = paginator.page(1)
#获取分页数据
>>> total_page=paginator.num_pages
>>> 
>>> page_num
<Page 1 of 2>
>>> total_page
2

猜你喜欢

转载自blog.csdn.net/qq_38628046/article/details/128177119