Django模型关系与视图操作详解:增删改查及跨表查询实战

蓝鲸
蓝鲸
发布时间:2026-10-13 | 4人浏览过
原创

本文详解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程序设计有所帮助。

相关标签:

本站声明

本文内容仅供参考,不代表本站观点。转载或引用请注明出处。如发现内容问题,请通过联系我们页面反馈。

Python 相关产品和应用

全部下载

专题列表