Django ManyToManyField多对多关系详解与实战

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

本文深入解析Django ORM中的多对多关系,通过ManyToManyField实现User与Group的双向关联。详解正向查询与反向查询的具体代码操作,包括在Admin后台自定义显示字段及Shell命令行下的数据交互示例,帮助开发者掌握复杂模型关系的构建与查询技巧。

Django ORM 关系类型概述

Django的对象关系映射(ORM)支持多种数据关联模式,主要涵盖一对一、多对一以及多对多三种类型。

在模型定义中,这三种关系分别对应特定的字段类型:

一对一关系使用 OneToOneField 定义。

多对一关系使用 ForeignKey 定义。

多对多关系使用 ManyToManyField 定义。

上述技术描述较为抽象,以下通过更直观的语义进行解释:

多对一关系(belong to):多个实例归属于一个实例,对应 ForeignKey。

一对一关系(has one):一个实例拥有另一个实例,对应 OneToOneField。

一对多关系(has many):一个实例拥有多个实例,对应 lots of A belong to B 与 B has many A。在建立 ForeignKey 时,Django 会自动在另一端建立对应的反向关系。

多对多关系(has many and belong to):一个实例既拥有多个实例,又属于多个实例,对应 ManyToManyField。该关系仅需在其中一个 Model 类中声明,关联表由 Django 自动创建。

多对多关系实战:User 与 Group 模型构建

以下通过具体案例演示多对多关系的实现:

假设存在两张数据表:User(用户)表和 Group(组)表。User 表包含用户名、邮箱、年龄等字段;Group 表包含组名。由于一个用户可以加入多个组,且一个组可以包含多个用户,因此 User 与 Group 之间构成多对多关系。

代码实现位于 mysite/learn/models.py 文件中。


#coding:utf8
from django.db import models

class Group(models.Model):
  Name = models.CharField(max_length=20)
  def __unicode__(self):
    return self.Name
    
    
class User(models.Model):
  Name = models.CharField(max_length=20)
  Email = models.CharField(max_length=50)
  group = models.ManyToManyField(Group,blank=True)
  def __unicode__(self):
    return self.Name
  def group_list(self):
    return ','.join([i.Name for i in self.group.all()])

创建 Group 和 User 两个模型类。Group 表仅包含 Name 字段;User 表包含 Name、Email 以及通过 ManyToManyField 关联的 group 字段。

在 User 模型中,由于 group 字段与 Group 表存在关联,需使用 ManyToManyField 进行定义。


ManyToManyField

def group_list(self):
    return ','.join([i.Name for i in self.group.all()])

定义 group_list 方法旨在后台管理界面中展示该字段信息,group_list 即为后台页面显示的自定义字段名称。


i.Name for i in self.group.all()

此处 Name 指向 Group 表中的 Name 字段,self.group 则是 User 模型中定义的 group 字段。

后台管理配置代码位于 mysite/admin.py 文件中。


from django.contrib import admin
from learn.models import *
# Register your models here.

class UserAdmin(admin.ModelAdmin):
  list_display = ['id','Name','Email','group_list']
admin.site.register(User,UserAdmin)

class GroupAdmin(admin.ModelAdmin):
  list_display = ['id','Name']
admin.site.register(Group,GroupAdmin)

访问 Django 的 admin 后台管理页面。

在 Group 表中创建相应的组记录。

在 User 表中创建用户记录,并在 Group 字段中选择所属的用户组。

观察上述界面截图,可以发现 Group 表仅显示组名,无法直接查看组内包含的用户。虽然 User 表显示了 group_list 字段,但若希望在 Group 详情中反向显示用户信息,可参考 User 表的实现方式,修改 mysite/learn/models.py 文件。


#coding:utf8
from django.db import models

class Group(models.Model):
  Name = models.CharField(max_length=20)
  def user_list(self):
    return ','.join([i.Name for i in self.user_set.all()])
  def __unicode__(self):
    return self.Name
