【问题标题】:Django Admin - 'ManyToManyField' object has no attribute 'through'Django Admin - “ManyToManyField”对象没有“通过”属性
【发布时间】:2016-11-29 09:50:22
【问题描述】:

tl;dr

当我尝试通过使用fieldsfieldsets 属性的自定义表单呈现具有ManyToMany 关系的管理类时,Django 抛出AttributeError,除了form 属性:

AttributeError: 'ManyToManyField' 对象没有属性 'through'


型号:

我有两个模型绑定了ManyToMany 关系:

class Project(models.Model):
    title = models.CharField(max_length=200, unique=True)

class Centre(models.Model):
    projects = models.ManyToManyField(
        Project, blank=True, related_name='centres',
    )

表格:

另外,我为Project 模型创建了一个自定义表单,为Centre 添加FilteredSelectMultiple 字段:

class ProjectAdminForm(forms.ModelForm):
    centres = forms.ModelMultipleChoiceField(
        Centre.objects.all(),
        widget=admin.widgets.FilteredSelectMultiple('Centres', False),
        required=False,
    )

    def __init__(self, *args, **kwargs):
        super(ProjectAdminForm, self).__init__(*args, **kwargs)
        if self.instance.pk:
            self.initial['centres'] = self.instance.centres.values_list(
                'pk', flat=True
            )

    def save(self, *args, **kwargs):
        instance = super(ProjectAdminForm, self).save(*args, **kwargs)
        if instance.pk:
            instance.centres.clear()
            instance.centres.add(*self.cleaned_data['centres'])
        return instance

管理员:

问题是,当我这样定义管理类时:

@admin.register(Project, site=admin_site)
class ProjectAdmin(admin.ModelAdmin):
    form = ProjectAdminForm

它工作正常并为titlecentres 字段呈现正确的表单。

问题

但是,如果我这样定义字段:

@admin.register(Project, site=admin_site)
class ProjectAdmin(admin.ModelAdmin):
    form = ProjectAdminForm
    fields = ('title', 'centres', )

这会抛出一个AttributeError:

AttributeError: 'ManyToManyField' 对象没有属性 'through'

我尝试在 Project 模型中的 models.ManyToManyField 上设置 through 属性,定义中介 ProjectCentresModel,但我仍然无法理解 Django 内部发生了什么以及我应该调整什么以使其工作.


追溯:

