我试图使用limit_choices_to限制Django Admin对ForeignKey的选择,但我无法弄清楚如何正确地做到这一点。
如果类别ID为16,此代码可以满足我的要求,但我无法弄清楚如何使用当前类别ID而不是硬编码。
class MovieCategory(models.Model):
category = models.ForeignKey(Category)
movie = models.ForeignKey(Movie)
prefix = models.ForeignKey('Prefix', limit_choices_to={'category_id': '16'},
blank=True, null=True)
number = models.DecimalField(verbose_name='Movie Number', max_digits=2,
blank=True, null=True, decimal_places=0)
是否有可能以某种方式引用ForeignKey类别的id?
答案 0 :(得分:15)
经过几个小时的阅读半相关问题后,我终于弄明白了。
你不能像我试图那样自我引用模型,所以没有办法让django按照我想要的方式使用limit_choices_to,因为它无法在同一模型中找到不同ForeignKey的id。
如果你改变django的工作方式,显然可以做到这一点,但解决这个问题的一种更简单的方法就是改为admin.py.
以下是我的models.py现在的样子:
# models.py
class MovieCategory(models.Model):
category = models.ForeignKey(Category)
movie = models.ForeignKey(Movie)
prefix = models.ForeignKey('Prefix', blank=True, null=True)
number = models.DecimalField(verbose_name='Movie Number', max_digits=2,
blank=True, null=True, decimal_places=0)
我完全删除了limit_choices_to。
我在Kyle Duncan发布的解决方案中找到了类似的问题here。
但不同之处在于它使用ManyToMany而不是ForeignKey。这意味着我必须删除我的班级filter_horizontal = ('prefix',)
下的MovieCategoryAdmin(admin.ModelAdmin):
,因为这仅适用于ManyToMany字段。
在admin.py中,我必须在顶部添加from django import forms
才能创建表单。
这就是表单的外观:
class MovieCategoryForm(forms.ModelForm):
class Meta:
model = MovieCategory
fields = ['prefix']
def __init__(self, *args, **kwargs):
super(MovieCategoryForm, self).__init__(*args, **kwargs)
self.fields['prefix'].queryset = Prefix.objects.filter(
category_id=self.instance.category.id)
我的AdminModel:
class MovieCategoryAdmin(admin.ModelAdmin):
"""
Admin Class for 'Movie Category'.
"""
fieldsets = [
('Category', {'fields': ['category']}),
('Movie', {'fields': ['movie']}),
('Prefix', {'fields': ['prefix']}),
('Number', {'fields': ['number']}),
]
list_display = ('category', 'movie', 'prefix', 'number')
search_fields = ['category__category_name', 'movie__title', 'prefix__prefix']
form = MovieCategoryForm
这正是Kyle在他的回答中描述的内容,除了我必须在表单中添加fields = ['prefix']
或者它不会运行。如果你按照他的步骤并记得删除filter_horizontal并添加你正在使用的字段,它应该可以工作。
编辑:此解决方案在编辑时工作正常,但在创建新条目时则无效,因为当一个人不退出时,它无法搜索类别ID。我想弄清楚如何解决这个问题。
答案 1 :(得分:1)
如果您不想添加自定义ModelForm,另一种方法是在ModelAdmin的get_form()
方法中处理此问题。这对我来说更可取,因为我需要轻松访问查询集的请求对象。
class StoryAdmin(admin.ModelAdmin):
def get_form(self, request, obj=None, **kwargs):
form = super(StoryAdmin, self).get_form(request, obj, **kwargs)
form.base_fields['local_categories'].queryset = LocalStoryCategory.\
objects.filter(office=request.user.profile.office)
return form
答案 2 :(得分:0)
请记住,limit_choices_to
支持“Either a dictionary, a Q object, or a callable returning a dictionary or Q object”并且理论上应该支持可以使用 django 的查询集过滤完成的任何查找。一个潜在的解决方案是根据您控制的类别的某些属性(例如 slug 字段)进行过滤。
class MovieCategory(models.Model):
category = models.ForeignKey(Category)
movie = models.ForeignKey(Movie)
prefix = models.ForeignKey('Prefix', blank=True, null=True,
limit_choices_to=Q(category__slug__startswith='movie'))
number = models.DecimalField(verbose_name='Movie Number', max_digits=2,
blank=True, null=True, decimal_places=0)
答案 3 :(得分:-1)
我有同样的问题,你的自我回答帮助我开始。但我还发现另一篇文章(question-12399803)完成了答案,即如何在创建新条目时进行过滤。
在views.py
中form = CustomerForm(groupid=request.user.groups.first().id)
在forms.py
中def __init__(self, *args, **kwargs):
if 'groupid' in kwargs:
groupid = kwargs.pop('groupid')
else:
groupid = None
super(CustomerForm, self).__init__(*args, **kwargs)
if not groupid:
groupid = self.instance.group.id
self.fields['address'].queryset = Address.objects.filter(group_id=groupid)
因此,无论是添加新客户还是更新现有客户,我都可以点击链接添加将分配给该客户的新地址。
这是我在StackOverflow上的第一个答案。我希望它有所帮助。