Django模型关系与视图操作详解:增删改查及跨表查询实战
本文详解Django框架中models.py的表创建与views.py的函数操作。涵盖一对一、一对多及多对多关系的定义,重点讲解create、add、remove、clear、set等核心方法在增删改查中的应用,并深入解析基于对象的正向与反向跨表查询技巧。
Django模型关系与视图操作详解
本文通过具体实例,详细介绍如何在Django框架中利用views.py中的函数对数据库表执行增删改查操作,供读者参考学习。
模型表关系定义
在models.py中定义表结构时,主要涉及以下三种关系类型:
一对一关系:可通过ForeignKey("Author",unique=True)或OneToOneField("Author")实现。
一对多关系:使用ForeignKey(to="Publish",to_field="id",on_delete=models.CASCADE)建立。
多对多关系:通过ManyToManyField(to="Author")定义。
接下来,我们首先构建几个示例数据表。
from django.db import models
# Create your models here.
class AuthorDetail(models.Model):
gf=models.CharField(max_length=32)
tel=models.CharField(max_length=32)
class Author(models.Model):
name=models.CharField(max_length=32)
age=models.IntegerField()
# 与AuthorDetail建立一对一的关系
# ad=models.ForeignKey(to="AuthorDetail",to_field="id",on_delete=models.CASCADE,unique=True)
ad=models.OneToOneField(to="AuthorDetail",to_field="id",on_delete=models.CASCADE,)
class Publish(models.Model):
name=models.CharField(max_length=32)
email=models.CharField(max_length=32)
addr=models.CharField(max_length=32)
class Book(models.Model):
title=models.CharField(max_length=32,unique=True)
price=models.DecimalField(max_digits=8,decimal_places=2,null=True)
pub_date=models.DateField()
# 与Publish建立一对多的关系,外键字段建立在多的一方
publish=models.ForeignKey(to="Publish",to_field="id",on_delete=models.CASCADE)
# 与Author表建立多对多的关系,ManyToManyField可以建在两个模型中的任意一个,自动创建关系表book_authors
authors=models.ManyToManyField(to="Author")
相关字段说明如下:
OneToOneField用于创建一对一关系。
to参数指定需要关联的目标表。
to_field指定关联的具体字段。
on_delete=models.CASCADE代表级联删除。若a表删除某条记录,b表中对应的记录也将被自动删除。ad为关联字段,但ORM在创建表时会自动为其添加_id后缀,因此实际关联字段名为ad_id。
注意:建立一对一关系时,关联字段会自动添加唯一性约束,例如ad_id。
ForeignKey用于建立外键关系。
on_delete=models.CASCADE同样表示级联删除。使用ForeignKey时必须指定on_delete参数,否则在2.x版本中会报错。ManyToManyField用于建立多对多关系,仅需一个to参数指定关联表。
在Book模型中定义多对多关系时,系统会自动创建一张额外的关系表。该表名由当前模型名(book)与关系属性名(等式左侧的authors)组合而成。
即创建名为book_authors的表,该表仅包含三个字段:自身id、Book表的主键id以及Author表的主键id。
视图函数中的增删改查操作
接下来在视图文件views.py中演示具体用法。
from django.shortcuts import render,HttpResponse
from app01.models import AuthorDetail,Author,Publish,Book
# Create your views here.
def add(request):
# 注意:因为author的ad属性是关联authordetail表,必须添加authordetail表,才能添加author表。
# hong_gf=AuthorDetail.objects.create(gf='小唐',tel=1314)
# hong=Author.objects.create(name='hong',age='25',ad=hong_gf)
# print(hong)
# # publish_id就是Book类的publish属性。它的字段为publish_id
# book = Book.objects.create(title='西游记', price=100, pub_date="1743-4-12", publish_id=2)
# print(book.title) # 打印title
# return HttpResponse('添加成功')
# xigua = Publish.objects.filter(name="西瓜出版社").first() #model对象
# book = Book.objects.create(title='三国演义',price=300,pub_date="1643-4-12",publish=xigua)
# return HttpResponse('添加成功')
以下代码展示了如何关联其他两个表的字段。
# book = Book.objects.create(title='python',price=122,pub_date="2012-12-12",publish_id=1)
# xiao = Author.objects.filter(name="xiao").first() #取Author表name为xiao的id
# zhang = Author.objects.filter(name="zhang").first()
# print(zhang)
# book.authors.add(xiao,zhang) # 添加2条数据,接收一个参数,就会产生一条记录
#
# return HttpResponse('添加成功')
以下代码展示了如何关联Author表中的所有作者。
# book = Book.objects.create(title='linux', price=155, pub_date="2013-12-12", publish_id=2)
# author_list=Author.objects.all()
# book.authors.add(*author_list)
# return HttpResponse('添加成功')
#解除绑定关系
# book = Book.objects.filter(id=3).first() # 先找到这本书
# xiao = Author.objects.filter(name="xiao").first() # 再找到作者
# book.authors.remove(xiao) # 解除绑定的关系
# return HttpResponse('解除绑定成功')
#清空所有关系对象
# book = Book.objects.filter(id=4).first()
# book.authors.clear() # 清理所有关系对象
# return HttpResponse('清理成功')
#绑定唯一的作者或者几个作者,放入一个列表中
book=Book.objects.filter(id=3).first()
wang=Author.objects.filter(name='wang').first()
book.authors.set([wang]) #先清空再设置
return HttpResponse('绑定唯一作者成功')
总结关键点如下:
重点掌握create、add、remove、clear、set这五个核心方法。
添加表记录的操作:
对于一对一和一对多关系,使用create方法,主要有两种用法:
1. create(字段名1=值1...)。适用于表单添加操作,注意此处字段名为ORM创建表后的实际字段名。
例如:Book类的publish属性是关联字段,ORM创建后其字段名为publish_id。
2. create(模型类属性1=值1...)。例如Book类的publish属性是关联字段。
直接执行create(publish=obj1),注意它接收一个Model对象,该对象包含主键id。
多对多关系使用add方法,同样有两种用法:
1. add(obj1, obj2...)。接收Model对象,对象中包含主键id。
2. add(主键id1, 主键id2...)。接收主键id,适用于表单添加操作。
此外,利用Python的打散语法,在列表前加*即可。例如*[1,2],它会依次调用前置方法,每次只取一个值。这在表单操作中非常有用。
删除记录的操作:
适用于一对一、一对多及多对一关系。
remove(obj1, obj2, ...)用于去除多个关系对象,需指定一个或多个对象。
clear()用于清理所有关系对象。无论现有关系有多少,一律清空。
set([obj1, obj2...])先清空再设置。无论现有关系有多少,一律清空后重新设置,适用于网页后台修改操作。
基于对象的跨表查询实战
查询部分——基于对象的跨表查询(子查询)。
一对多查询示例。
查看book_authors表的内容。

