假设我在models.py
中有以下内容:
class Company(models.Model):
name = ...
class Rate(models.Model):
company = models.ForeignKey(Company)
name = ...
class Client(models.Model):
name = ...
company = models.ForeignKey(Company)
base_rate = models.ForeignKey(Rate)
即有多个Companies
,每个Rates
和Clients
的范围。每个Client
应该有一个从其父Company's Rates
中选择的基Rate
,而不是另一个Company's Rates
。
在创建用于添加Client
的表单时,我希望删除Company
选项(因为已经通过Company
页面上的“添加客户端”按钮选择了该选项),并将Rate
选项限制为Company
。
在Django 1.0中如何实现这一点?
我当前的forms.py
文件目前只是样板文件:
from models import *
from django.forms import ModelForm
class ClientForm(ModelForm):
class Meta:
model = Client
views.py
也是基本的:
from django.shortcuts import render_to_response, get_object_or_404
from models import *
from forms import *
def addclient(request, company_id):
the_company = get_object_or_404(Company, id=company_id)
if request.POST:
form = ClientForm(request.POST)
if form.is_valid():
form.save()
return HttpResponseRedirect(the_company.get_clients_url())
else:
form = ClientForm()
return render_to_response('addclient.html', {'form': form, 'the_company':the_company})
在Django 0.96中,我可以在渲染模板之前做以下事情来破解这个问题:
manipulator.fields[0].choices = [(r.id,r.name) for r in Rate.objects.filter(company_id=the_company.id)]
ForeignKey.limit_choices_to
看起来很有希望,但我不知道如何传入the_company.id
,我不清楚这是否会在Admin界面之外工作。
谢谢。(这似乎是一个非常基本的要求,但如果我应该重新设计的东西,我愿意接受建议。)
9条答案
按热度按时间p4rjhz4m1#
ForeignKey由django.forms.ModelChoiceField表示,这是一个ChoiceField,其选择是一个模型QuerySet。请参阅ModelChoiceField的参考。
因此,为字段的
queryset
属性提供QuerySet。这取决于表单的构建方式。如果构建显式表单,则将直接命名字段。如果使用默认的ModelForm对象
form.fields["rate"].queryset = ...
这是在视图中显式完成的。没有黑客攻击。
cx6n0qe32#
除了S.Lott的回答,正如评论中提到的那样,可以通过覆盖
ModelForm.__init__
函数来添加查询集过滤器。(这可以很容易地应用于常规表单)它可以帮助重用并保持视图函数的整洁。这对于重用很有用,比如说,如果你有很多模型需要公共的过滤器(通常我声明一个抽象的Form类)。
除此之外,我只是重申Django博客材料,其中有许多好的。
2skhul333#
这很简单,适用于Django 1.4:
你不需要在表单类中指定它,但可以直接在ModelAdmin中指定,因为Django已经在ModelAdmin中包含了这个内置方法(来自文档):
一个更好的方法(例如创建一个用户可以访问的前端管理界面)是子类化ModelAdmin,然后改变下面的方法。最终结果是一个用户界面,只显示与他们相关的内容,同时允许您(超级用户)看到所有内容。
我已经覆盖了四个方法,前两个方法使用户无法删除任何内容,并且它还删除了管理站点上的删除按钮。
第三个覆盖过滤任何包含引用的查询(在示例中为“user”或“porcupine”(仅作为说明))。
最后一个覆盖过滤模型中的任何外键字段,以过滤与基本查询集相同的可用选项。
通过这种方式,您可以呈现一个易于管理的前端管理站点,允许用户随意处理自己的对象,并且您不必记住键入我们上面讨论的特定ModelAdmin过滤器。
移除“删除”按钮:
阻止删除权限
过滤可在管理站点上查看的对象:
筛选管理站点上所有外键字段的选项:
wwtsj6pe4#
要使用通用视图(如CreateView)执行此操作...
其中最重要的部分
,read my post here
tkqqtvp15#
如果你还没有创建表单,想要更改查询集,你可以这样做:
当你使用通用视图时,这是非常有用的!
polhcujo6#
所以,我真的试着去理解这一点,但似乎Django仍然没有让它变得非常简单。我不是那么愚蠢,但我就是看不到任何(有点)简单的解决方案。
我发现在这种情况下必须覆盖Admin视图通常是非常丑陋的,而且我发现的每个示例都不完全适用于Admin视图。
这是我制作的模型中常见的情况,我发现没有明显的解决方案是令人震惊的。
我有这些课程:
这在为公司设置管理员时会产生问题,因为它有合同和位置的内联,并且合同的位置m2m选项没有根据您当前编辑的公司进行正确过滤。
简而言之,我需要一些管理选项来做这样的事情:
最后,我不关心过滤过程是放在基本的CompanyAdmin上,还是放在ContractInline上(放在inline上更有意义,但它很难将基本的Contract引用为“self”)。
有没有人知道像这个迫切需要的快捷方式这样简单的东西?当我为这类事情做PHP管理员时,这被认为是基本的功能!事实上,它总是自动的,如果你真的不想要它,就必须禁用它!
oiopk7p57#
一种更公开的方法是在Admin类中调用get_form。它也适用于非数据库字段。例如,这里我在表单上有一个名为'_terminal_list'的字段,可以在特殊情况下使用,用于从get_list(request)中选择几个终端项,然后根据请求进行过滤。user:
ccrfmcuu8#
在运行时(例如在CreateView中)限制ModelForm的ForeignKey字段的选择的一个好方法是通过在视图中覆盖
get_form_class()
来为base_fields['field_name']
设置limit_choices_to
。例如,在创建客户端时,要将“Rate”的选择限制为URL中标识的“Company”的选择:
k2arahey9#
根据Django文档,您可以使用模型表单的
__init__
方法将过滤器应用于默认查询集。https://docs.djangoproject.com/en/3.1/ref/contrib/admin/#django.contrib.admin.ModelAdmin.formfield_for_foreignkey