Django管理员根据另一个字段过滤ForeignKey下拉列表 [英] Django Admin filtering ForeignKey dropdown based on another field

查看:795
本文介绍了Django管理员根据另一个字段过滤ForeignKey下拉列表的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有3个模型:

  class FileType(models.Model):
name = models.CharField max_length = 128)

class ManagedFile(models.Model):
type = models.ForeignKey(FileType)
content = models.FileField(upload_to = path_maker)

class Tag(models.Model):
type = models.ForeignKey(FileType)
m_file = models.ForeignKey(ManagedFile)

def clean(self)
如果self.m_file为None:
return
如果self.type!= self.m_file.type:
raise ValidationError(文件类型不匹配标签类型)

当为标签选择一个m_file时,m_files类型必须与标签类型匹配。这一切都很好,但是管理员下拉Tag.m_file显示所有类型的文件,不管标签的类型。这对用户感到困惑



我似乎有一些方法可以静态地过滤掉下拉列表。所以如果我想说,我们永远不会让用户在下拉列表中看到Type.pk = 1,我可以这样做。但似乎没有办法过滤m_file.Type == Self.Type

解决方案

其实很简单动态创建您的管理表单类。这样做应该可以工作:

  def tagform_factory(filetype):
class TagForm(forms.ModelForm):
m_file = forms.ModelChoiceField(
queryset = ManagedFile.objects.filter(type = filetype)

返回TagForm


class TagAdmin

def get_form(self,request,obj = None,** kwargs):
如果obj不是None,obj.type不是None:
kwargs ['form'] = tagform_factory(obj.type)
return super(TagAdmin,self).get_form(request,obj,** kwargs)

请注意, get_form 方法负责构建表单,而不是表单实例。但是,您仍然需要决定如何处理用于添加新标签的表单,而不是编辑现有的标签。在这种情况下,您还没有可以限制下拉列表的类型。也许这里潜伏着一个数据建模问题?您真的需要标签模型中的类型字段?也许它应该被删除?


I have 3 Models:

class FileType(models.Model):
    name=models.CharField(max_length=128)

class ManagedFile(models.Model):
    type = models.ForeignKey(FileType)
    content = models.FileField(upload_to=path_maker)

class Tag(models.Model):
    type = models.ForeignKey(FileType)
    m_file = models.ForeignKey(ManagedFile)

    def clean(self):
        if self.m_file is None:
            return
        if self.type != self.m_file.type:
            raise ValidationError("File type does not match Tag type")

When select an m_file for a tag, the m_files type MUST match the Tags type. This is all well and good, but the admin drop down for Tag.m_file shows files of all types, regardless of the Tag's type. This is Confusing to users.

There seem to me a number of ways to filter the drop down statically. So if I wanted to say that we will never let the user see Type.pk=1 in the dropdown, I can to that. But there does not seem to be a way to filter on m_file.Type == Self.Type

解决方案

It is actually quite easy to create your admin form classes dynamically. Something like this should work:

def tagform_factory(filetype):
    class TagForm(forms.ModelForm):
        m_file = forms.ModelChoiceField(
            queryset=ManagedFile.objects.filter(type=filetype)
        )
    return TagForm


class TagAdmin(admin.ModelAdmin):

    def get_form(self, request, obj=None, **kwargs):
        if obj is not None and obj.type is not None:
            kwargs['form'] = tagform_factory(obj.type)
        return super(TagAdmin, self).get_form(request, obj, **kwargs)

Note that the get_form method is responsible for building the form class, not the form instance. It is badly named, IMHO.

However, you still need to decide what to do for forms that are used to add new tags, rather than edit existing ones. In that case you do not yet have a type to which you can restrict the dropdown. Maybe there is actually a data modeling problem lurking here? Do you really need the type field on the Tag model? Maybe it should just be removed?

这篇关于Django管理员根据另一个字段过滤ForeignKey下拉列表的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
相关文章
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