Unhandled exception in thread started by <function check_errors.<locals>.wrapper at 0x7f88ac6e5bf8>
Traceback (most recent call last):
  File "/media/kidbinary/Data/web/PYTHON/.virtualenvs/work/lib/python3.5/site-packages/django/utils/autoreload.py", line 226, in wrapper
    fn(*args, **kwargs)
  File "/media/kidbinary/Data/web/PYTHON/.virtualenvs/work/lib/python3.5/site-packages/django/core/management/commands/runserver.py", line 113, in inner_run
    autoreload.raise_last_exception()
  File "/media/kidbinary/Data/web/PYTHON/.virtualenvs/work/lib/python3.5/site-packages/django/utils/autoreload.py", line 249, in raise_last_exception
    six.reraise(*_exception)
  File "/media/kidbinary/Data/web/PYTHON/.virtualenvs/work/lib/python3.5/site-packages/django/utils/six.py", line 685, in reraise
    raise value.with_traceback(tb)
  File "/media/kidbinary/Data/web/PYTHON/.virtualenvs/work/lib/python3.5/site-packages/django/utils/autoreload.py", line 226, in wrapper
    fn(*args, **kwargs)
  File "/media/kidbinary/Data/web/PYTHON/.virtualenvs/work/lib/python3.5/site-packages/django/__init__.py", line 27, in setup
    apps.populate(settings.INSTALLED_APPS)
  File "/media/kidbinary/Data/web/PYTHON/.virtualenvs/work/lib/python3.5/site-packages/django/apps/registry.py", line 115, in populate
    app_config.ready()
  File "/media/kidbinary/Data/web/PYTHON/.virtualenvs/work/lib/python3.5/site-packages/django/contrib/admin/apps.py", line 23, in ready
    self.module.autodiscover()
  File "/media/kidbinary/Data/web/PYTHON/.virtualenvs/work/lib/python3.5/site-packages/django/contrib/admin/__init__.py", line 26, in autodiscover
    autodiscover_modules('admin', register_to=site)
  File "/media/kidbinary/Data/web/PYTHON/.virtualenvs/work/lib/python3.5/site-packages/django/utils/module_loading.py", line 50, in autodiscover_modules
    import_module('%s.%s' % (app_config.name, module_to_search))
  File "/media/kidbinary/Data/web/PYTHON/.virtualenvs/work/lib/python3.5/importlib/__init__.py", line 126, in import_module
    return _bootstrap._gcd_import(name[level:], package, level)
  File "<frozen importlib._bootstrap>", line 986, in _gcd_import
  File "<frozen importlib._bootstrap>", line 969, in _find_and_load
  File "<frozen importlib._bootstrap>", line 958, in _find_and_load_unlocked
  File "<frozen importlib._bootstrap>", line 673, in _load_unlocked
  File "<frozen importlib._bootstrap_external>", line 665, in exec_module
  File "<frozen importlib._bootstrap>", line 222, in _call_with_frames_removed
  File "/media/kidbinary/Data/web/PYTHON/work_project/work/website/admin.py", line 165, in <module>
    class ProjectAdmin(DefaultOrderingModelAdmin):
  File "/media/kidbinary/Data/web/PYTHON/.virtualenvs/work/lib/python3.5/site-packages/django/contrib/admin/decorators.py", line 28, in _model_admin_wrapper
    admin_site.register(models, admin_class=admin_class)
  File "/media/kidbinary/Data/web/PYTHON/.virtualenvs/work/lib/python3.5/site-packages/django/contrib/admin/sites.py", line 110, in register
    system_check_errors.extend(admin_obj.check())
  File "/media/kidbinary/Data/web/PYTHON/.virtualenvs/work/lib/python3.5/site-packages/django/contrib/admin/options.py", line 117, in check
    return self.checks_class().check(self, **kwargs)
  File "/media/kidbinary/Data/web/PYTHON/.virtualenvs/work/lib/python3.5/site-packages/django/contrib/admin/checks.py", line 515, in check
    errors = super(ModelAdminChecks, self).check(admin_obj)
  File "/media/kidbinary/Data/web/PYTHON/.virtualenvs/work/lib/python3.5/site-packages/django/contrib/admin/checks.py", line 71, in check
    errors.extend(self._check_fieldsets(admin_obj))
  File "/media/kidbinary/Data/web/PYTHON/.virtualenvs/work/lib/python3.5/site-packages/django/contrib/admin/checks.py", line 155, in _check_fieldsets
    for index, fieldset in enumerate(obj.fieldsets)
  File "/media/kidbinary/Data/web/PYTHON/.virtualenvs/work/lib/python3.5/site-packages/django/contrib/admin/checks.py", line 155, in <listcomp>
    for index, fieldset in enumerate(obj.fieldsets)
  File "/media/kidbinary/Data/web/PYTHON/.virtualenvs/work/lib/python3.5/site-packages/django/contrib/admin/checks.py", line 190, in _check_fieldsets_item
    for fieldset_fields in fieldset[1]['fields']
  File "/media/kidbinary/Data/web/PYTHON/.virtualenvs/work/lib/python3.5/site-packages/django/contrib/admin/checks.py", line 190, in <listcomp>
    for fieldset_fields in fieldset[1]['fields']
  File "/media/kidbinary/Data/web/PYTHON/.virtualenvs/work/lib/python3.5/site-packages/django/contrib/admin/checks.py", line 204, in _check_field_spec
    return self._check_field_spec_item(obj, model, fields, label)
  File "/media/kidbinary/Data/web/PYTHON/.virtualenvs/work/lib/python3.5/site-packages/django/contrib/admin/checks.py", line 220, in _check_field_spec_item
    if field.many_to_many and not field.remote_field.through._meta.auto_created:
AttributeError: 'ManyToManyField' object has no attribute 'through'

【问题讨论】:

  • 请将完整的错误回溯添加到您的问题中!
  • 我理解了第一个问题,因为您试图通过管理员中的 manytomanyfield 显示项目列表。这是你的初衷吗?
  • 是的,就是这样,但我想像FilteredSelectMultiple 一样显示它们,而不是堆叠或表格内联(有效)。问题实际上是关于为什么当我在管理类中明确定义字段时它会引发错误。
  • 我向它添加了一个模型并且它起作用了。我在 django 中检查了错误的来源,然后向它添加了一个模型并且它起作用了。诡异的。试试看,如果可行,我会将其添加为答案并提供更多详细信息
  • 请问,哪个型号?

标签: python django python-3.x django-admin many-to-many


【解决方案1】:
class ProjectAdmin(admin.ModelAdmin):
    model = Project
    form = ProjectAdminForm
    fields = ('title', 'centres',)


class CentreAdmin(admin.ModelAdmin):
    model = Centre
    list_display = ['id', 'get_projects']

    def get_projects(self, obj):
        #lists all the projects under a center without having to use inlines
        return "\n".join([proj.title for proj in obj.projects.all()])

老实说,我不能说它为什么会抛出这个错误,添加模型只是猜测。我在 django 中检查了错误的源文件,但无法真正理解那里发生了什么。

【讨论】:

  • 我想你有点误解了这个问题......我的设置有些不同。
猜你喜欢
  • 2016-04-14
  • 2016-10-23
  • 1970-01-01
  • 2015-11-10
  • 2019-12-04
  • 2017-04-25
  • 1970-01-01
  • 2015-06-07
  • 1970-01-01
相关资源
最近更新 更多