class User(models.Model):
  Name = models.CharField(max_length=20)
  Email = models.CharField(max_length=50)
  group = models.ManyToManyField(Group,blank=True)
  def __unicode__(self):
    return self.Name
  def group_list(self):
    return ','.join([i.Name for i in self.group.all()])

在 learn/admin.py 文件中为 GroupAdmin 添加 user_list 字段以支持反向显示。

再次访问 admin 后台管理页面,此时在 Group 表的详情视图中即可看到 user_list 信息。

正向与反向查询操作指南

接下来介绍正向查询与反向查询的操作方法。

正向查询示例:

基于已创建的 User 和 Group 表,现需查询 User 表中特定用户所属的组。

进入 Django Shell 命令行环境。


python manage.py shell

>>> from learn.models import *
>>> User.objects.all()
[<User: 老黄>, <User: 老张>, <User: 老王>]
>>> User.objects.all()[0]
<User: 老黄>
>>> User.objects.all()[0].Email
u'laohuang@qq.com'
>>> User.objects.all()[0].group.all()
[<Group: CEO>, <Group: COO>]
>>> User.objects.all()[0].group.all()[0].Name
u'CEO'
>>> User.objects.all()[0].group.all()[0].id

mysite/models.py 文件中的每个类均映射为 Django ORM 对象,使用


User.objects.all()

可以获取所有对象,返回结果为列表形式。


[<User: 老黄>, <User: 老张>, <User: 老王>]

获取列表中的第一个对象实例。


>>> User.objects.all()[0]
<User: 老黄>

获取名为“老黄”的用户对象的 Email 属性值。


>>> User.objects.all()[0].Email
u'laohuang@qq.com'

获取该用户所属组的组名及 ID 信息。


>>> User.objects.all()[0].group.all()[0].Name
u'CEO'
>>> User.objects.all()[0].group.all()[0].id

反向查询示例:


>>> from learn.models import * ##导入models中所有的类

>>> Group.objects.all()  ##查看Group表中所有的对象
[<Group: CEO>, <Group: CTO>, <Group: COO>, <Group: VP>]

>>> Group.objects.all()[0] ##查看Group表中第一个对象CEO
<Group: CEO>

>>> Group.objects.all()[0].Name ##查看CEO这个对象的Name属性
u'CEO'

>>> Group.objects.all()[0].user_set.all() ##反向查看CEO这个对象的用户名
[<User: 老黄>]

>>> Group.objects.all()[0].user_set.all()[0]
<User: 老黄>

>>> Group.objects.all()[0].user_set.all()[0].Email ##反向查看CEO这个对象的Email
u'laohuang@qq.com'

>>> Group.objects.all()[0].user_set.all()[0].Name 
u'\u8001\u9ec4'

以上关于 Django ManyToManyField 多对多关系的实例详解即为全部内容,希望能为读者提供有益参考。

相关标签:

免责声明:本文内容仅供参考,不代表本站观点。转载或引用请注明出处。

Python 相关产品和应用

全部下载
Selenium

Selenium

4.51.0 · Windows

用于浏览器自动化和 Web 测试的 Python 工具。

scikit-learn

scikit-learn

1.9.1 · Windows

常用 Python 机器学习算法与模型评估工具库。

Black

Black

26.10.1 · Windows

强调一致性的 Python 自动代码格式化工具。

Ruff

Ruff

0.17.1 · macOS

由 Rust 编写的高速 Python 代码检查和格式化工具。

pytest

pytest

9.1.1 · Windows

简洁而强大的 Python 自动化测试框架。

FastAPI

FastAPI

0.146.0 · Windows

高性能 Python API 框架,支持类型提示和自动接口文档。

Flask

Flask

3.1.3 · Windows

轻量灵活的 Python Web 应用框架。

Django

Django

6.1.2 · Windows

成熟的 Python Web 框架,适合构建内容站点和业务系统。

Spyder

Spyder

6.1.7 · Windows

面向科学计算与数据分析的 Python 集成开发环境。

SciPy

SciPy

1.18.1 · Windows

面向科学、工程和技术计算的 Python 算法库。