单表、多表操作

一、单表操作

1.1 在python的脚本下调用Django环境

import os
 
if __name__ == '__main__':
    os.environ.setdefault("DJANGO_SETTINGS_MODULE", "day76.settings")
 
    import django
 
    django.setup()

1.2 用orm创建表

复制代码
from django.db import models


# Create your models here.


class Book(models.Model):
    # id 在建表时可以不用写,默认会自动添加

    name = models.CharField(max_length=55)
    price = models.CharField(max_length=11)
    publish = models.CharField(max_length=44)
    date = models.DateField(null=True)

    # 指定输出显示内容的格式
    def __str__(self):
        return 'name: %s, price: %s' % (self.name, self.price)
models.py
复制代码
  • 数据的迁移操作
python3 manage.py makemigrations    #只是对变化做一个记录,记录文件在app的migrations文件夹下
python3 manage.py migrate        #把更改提交到数据库
python3 manage.py showmigrations    #查看那个app中的数据没有提交到数据库,打×表示已提交

1.3 对数据的操作

  • 添加数据
# 方法一:
models.Book.objects.create(name='阿甘正传', price='23', publish='环球出版社', date='2018-8-8')
 
# 方法二:
import datetime
c_time = datetime.datetime.now()
book = models.Book(name='史前人类', price='68', publish='华夏出版社', date=c_time)
book.save()
  • 删除数据
# 方法一:
models.Book.objects.filter(name='史前人类').delete()
 