一般写法如下:
def add(request):
book = Book.objects.filter(title="西游记").first() #过滤出记录
publish_id = book.publish_id #找出书籍对应的出版社id
publish = Publish.objects.filter(id=publish_id).first() #根据id号在 Publish表中找出出版社名称
print(publish.name)
简化写法如下:
def add(request):
book = Book.objects.filter(title="西游记").first() #找出Book表中title为 西游记的 记录
print(book.publish.name) #书籍.出版社.名称
关于正向和反向查询的区分。
判断正向或反向的关键在于关键字段的位置。
若通过关联字段进行查询,则为正向;否则为反向。
简而言之:正向查询按字段名进行。
反向查询则按表名小写后加_set(),例如:publish.book_set(),适用于一对多和多对多。若记录只有一条,则通过字段.名称进行查询,适用于一对一。
示例:找出西瓜出版社出版的所有书籍名称(一对多查询)。
正向查询实现:
def add(request):
publish = Publish.objects.filter(name="西瓜出版社").first() # 先找出版社
ret = Book.objects.filter(publish_id=publish.id).values("title") # 再找书籍
print(ret)
return HttpResponse('ok')
反向查询实现:
def add(request):
publish = Publish.objects.filter(name="西瓜出版社").first() # 先找出版社
ret = publish.book_set.all().values("title") # 再找书籍,过滤title
print(ret)
return HttpResponse('ok')
示例:多对多关系查询。
正向查询:查询Python这本书籍的所有作者的姓名和年龄。
def add(request):
book = Book.objects.filter(title="python").first() # 先找书籍
ret = book.authors.all().values("name","age") # 再找作者,过滤name和age
print(ret)
return HttpResponse('ok')
反向查询:查询作者xiao出版过的所有书籍名称。
def add(request):
xiao = Author.objects.filter(name="xiao").first() # 先找作者
ret = xiao.book_set.all().values("title") # 再找书籍,过滤title
print(ret)
return HttpResponse('ok')

示例:一对一关系查询。
正向查询:查询xiao的女朋友的名字,通过gf字段。
def add(request):
xiao = Author.objects.filter(name="xiao").first() # 先找作者
ret = xiao.ad.gf # 再找女朋友
print(ret)
return HttpResponse('ok')
反向查询:查询手机号为112的作者名字。
def add(request):
phone = AuthorDetail.objects.filter(tel="112").first() # 先找号码
ret = phone.author.name # 再找作者的名字
print(ret)

希望本文所述内容能对大家基于Django框架的Python程序设计有所帮助。
免责声明:本文内容仅供参考,不代表本站观点。转载或引用请注明出处。









