在 django admin 中使用 related_name 配置多对多字段

Posted

技术标签:

【中文标题】在 django admin 中使用 related_name 配置多对多字段【英文标题】:Configuring Many-to-many field in django admin with related_name 【发布时间】:2013-09-14 00:27:21 【问题描述】:

我在 djando 1.5 中定义了以下模型和管理员。这是子网和vlan之间的多对多关系。我使用 ManyToMany 字段中的 related_name 选项,以便能够从相关子网对象中获取 vlan 的集合。从管理员向 vlan 添加子网效果很好。但是,当我尝试将 Horizo​​ntal_filer 添加到子网管理员以便将 van 添加到其 vlan 集中时,我收到一条错误消息,指出 vlans 属性不存在。我在某些视图中使用了子网对象,并且可以正确访问 vlans 属性。

我在这里做错了什么?我看过类似的帖子,但我无法成功调整任何提议的解决方案。

感谢您的帮助

模型.py

from django.db import models

class Subnet(models.Model):
    networkAddress = models.CharField(max_length=15)
    size = models.IntegerField()

    def __unicode__(self):
        return "%s/%s" % (self.networkAddress, self.size)

class IpAddress(models.Model):
    ipAddress = models.CharField(max_length=15)
    subnet = models.ForeignKey(Subnet)

    def __unicode__(self):
        return "%s" % (self.ipAddress)

class Vlan(models.Model):
    number = models.IntegerField()
    description = models.CharField(max_length=150)
    subnets = models.ManyToManyField(Subnet, related_name='vlans', blank=True)

    def __unicode__(self):
        return "VLAN %s (%s)" % (self.number, self.description)

admin.py

from network.models import Subnet, IpAddress, Vlan
from django.contrib import admin

class SubnetAdmin(admin.ModelAdmin):
    filter_horizontal = ('vlans',)

admin.site.register(Subnet, SubnetAdmin)
admin.site.register(IpAddress)
admin.site.register(Vlan)

我得到的错误

Request Method:     GET
Request URL:    http://127.0.0.1:8000/admin/
Django Version:     1.5.2
Exception Type:     ImproperlyConfigured
Exception Value:    

'SubnetAdmin.filter_horizontal' refers to field 'vlans' that is missing from model 'network.Subnet'.

【问题讨论】:

我昨天遇到了同样的问题。我只是通过将 ManyToMany 声明移动到另一个模型来解决它。也许你可以尝试创建一个返回self.vlans的模型方法。 好吧,如果我将 de ManyToManyField 更改为另一个模型,我会遇到同样的问题。在这种情况下,我真的希望能够从两端编辑关系 那我试试模型法方法 所以你的意思是这样的: def vlans(self): return self.vlans in Subnet model ?如果是这样,我试过了,它抛出了同样的错误:( 【参考方案1】:

显然这是8 year old feature request。有django-admin-extend。或者你可以扔东西like this in there:

from django.contrib import admin as admin_module

class SiteForm(ModelForm):
    user_profiles = forms.ModelMultipleChoiceField(
        label='Users granted access',
        queryset=UserProfile.objects.all(),
        required=False,
        help_text='Admin users (who can access everything) not listed separately',
        widget=admin_module.widgets.FilteredSelectMultiple('user profiles', False))

class SiteAdmin(admin_module.ModelAdmin):
    fields = ('user_profiles',)

    def save_model(self, request, obj, form, change):
        # save without m2m field (can't save them until obj has id)
        super(SiteAdmin, self).save_model(request, obj, form, change) 
        # if that worked, deal with m2m field
        obj.user_profiles.clear()
        for user_profile in form.cleaned_data['user_profiles']:
             obj.user_profiles.add(user_profile)

    def get_form(self, request, obj=None, **kwargs):
        if obj:
            self.form.base_fields['user_profiles'].initial = [ o.pk for o in obj.userprofile_set.all() ]
        else:
            self.form.base_fields['user_profiles'].initial = []
        return super(SiteAdmin, self).get_form(request, obj, **kwargs)

当您在 fields 元组中指定它时,它应该给您一个 filter_horizontal

【讨论】:

【参考方案2】:

我创建了一个涵盖此特定问题的公共要点。

https://gist.github.com/Wtower/0b181cc06f816e4feac14e7c0aa2e9d0

一般的想法是使用特定的基本表单类来为表单定义一个“反向”m2m 字段,否则将不包含它。然后轻松覆盖管理类中的form

虽然代码不是很复杂,但要包含在答案中的要点代码有点长,因此对此深表歉意。

【讨论】:

以上是关于在 django admin 中使用 related_name 配置多对多字段的主要内容,如果未能解决你的问题,请参考以下文章

Django_xadmin_TypeError: Related Field got invalid lookup: icontains

Django_xadmin_TypeError: Related Field got invalid lookup: icontains

Django Admin 覆盖显示的字段值

Django Admin,修改/自定义manytomany字段的选择框中的名称

如何在模板 Django 中使用 select_related?

Django中select_related和prefetch_related的用法与区别