# 方法二:
book = models.Book.objects.filter(name='史前人类').first()
book.delete(
  • 修改数据
# 方法一:
book = models.Book.objects.filter(name='阿甘正传').update(price='44')
 
# 方法二:
book = models.Book.objects.filter(name='阿甘正传').first()
book.price = '55'
book.save()
  • 查询数据
1> all():                  查询所有结果                  
2> filter(**kwargs):       它包含了与所给筛选条件相匹配的对象     
3> get(**kwargs):          返回与所给筛选条件相匹配的对象,返回结果有且只有一个,如果符合筛选条件的对象超过一个或者没有都会抛出错误。
4> exclude(**kwargs):      它包含了与所给筛选条件不匹配的对象
5> order_by(*field):       对查询结果排序('-id')  
6> reverse():              对查询结果反向排序        
7> count():                返回数据库中匹配查询(QuerySet)的对象数量。  
8> first():                返回第一条记录     
9> last():                 返回最后一条记录       
10> exists():              如果QuerySet包含数据,就返回True,否则返回False   
11> values(*field):        返回一个ValueQuerySet——一个特殊的QuerySet,运行后得到的并不是一系列 model的实例化对象,而是一个可迭代的字典序列
12> values_list(*field):   它与values()非常相似,它返回的是一个元组序列,values返回的是一个字典序列          
13> distinct():            从返回结果中剔除重复纪录

1.4 数据的模糊查询

Book.objects.filter(price__in=[45,98,56]) 价格在[]的书
Book.objects.filter(price__gt=100)    大于
Book.objects.filter(price__lt=100)    小于
Book.objects.filter(price__gte=100)   大于等于
Book.objects.filter(price__lte=100)   小于等于
Book.objects.filter(price__range=[100,200])   在XX范围内
Book.objects.filter(name__contains="阿")     查询名字有'%阿%'的书
Book.objects.filter(name__icontains="python")  查询名字带python的书,忽略大小写
Book.objects.filter(name__startswith="神")    以'神'开头的书
Book.objects.filter(date__year=2017)        按年查询

 二、多表操作

案例:以下面这些概念,字段和关系查询
 
作者模型:一个作者有姓名和性别及其他详细信息。
 
作者详细模型:把作者的详情放到详情表,包含手机号,家庭住址等信息。作者详情模型和作者模型之间是一对一的关系(OneToOneField)
 
出版社模型:出版社有名称,所在城市以及email。
 
书籍模型: 书籍有书名、价格、作者(一本书可能会有多个作者,一个作者也可以写多本书),所以作者和书籍的关系就是多对多的关联关系(ManyToManyField),但是一本书只应该由一个出版社出版,所以出版社和书籍是一对多的关联关系(ForeignKey)。

2.1 创建表操作

  • 创建类,添加字段
复制代码
from django.db import models


# Create your models here.
class Book(models.Model):
    name = models.CharField(max_length=32)
    price = models.DecimalField(max_digits=5, decimal_places=2)
    publish = models.ForeignKey(to='Publish', to_field='id')
    authors = models.ManyToManyField(to='Author')

    def __str__(self):
        return self.name


class Author(models.Model):
    name = models.CharField(max_length=33)
    sex = models.IntegerField()

    # 一对一关系建议使用 OneToOneField
    author_details = models.OneToOneField(to='AuthorDetails')

    def __str__(self):
        return self.name


class AuthorDetails(models.Model):
    phone = models.CharField(max_length=21)
    address = models.CharField(max_length=66)


class Publish(models.Model):
    name = models.CharField(max_length=33)
    address = models.CharField(max_length=64)
    email = models.EmailField()

    def __str__(self):
        return self.name


'''
注意点:
    一对一: OneToOneField
    一对多: ForeignKey
    多对多: ManyToManyField
    OneToOneField 和 ForeignKey 在建模型表时会在字段名后自动添加_id,如:publish_id
    ManyToManyField 会自动创建第三张表
'''
models.py
复制代码
  • 添加出版社信息

Publish.objects.create(name='环球出版社', address='北京', email='0000@foxm.com')
Publish.objects.create(name='华夏出版社', address='北京', email='1111@foxm.com')
  • 添加书籍信息

# pk 为主键,可通过主键查找,也可通过 id 查找
publish = Publish.objects.filter(pk=1).first()
Book.objects.create(name='雷神之诸神之怒', price=65.9, publish=publish)
Book.objects.create(name='雷神之黑暗世界', price=75.3, publish=publish)
Book.objects.create(name='雷神之诸神黄昏', price=45.5, publish=publish)
  • 添加作者详情信息

AuthorDetails.objects.create(phone='18800001', address='昌平')
AuthorDetails.objects.create(phone='16600002', address='五环')
  • 添加作者信息

au_details = AuthorDetails.objects.filter(id=1).first()
Author.objects.create(name='jack', sex=1, author_details=au_details)
au_details = AuthorDetails.objects.filter(id=2).first()
Author.objects.create(name='peter', sex=1, author_details=au_details)

2.2 连表的增删改查

# 获取作者
jack = Author.objects.filter(name='jack').first()
peter = Author.objects.filter(name='peter').first()
 
# 获取书名
book = Book.objects.filter(name='雷神之诸神之怒').first()
# 一:.add() 添加,可添加一个或多个对象,id
# 为 雷神之诸神之怒 新增作者 jack,peter
book.authors.add(jack, peter)
# 也可以按作者id添加
book.authors.add(1,2)
 
# 二:.remove() 删除,可以是id,也可以是对象,能传多个值
book.authors.remove(jack) # 按名字删除
book.authors.remove(1, 2) # 按id删除
 
# 三:.clear() 清空所有,不用传值
book.authors.clear()
 
# 四:.set() 先清空,再新增,注意点:传的值必须是列表,列表内可以是id,或者对象
book.authors.set([jack,])

2.3 基于对象的连表查询

基于对象的连表查询是子查询,即多次查询

  • 一对一

正向:由关联字段所在的表去查找其他表时---按字段

反向:由其他表去查找关联字段所在的表时---按表名小写

# 正向: 查找作者jack的phone信息时
author = Author.objects.filter(name='jack').first()
res = author.author_details.phone # author.author_details 作者详情对象
print(res)
 
# 反向: 查找地址是五环的作者名字
address = AuthorDetails.objects.filter(address='五环').first()
author = address.author.name # address.author 作者对象
print(author)
  • 一对多

正向: 由关联字段所在的表去查找其他表时---按字段

反向: 由其他表去查找关联字段所在的表时---按表名小写_set.all()

# 正向: 查找 雷神之诸神之怒 的出版社邮箱
book = Book.objects.filter(name='雷神之诸神之怒').first()
publish_email = book.publish.email
print(publish_email)
 
# 反向: 查找邮箱是 0000@foxm.com 的出版社出版的 雷神之诸神黄昏 这本书的价格
email = Publish.objects.filter(email='0000@foxm.com').first()
book = email.book_set.all().filter(name='雷神之诸神黄昏').values('price') # email.book_set.all() 拿出的是所有图书
print(book)
  • 多对多

正向: 由关联字段所在的表去查找其他表时---按字段.all()

反向: 由其他表去查找关联字段所在的表时---按表名小写_set.all()

# 正向: 查找 雷神之诸神之怒 的作者信息
book = Book.objects.filter(name='雷神之诸神之怒').first()
author = book.authors.all()
print(author)
 
# 反向: 查找 作者jack 所写的书籍
author = Author.objects.filter(name='jack').first()
books = author.book_set.all()
print(books)

2.4 基于双下划线的连表查询

***正向查询按字段,反向连表查询按表名小写***

  • 一对一

# 查询 作者jack 的phone信息
# 以 Author 表作为基表查询
phone = Author.objects.filter(name='jack').values('author_details__phone')
 
# 以 AuthorDetails 表作为基表查询
phone = AuthorDetails.objects.filter(author__name='jack').values('phone')
print(phone)
  •  一对多
# 查询出版社为北京的出版社出版的所有图书的名字、价格
# 以 Publish 为基表查询
res = Publish.objects.filter(name='北京出版社').values('book__name','book__price')
# 以 Book 为基表查询
res = Book.objects.filter(publish__name='北京出版社').values('name', 'price')
print(res)
  • 多对多
# 查询 雷神之诸神之怒 的所有作者的名字
# 以 Book 为基表查询
authors = Book.objects.filter(name='雷神之诸神之怒').values('authors__name')
# 以 Author 为基表查询
authors = Author.objects.filter(book__name='雷神之诸神之怒').values('name')
print(authors)
# 查询图书价格大于30的所有作者的名字
# 以 Book 为基表查询
authors = Book.objects.filter(price__gt=30).values('authors__name')
# 以 Author 为基表查询
authors = Author.objects.filter(book__price__gt=30).values('name')
print(authors)
  • 多次连表查询

# 查询 环球出版社 出版过的书籍的名字和作者的名字
# 以 Publish 为基表查询
res = Publish.objects.filter(name='环球出版社').values('book__name', 'book__authors__name')
print(res)
# 以 Book 为基表查询
res1 = Book.objects.filter(publish__name='环球出版社').values('name', 'authors__name')
print(res1)
# 以 Author 为基表查询
res2 = Author.objects.filter(book__publish__name='环球出版社').values('book__name', 'name')
print(res2)

2.5 聚合查询&分组查询

  • 聚合查询 .aggregate()
    • aggregate()QuerySet 的一个终止子句,即它返回一个包含一些键值对的字典
from django.db.models import Avg, Min, Max, Sum, Count
 
# 计算所有书籍的平均价格,最高价格,最低价格,总和
avg_price = Book.objects.aggregate(Avg('price'))
max_price = Book.objects.aggregate(Max('price'))
min_price = Book.objects.aggregate(Min('price'))
sum_price = Book.objects.aggregate(Sum('price'))
print(avg_price)
print(max_price)
print(min_price)
print(sum_price)
 
# 查询 环球出版社 出版书籍的数量
count = Publish.objects.filter(name='环球出版社').aggregate(Count('book'))
print(count)
  • 分组查询 .annotate()
    • annotate()为调用的 QuerySet中每一个对象都生成一个独立的统计值(统计方法用聚合函数)。
# 统计书籍名以'黄昏'结尾的书的作者的个数
res = Book.objects.all().filter(name__endswith='黄昏').annotate(num=Count('authors')).values('name','num')
print(res)
 
# 总结:以谁分组, 就以谁做基表, filter过滤, annotate取分组, values取值
# 模板
    # values 在前表示group by,在后表示取值
    # filter 在前表示where条件,在后表示having
 
# 统计书籍名以'黄昏'结尾的书的作者的个数(按模板)
res = Book.objects.values('name').filter(name__endswith='黄昏').annotate(num=Count('authors')).values('name', 'num')
print(res)
 
# 查询每个作者所出书籍的价格的总和
res = Author.objects.values('name').annotate(num=Sum('book__price')).values('name', 'num')
print(res)

2.6 F查询 & Q查询

Django 提供 F() 来对两个字段的值做比较。F() 的实例可以在查询中引用字段,来比较同一个 model 实例中两个不同字段的值

# F 函数
from django.db.models import F,Q
 
# 将所有书籍的价格加10元
res = Book.objects.all().update(price=F('price')+10)
print(res)
 
 
# Q 函数
# 表示或(|)、非(~)关系
# 查询作者的名字是jack 或 peter 的 书
res = Book.objects.filter(Q(authors__name='jack')|Q(authors__name='peter'))
print(res)

2.7 常用字段及参数

  • orm字段
AutoField----->int 自增,必须输入参数primary_key=True
CharField(max_length=[0-255])----->字符类型,必须提供max_length参数
DateTimeField----->日期+时间格式 YY-MM-DD HH:MM[:ss[.uuuuuu]][TZ]
DateField----->日期格式 YY-MM-DD
TimeField----->时间格式 HH:MM[:ss[.uuuuuu]][TZ]
EmailField----->字符串类型
IntegerField----->整数(-2147483648 2147483647
PositiveIntegerField(PositiveIntegerRelDbTypeMixin, IntegerField)----->正整数(0 2147483647
NullBooleanField----->可以为空的布尔值
TextField----->文本类型
  • orm字段参数
posted @   cnblogs用户  阅读(263)  评论(0编辑  收藏  举报
编辑推荐:
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 基于Microsoft.Extensions.AI核心库实现RAG应用
· Linux系列:如何用heaptrack跟踪.NET程序的非托管内存泄露
· 开发者必知的日志记录最佳实践
· SQL Server 2025 AI相关能力初探
阅读排行:
· 震惊!C++程序真的从main开始吗?99%的程序员都答错了
· winform 绘制太阳,地球,月球 运作规律
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
· 上周热点回顾(3.3-3.9)
· 超详细:普通电脑也行Windows部署deepseek R1训练数据并当服务器共享给他人
点击右上角即可分享
微信分享提示