假设我在我的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)

也就是说,有多个公司,每个公司都有一系列的费率和客户。每个客户都应该有一个从其母公司的利率中选择的基础利率,而不是其他公司的利率。

当创建一个添加客户端表单时,我想删除公司选项(因为已经通过公司页面上的“添加客户端”按钮进行了选择),并将费率选项限制为该公司。

在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。看起来很有前途,但我不知道如何在公司里过关。id和我不清楚,如果这将工作以外的管理界面无论如何。

谢谢。(这似乎是一个非常基本的要求,但如果我应该重新设计一些东西,我愿意听取建议。)


当前回答

更公开的方法是在Admin类中调用get_form。它也适用于非数据库字段。例如,在这里我有一个名为'_terminal_list'的字段,可以在特殊情况下使用,从get_list(请求)中选择几个终端项,然后根据request.user进行过滤:

class ChangeKeyValueForm(forms.ModelForm):  
    _terminal_list = forms.ModelMultipleChoiceField( 
queryset=Terminal.objects.all() )

    class Meta:
        model = ChangeKeyValue
        fields = ['_terminal_list', 'param_path', 'param_value', 'scheduled_time',  ] 

class ChangeKeyValueAdmin(admin.ModelAdmin):
    form = ChangeKeyValueForm
    list_display = ('terminal','task_list', 'plugin','last_update_time')
    list_per_page =16

    def get_form(self, request, obj = None, **kwargs):
        form = super(ChangeKeyValueAdmin, self).get_form(request, **kwargs)
        qs, filterargs = Terminal.get_list(request)
        form.base_fields['_terminal_list'].queryset = qs
        return form

其他回答

所以,我真的试图理解这一点,但似乎Django仍然没有使它非常简单。我不是那么笨,但我就是看不到任何(多少)简单的解决办法。

我发现对于这类事情,必须覆盖Admin视图通常是非常丑陋的,而且我发现的每个示例都不能完全应用于Admin视图。

这在我做的模型中是很常见的情况,我发现没有明显的解决方案是令人震惊的……

我有这些类:

# models.py
class Company(models.Model):
    # ...
class Contract(models.Model):
    company = models.ForeignKey(Company)
    locations = models.ManyToManyField('Location')
class Location(models.Model):
    company = models.ForeignKey(Company)

这在为Company设置Admin时产生了一个问题,因为它有内联的合同和位置,合同的m2m位置选项没有根据您当前编辑的公司进行适当的过滤。

简而言之,我需要一些管理选项来做这样的事情:

# admin.py
class LocationInline(admin.TabularInline):
    model = Location
class ContractInline(admin.TabularInline):
    model = Contract
class CompanyAdmin(admin.ModelAdmin):
    inlines = (ContractInline, LocationInline)
    inline_filter = dict(Location__company='self')

最终,我不关心过滤过程是放在基础CompanyAdmin上,还是放在ContractInline上。(将它放在内联更有意义,但它很难将基契约引用为“self”。)

有人知道像这条急需的捷径一样简单的东西吗?当我为这类事情创建PHP管理员时,这被认为是基本功能!事实上,它总是自动的,如果你真的不想要它,就必须关闭它!

更公开的方法是在Admin类中调用get_form。它也适用于非数据库字段。例如,在这里我有一个名为'_terminal_list'的字段,可以在特殊情况下使用,从get_list(请求)中选择几个终端项,然后根据request.user进行过滤:

class ChangeKeyValueForm(forms.ModelForm):  
    _terminal_list = forms.ModelMultipleChoiceField( 
queryset=Terminal.objects.all() )

    class Meta:
        model = ChangeKeyValue
        fields = ['_terminal_list', 'param_path', 'param_value', 'scheduled_time',  ] 

class ChangeKeyValueAdmin(admin.ModelAdmin):
    form = ChangeKeyValueForm
    list_display = ('terminal','task_list', 'plugin','last_update_time')
    list_per_page =16

    def get_form(self, request, obj = None, **kwargs):
        form = super(ChangeKeyValueAdmin, self).get_form(request, **kwargs)
        qs, filterargs = Terminal.get_list(request)
        form.base_fields['_terminal_list'].queryset = qs
        return form

ForeignKey由django.forms表示。ModelChoiceField是一个ChoiceField,它的选项是一个模型QuerySet。请参阅ModelChoiceField的参考。

因此,为字段的QuerySet属性提供一个QuerySet。这取决于你的表单是如何构建的。如果构建显式表单,则会直接为字段命名。

form.rate.queryset = Rate.objects.filter(company_id=the_company.id)

如果您使用默认的ModelForm对象,form.fields["rate"]。Queryset =…

这是在视图中显式完成的。不要到处乱黑。

根据Django文档,你可以使用模型表单的__init__方法对默认的queryset应用过滤器。

https://docs.djangoproject.com/en/3.1/ref/contrib/admin/#django.contrib.admin.ModelAdmin.formfield_for_foreignkey

class CountryAdminForm(forms.ModelForm):
    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        self.fields['capital'].queryset = self.instance.cities.all()

class CountryAdmin(admin.ModelAdmin):
    form = CountryAdminForm

要做到这一点,用一个通用视图,如CreateView…

class AddPhotoToProject(CreateView):
    """
    a view where a user can associate a photo with a project
    """
    model = Connection
    form_class = CreateConnectionForm


    def get_context_data(self, **kwargs):
        context = super(AddPhotoToProject, self).get_context_data(**kwargs)
        context['photo'] = self.kwargs['pk']
        context['form'].fields['project'].queryset = Project.objects.for_user(self.request.user)
        return context
    def form_valid(self, form):
        pobj = Photo.objects.get(pk=self.kwargs['pk'])
        obj = form.save(commit=False)
        obj.photo = pobj
        obj.save()

        return_json = {'success': True}

        if self.request.is_ajax():

            final_response = json.dumps(return_json)
            return HttpResponse(final_response)

        else:

            messages.success(self.request, 'photo was added to project!')
            return HttpResponseRedirect(reverse('MyPhotos'))

最重要的是…

    context['form'].fields['project'].queryset = Project.objects.for_user(self.request.user)

,在这里阅读我的文章