Django ManyToManyField多对多关系详解与实战
本文深入解析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 多对多关系的实例详解即为全部内容,希望能为读者提供有益参考。
免责声明:本文内容仅供参考,不代表本站观点。转载或引用请注明出处。









