class OrganizationPayImg(BaseStatusModel):
name = models.CharField('组织二维码名称',null=True, max_length=100)
organization_id = models.IntegerField('组织id', null=True, db_index=True)
url = models.CharField('组织二维码地址', null=True, max_length=255)
payway = models.CharField('支付类型', null=True, max_length=64)
class Meta:
db_table = 'organization_pay_img'
verbose_name = '组织收款二维码'
verbose_name_plural = verbose_name
事务
with transaction.atomic():
代码
1、创建项目
django-admin startproject bookmanager
2、创建应用
python manage.py startapp book
3、数据库配置
在settings.py中保存了数据库的连接配置信息,Django默认初始配置使用sqlite数据库。
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.sqlite3',
'NAME': os.path.join(BASE_DIR, 'db.sqlite3'),
}
}
使用MySQL数据库首先需要安装驱动程序
pip install PyMySQL
在Django的工程同名子目录的__init__.py文件中添加如下语句
import pymysql
pymysql.install_as_MySQLdb()
修改DATABASES配置信息
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.mysql',
'HOST': '127.0.0.1', # 数据库主机
'PORT': 3306, # 数据库端口
'USER': 'root', # 数据库用户名
'PASSWORD': 'mysql', # 数据库用户密码
'NAME': 'book' # 数据库名字
}
}
4、数据库表创建
1)字段类型
类型 | 说明 |
---|---|
AutoField | 自动增长的IntegerField,通常不用指定,不指定时Django会自动创建属性名为id的自动增长属性 |
BooleanField | 布尔字段,值为True或False |
NullBooleanField | NullBooleanField |
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,对上传的内容进行校验,确保是有效的图片 |
SmallIntegerField | tinyint类型 |
2) 选项
选项 | 说明 |
---|---|
null | 如果为True,表示允许为空,默认值是False |
blank | 如果为True,则该字段允许为空白,默认值是False |
db_column | 字段的名称,如果未指定,则使用属性的名称 |
db_index | 若值为True, 则在表中会为此字段创建索引,默认值是False |
default | 默认值 |
primary_key | 若为True,则该字段会成为模型的主键字段,默认值是False,一般作为AutoField的选项使用 |
unique | 如果为True, 这个字段在表中必须有唯一值,默认值是False |
verbose_name | 备注 |
on_delete | 绑定外键类型 |
max_length | 长度max_length=50 |
db_constraint | 用于外键(ForeignKey)或多对多(ManyToManyField)关系,控制是否在数据库层面创建关联约束。默认值true |
blank | 作用:控制字段在表单验证时是否允许为空值(空字符串或空数据)。默认值:False |
on_delete=models.CASCADE
3) 外键
在设置外键时,需要通过on_delete选项指明主表删除数据时,对于外键引用表数据如何处理,在django.db.models中包含了可选常量:
类型 | 说明 |
---|---|
CASCADE | 级联,删除主表数据时连通一起删除外键表中数据 |
PROTECT | 保护,通过抛出ProtectedError异常,来阻止删除主表中被外键应用的数据 |
SET_NULL | 设置为NULL,仅在该字段null=True允许为null时可用 |
SET_DEFAULT | 设置为默认值,仅在该字段设置了默认值时可用 |
SET() | 设置为特定值或者调用特定方法 |
DO_NOTHING | 不做任何操作,如果数据库前置指明级联性,此选项会抛出IntegrityError异常 |
on_delete=models.CASCADE
配置文件夹
INSTALLED_APPS = [
'django.contrib.admin',
'django.contrib.auth',
# ...其他默认应用
'book', # 添加你的应用名称
]
book的models.py
from django.db import models
# Create your models here.
# 准备书籍列表信息的模型类
class BookInfo(models.Model):
# 创建字段,字段类型...
name = models.CharField(max_length=20, verbose_name='名称')
pub_date = models.DateField(verbose_name='发布日期',null=True)
readcount = models.IntegerField(default=0, verbose_name='阅读量')
commentcount = models.IntegerField(default=0, verbose_name='评论量')
is_delete = models.BooleanField(default=False, verbose_name='逻辑删除')
class Meta:
db_table = 'bookinfo' # 指明数据库表名
verbose_name = '图书' # 在admin站点中显示的名称
def __str__(self):
"""定义每个数据对象的显示信息"""
return self.name
# 准备人物列表信息的模型类
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='逻辑删除')
class Meta:
db_table = 'peopleinfo'
verbose_name = '人物信息'
def __str__(self):
return self.name
生成迁移文件
python manage.py makemigrations
同步到数据库中
python manage.py migrate
添加数据
insert into bookinfo(name, pub_date, readcount,commentcount, is_delete) values
('射雕英雄传', '1980-5-1', 12, 34, 0),
('天龙八部', '1986-7-24', 36, 40, 0),
('笑傲江湖', '1995-12-24', 20, 80, 0),
('雪山飞狐', '1987-11-11', 58, 24, 0);
insert into peopleinfo(name, gender, book_id, description, is_delete) values
('郭靖', 1, 1, '降龙十八掌', 0),
('黄蓉', 0, 1, '打狗棍法', 0),
('黄药师', 1, 1, '弹指神通', 0),
('欧阳锋', 1, 1, '蛤蟆功', 0),
('梅超风', 0, 1, '九阴白骨爪', 0),
('乔峰', 1, 2, '降龙十八掌', 0),
('段誉', 1, 2, '六脉神剑', 0),
('虚竹', 1, 2, '天山六阳掌', 0),
('王语嫣', 0, 2, '神仙姐姐', 0),
('令狐冲', 1, 3, '独孤九剑', 0),
('任盈盈', 0, 3, '弹琴', 0),
('岳不群', 1, 3, '华山剑法', 0),
('东方不败', 0, 3, '葵花宝典', 0),
('胡斐', 1, 4, '胡家刀法', 0),
('苗若兰', 0, 4, '黄衣', 0),
('程灵素', 0, 4, '医术', 0),
('袁紫衣', 0, 4, '六合拳', 0);
5、直接窗口操作
python manage.py shell
5、新增
from book.models import BookInfo,PeopleInfo
是一种新增
books = BookInfo(
name='大得',
pub_date='2010-1-1'
)
books.save()
第二种新增
PeopleInfo.objects.create(
name='大得',
book=books
)
6、修改
from book.models import PeopleInfo, BookInfo
是一种修改
person = PeopleInfo.objects.get(name='itheima')
person.name = '大得2'
person.save()
是二种修改
PeopleInfo.objects.filter(name='itcast').update(name='大得')
7、删除
from book.models import PeopleInfo, BookInfo
是一种删除
person = PeopleInfo.objects.get(name='大得')
person.delete()
是二种删除
BookInfo.objects.filter(name='python入门').delete()
8、基础查询
1、基础查询
基础查询
1、返回一个对象
data = BookInfo.objects.get(id=1)
data.name
2、查全部
BookInfo.objects.all()
过滤查询
filter过滤出多个结果
exclude排除掉符合条件剩下的结果
get过滤单一结果
查询id等于1的数组
data = BookInfo.objects.filter(id=1)
data[0].name
模糊查询__contains
BookInfo.objects.filter(name__contains='大')
不区分大小写模糊查询
__icontains
空查询
isnull:是否为null
BookInfo.objects.filter(name__isnull=True)
范围查询
in:是否包含在范围内
BookInfo.objects.filter(id__in=[1,3,5])
比较查询
__istartswith,模糊查询,张%
__range,范围区间,__range=(Decimal('10.00'), Decimal('50.00')),(10.00>=a or a<=50.00)
__ne,不等于
gt大于 (greater then)
gte大于等于 (greater then equal)
lt小于 (less then)
lte小于等于 (less then equal)
BookInfo.objects.filter(id__gt=3)
不等于的运算符,使用exclude()过滤器。
result = Book.objects.exclude(author="张三")
2、F和Q对象,F判断sql两个字段,Q条件
# readcount数据库字段1,commentcount数据库字段2
from django.db.models import F
BookInfo.objects.filter(readcount__gt=F('commentcount'))
乘2
BookInfo.objects.filter(readcount__gt=F('commentcount')*2)
Q对象,&是and,|是or
where = Q(id__gt=1)
where &= Q(name_id__gt=1)
where &= Q( Q(name_id__gt=1) | Q(name_id__gt=1))
BookInfo.objects.filter(Q(readcount__gt=20))
3、聚合函数
使用aggregate()过滤器调用聚合函数。聚合函数包括:Avg平均,Count数量,Max最大,Min最小,Sum
BookInfo.objects.aggregate(Sum('readcount'))
获得总数也可以这样写
BookInfo.objects.count()
汇总
queryset = OfflineOrderUUID.objects.filter(
order_payment__card_info_id=params_data.card_id,
order_payment__order_status__in=['ORDER_SUCCESS'],
order_payment__deduction_time__gte=ten_days_ago,
id__gt=popup.id
)
# 统计订单数量
order_count = queryset.aggregate(count=Count('id'))['count'] or 0
# 统计总金额(假设 origin_fee 是 order_payment 模型中的字段)
total_amount = queryset.aggregate(sum=Sum('order_payment__origin_fee'))['sum'] or Decimal('0.00')
4、 排序
# 默认升序
BookInfo.objects.all().order_by('id')
# 降序
BookInfo.objects.all().order_by('-id')
9、关联查询
由一到多的访问语法:
一对应的模型类对象.多对应的模型类名小写_set 例:
#peopleinfo是另外一张表,有一个book_id,_set方法是模型默认方法,会自动去找book_id,在主模型中无需有这个字段,peopleinfo模型有book外键
book = BookInfo.objects.get(id=1)
book.peopleinfo_set.all()
由多到一的查询语法:
#直接点book就可以了,因为有外键关联
person = PeopleInfo.objects.get(id=1)
person.book
访问一对应的模型类关联对象的id语法:
person = PeopleInfo.objects.get(id=1)
person.book_id
10、多模型查询
由多模型类条件查询
关联模型类名小写__属性名__条件运算符=值
BookInfo通过peopleinfo有book外键
book = BookInfo.objects.filter(peopleinfo__name='郭靖')
book = BookInfo.objects.filter(peopleinfo__description__contains='八')
PeopleInfo有book外键模型
PeopleInfo.objects.filter(book__name='天龙八部')
11、分页
from book.models import PeopleInfo, BookInfo
#导入分页类
from django.core.paginator import Paginator
#查询数据
books = BookInfo.objects.all()
#创建分页实例
paginator=Paginator(books,2)
#获取指定页码的数据
page_skus = paginator.page(1)
#获取总页数
total_page=paginator.num_pages
# 获取当前页的数据列表(核心)
current_page_data = page_skus.object_list
print(current_page_data)
paginator.count:总数据条数
paginator.num_pages:总页数(整数)
page_skus.number:当前页码
page_skus.has_next():是否有下一页
page_skus.has_previous():是否有上一页
page_skus.next_page_number():下一页页码(如果存在)
page_skus.previous_page_number():上一页页码(如果存在
12、多对多
假设我们有两个模型:Book(书籍)和Author(作者),一个书籍可以有多个作者,一个作者可以写多本书。
from django.db import models
class Author(models.Model):
name = models.CharField(max_length=50, verbose_name="作者姓名")
age = models.IntegerField(verbose_name="年龄")
def __str__(self):
return self.name
class Book(models.Model):
title = models.CharField(max_length=100, verbose_name="书名")
publish_date = models.DateField(verbose_name="出版日期")
# 定义多对多关系:一本书关联多个作者
authors = models.ManyToManyField(Author, related_name="books", verbose_name="作者")
def __str__(self):
return self.title
related_name="books" 用于定义从关联模型(这里是 Author 模型)反向引用当前模型(假设是 Book 模型)时使用的属性名。
没有设置 related_name 时,Django 会默认使用当前模型名的小写加上 _set 作为反向引用名(例如 author.book_set)
# 获取ID为1的作者
author = Author.objects.get(id=1)
# 通过related_name获取该作者的所有书籍
books_by_author = author.books.all()
related_name 的主要作用是提供一个更直观、可读性更好的反向引用方式,让代码更易理解。在这个例子中,author.books 显然比默认的 author.book_set 更符合自然语言习惯。
card_service应用名,CardUserGroup模型的方法名
card_user_groups = models.ManyToManyField('card_service.CardUserGroup', verbose_name="用户分组")
关键参数说明:
ManyToManyField(Author):表示与Author模型建立多对多关系
related_name="books":定义反向关联名称,通过作者可以用author.books查询其所有书籍
Django 会自动创建中间表(无需手动定义),用于存储多对多关系
定义模型后,执行迁移命令生成数据表:
python manage.py makemigrations
python manage.py migrate
多对多关系的操作
# 创建作者
author1 = Author.objects.create(name="张三", age=30)
author2 = Author.objects.create(name="李四", age=35)
# 创建书籍
book1 = Book.objects.create(title="Django入门", publish_date="2023-01-01")
book2 = Book.objects.create(title="Python高级编程", publish_date="2022-05-10")
# 给书籍添加作者(多对多关联)
book1.authors.add(author1, author2) # 一本书关联多个作者
book2.authors.add(author1) # 另一本书关联一个作者
# 也可以通过作者反向关联书籍
author2.books.add(book2) # 作者李四也关联book2
查询关联数据
# 1. 通过书籍查作者(正向查询)
book = Book.objects.get(title="Django入门")
authors = book.authors.all() # 获取这本书的所有作者
print(f"{book.title}的作者:{[a.name for a in authors]}")
# 2. 通过作者查书籍(反向查询,使用related_name)
author = Author.objects.get(name="张三")
books = author.books.all() # 获取这个作者的所有书籍
print(f"{author.name}的书籍:{[b.title for b in books]}")
# 3. 过滤查询(查询包含特定作者的书籍)
books = Book.objects.filter(authors__name="张三") # 查询张三写的所有书
修改关联关系
book = Book.objects.get(title="Django入门")
# 替换关联(移除现有所有作者,添加新作者)
book.authors.set([author1]) # 只保留author1
# 添加新关联(不会移除现有关联)
book.authors.add(author2) # 重新添加author2
# 移除某个关联
book.authors.remove(author1) # 移除author1
清空关联
book = Book.objects.get(title="Django入门")
book.authors.clear() # 清空这本书的所有作者关联(不会删除作者本身)
删除数据
# 删除作者(会自动删除中间表中的关联记录)
author = Author.objects.get(name="张三")
author.delete() # 同时删除该作者与所有书籍的关联
# 删除书籍(同理,会自动删除中间表关联)
book = Book.objects.get(title="Django入门")
book.delete()
自定义中间表(可选)
如果需要在多对多关系中存储额外信息(如 “作者在书中的角色”),可以自定义中间表:
class BookAuthor(models.Model):
book = models.ForeignKey(Book, on_delete=models.CASCADE)
author = models.ForeignKey(Author, on_delete=models.CASCADE)
role = models.CharField(max_length=50, verbose_name="角色(如:主编、合著)") # 额外字段
join_date = models.DateField(verbose_name="参与日期") # 额外字段
class Book(models.Model):
# ...其他字段
# 通过through指定自定义中间表
authors = models.ManyToManyField(Author, through=BookAuthor, through_fields=('book', 'author'))
使用自定义中间表时,关联操作需要通过中间表模型进行:
# 添加关联(带额外信息)
BookAuthor.objects.create(
book=book1,
author=author1,
role="主编",
join_date="2022-10-01"
)
多对多关系是 Django ORM 中非常灵活的关联方式,适用于需要双向多关联的场景。核心是通过ManyToManyField定义关系,然后使用add()/remove()/set()等方法管理关联。