You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在Django中实现两个多对多字段的双向关联?

解决Django多对多关联双向同步展示问题

你的问题核心在于定义了两个独立的多对多字段(CustomUser.user_counter和CounterParty.counter_user),导致两边的关联数据不互通。下面是具体的修正方案:


1. 修正模型定义

打开models.py,删除重复的多对多字段,复用同一个关联关系:

class CustomUser(models.Model):
    user = models.OneToOneField(User, on_delete=models.CASCADE, verbose_name='Пользователь')
    # 添加related_name,让CounterParty可以反向访问关联的CustomUser
    user_counter = models.ManyToManyField(
        'CounterParty', 
        blank=True, 
        verbose_name='Контрагенты пользователя',
        related_name='related_users'
    )

    def __str__(self):
        return f'{self.user}'


class CounterParty(models.Model):
    GUID = models.UUIDField(default=uuid.uuid4, editable=True, unique=True)
    name = models.CharField(max_length=150, verbose_name='Наименование')
    customer = models.BooleanField(default=False, verbose_name='Заказчик')
    contractor = models.BooleanField(default=False, verbose_name='Подрядчик')
    # 删除原有的counter_user字段,避免重复关联

    class Meta:
        verbose_name = 'Контрагент'
        verbose_name_plural = 'Контрагенты'

    def __str__(self):
        return self.name  # 补充返回名称,方便后台显示

2. 调整Admin配置实现双向展示

修改admin.py,在CounterParty的管理界面添加关联用户的展示:

方法一:用Inline组件实现可编辑的关联展示

from django.contrib import admin
from .models import CustomUser, CounterParty, ObjectList, SectionList
from authentication.models import User
from authentication.admin import UserAdmin


class CustomUserInLine(admin.StackedInline):
    model = CustomUser
    can_delete = False
    verbose_name_plural = 'Пользователи'


class CustomUserAdmin(UserAdmin):
    inlines = (CustomUserInLine,)


# 新增Inline,用于在CounterParty界面展示关联的用户
class CounterPartyUserInline(admin.TabularInline):
    model = CustomUser.user_counter.through  # 直接关联多对多中间表
    verbose_name = '关联用户'
    verbose_name_plural = '关联用户'
    extra = 0  # 不显示空的添加行


@admin.register(CounterParty)
class CounterPartyAdmin(admin.ModelAdmin):
    inlines = (CounterPartyUserInline,)
    # 可选:在列表页显示关联用户数量
    list_display = ('name', 'customer', 'contractor', 'get_user_count')

    def get_user_count(self, obj):
        return obj.related_users.count()
    get_user_count.short_description = '关联用户数'


admin.site.unregister(User)
admin.site.register(User, CustomUserAdmin)

方法二:仅展示关联用户(只读)

如果不需要在CounterParty界面修改关联,可直接添加只读字段:

@admin.register(CounterParty)
class CounterPartyAdmin(admin.ModelAdmin):
    readonly_fields = ('get_related_users',)
    fields = ('name', 'customer', 'contractor', 'get_related_users')

    def get_related_users(self, obj):
        return ', '.join([str(cu.user) for cu in obj.related_users.all()])
    get_related_users.short_description = '关联用户'

3. 执行数据库迁移

修改模型后,运行以下命令更新数据库:

python manage.py makemigrations
python manage.py migrate

效果验证

  • 在用户管理界面设置的CounterParty关联,会自动同步到CounterParty的管理界面
  • 在CounterParty界面添加的用户关联,也会同步到用户管理界面的对应位置

内容的提问来源于stack exchange,提问作者Zesshi

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.02 05:25:23