如何过滤Django模型形式中的foreign - key选项?

时间:2021-11-17 02:53:27

Say I have the following in my 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)

I.e. there are multiple Companies, each having a range of Rates and Clients. Each Client should have a base Rate that is chosen from it's parent Company's Rates, not another Company's Rates.

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

When creating a form for adding a Client, I would like to remove the Company choices (as that has already been selected via an "Add Client" button on the Company page) and limit the Rate choices to that Company as well.

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

How do I go about this in Django 1.0?

在Django 1.0中我该怎么做呢?

My current forms.py file is just boilerplate at the moment:

我目前的形式。py文件目前只是样板文件:

from models import *
from django.forms import ModelForm

class ClientForm(ModelForm):
    class Meta:
        model = Client

And the views.py is also basic:

和视图。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})

In Django 0.96 I was able to hack this in by doing something like the following before rendering the template:

在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 seems promising but I don't know how to pass in the_company.id and I'm not clear if that will work outside the Admin interface anyway.

ForeignKey。limit_choices_to看起来很有前途,但是我不知道如何在公司里过关。id和我不清楚这是否会在管理界面之外工作。

Thanks. (This seems like a pretty basic request but if I should redesign something I'm open to suggestions.)

谢谢。(这似乎是一个相当基本的要求,但如果我重新设计一些东西,我愿意接受建议。)

7 个解决方案

#1


207  

ForeignKey is represented by django.forms.ModelChoiceField, which is a ChoiceField whose choices are a model QuerySet. See the reference for ModelChoiceField.

ForeignKey由django.forms(表格)表示。ModelChoiceField是一个ChoiceField,它的选择是一个模型QuerySet。参见ModelChoiceField的引用。

So, provide a QuerySet to the field's queryset attribute. Depends on how your form is built. If you build an explicit form, you'll have fields named directly.

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

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

If you take the default ModelForm object, form.fields["rate"].queryset = ...

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

This is done explicitly in the view. No hacking around.

这是在视图中显式完成的。没有黑客。

#2


118  

In addition to S.Lott's answer and as becomingGuru mentioned in comments, its possible to add the queryset filters by overriding the ModelForm.__init__ function. (This could easily apply to regular forms) it can help with reuse and keeps the view function tidy.

除了年代。Lott的回答和注释中提到的成为guru,可以通过覆盖ModelForm添加queryset过滤器。__init__函数。(这可以很容易地应用于规则表单),它可以帮助重用并保持视图功能的整洁。

class ClientForm(forms.ModelForm):
    def __init__(self,company,*args,**kwargs):
        super (ClientForm,self ).__init__(*args,**kwargs) # populates the post
        self.fields['rate'].queryset = Rate.objects.filter(company=company)
        self.fields['client'].queryset = Client.objects.filter(company=company)

    class Meta:
        model = Client

def addclient(request, company_id):
        the_company = get_object_or_404(Company, id=company_id)

        if request.POST:
            form = ClientForm(the_company,request.POST)  #<-- Note the extra arg
            if form.is_valid():
                form.save()
                return HttpResponseRedirect(the_company.get_clients_url())
        else:
            form = ClientForm(the_company)

        return render_to_response('addclient.html', 
                                  {'form': form, 'the_company':the_company})

This can be useful for reuse say if you have common filters needed on many models (normally I declare an abstract Form class). E.g.

如果在许多模型上都需要公共过滤器(通常我声明一个抽象表单类),这对于重用是有用的。如。

class UberClientForm(ClientForm):
    class Meta:
        model = UberClient

def view(request):
    ...
    form = UberClientForm(company)
    ...

#or even extend the existing custom init
class PITAClient(ClientForm):
    def __init__(company, *args, **args):
        super (PITAClient,self ).__init__(company,*args,**kwargs)
        self.fields['support_staff'].queryset = User.objects.exclude(user='michael')

Other than that I'm just restating Django blog material of which there are many good ones out there.

除此之外,我还重申了Django的博客材料,其中有很多很好的材料。

#3


39  

This is simple, and works with Django 1.4:

这很简单,适用于Django 1.4:

class ClientAdminForm(forms.ModelForm):
    def __init__(self, *args, **kwargs):
        super(ClientAdminForm, self).__init__(*args, **kwargs)
        # access object through self.instance...
        self.fields['base_rate'].queryset = Rate.objects.filter(company=self.instance.company)

class ClientAdmin(admin.ModelAdmin):
    form = ClientAdminForm
    ....

You don't need to specify this in a form class, but can do it directly in the ModelAdmin, as Django already includes this built-in method on the ModelAdmin (from the docs):

您不需要在表单类中指定它,但是可以在ModelAdmin中直接指定,因为Django已经在ModelAdmin(来自文档)中包含了这个内置方法:

ModelAdmin.formfield_for_foreignkey(self, db_field, request, **kwargs)¶
'''The formfield_for_foreignkey method on a ModelAdmin allows you to 
   override the default formfield for a foreign keys field. For example, 
   to return a subset of objects for this foreign key field based on the
   user:'''

class MyModelAdmin(admin.ModelAdmin):
    def formfield_for_foreignkey(self, db_field, request, **kwargs):
        if db_field.name == "car":
            kwargs["queryset"] = Car.objects.filter(owner=request.user)
        return super(MyModelAdmin, self).formfield_for_foreignkey(db_field, request, **kwargs)

An even niftier way to do this (for example in creating a front-end admin interface that users can access) is to subclass the ModelAdmin and then alter the methods below. The net result is a user interface that ONLY shows them content that is related to them, while allowing you (a super-user) to see everything.

实现这一点的一种更简单的方法(例如创建用户可以访问的前端管理界面)是子类化ModelAdmin,然后修改下面的方法。最终的结果是用户界面只显示与它们相关的内容,同时允许您(超级用户)查看所有内容。

I've overridden four methods, the first two make it impossible for a user to delete anything, and it also removes the delete buttons from the admin site.

我已经重写了四种方法,前两种方法使用户不可能删除任何内容,它还从管理站点删除了delete按钮。

The third override filters any query that contains a reference to (in the example 'user' or 'porcupine' (just as an illustration).

第三个覆盖筛选任何包含引用的查询(在示例“user”或“porcupine”中)(作为示例)。

The last override filters any foreignkey field in the model to filter the choices available the same as the basic queryset.

最后的覆盖筛选模型中的任何foreignkey字段,以筛选与基本的queryset相同的选项。

In this way, you can present an easy to manage front-facing admin site that allows users to mess with their own objects, and you don't have to remember to type in the specific ModelAdmin filters we talked about above.

通过这种方式,您可以提供一个易于管理的前端管理站点,该站点允许用户处理自己的对象,并且您不必记住输入我们上面讨论过的特定的ModelAdmin过滤器。

class FrontEndAdmin(models.ModelAdmin):
    def __init__(self, model, admin_site):
        self.model = model
        self.opts = model._meta
        self.admin_site = admin_site
        super(FrontEndAdmin, self).__init__(model, admin_site)

remove 'delete' buttons:

删除“删除”按钮:

    def get_actions(self, request):
        actions = super(FrontEndAdmin, self).get_actions(request)
        if 'delete_selected' in actions:
            del actions['delete_selected']
        return actions

prevents delete permission

防止删除权限

    def has_delete_permission(self, request, obj=None):
        return False

filters objects that can be viewed on the admin site:

筛选可在管理站点上查看的对象:

    def get_queryset(self, request):
        if request.user.is_superuser:
            try:
                qs = self.model.objects.all()
            except AttributeError:
                qs = self.model._default_manager.get_queryset()
            return qs

        else:
            try:
                qs = self.model.objects.all()
            except AttributeError:
                qs = self.model._default_manager.get_queryset()

            if hasattr(self.model, ‘user’):
                return qs.filter(user=request.user)
            if hasattr(self.model, ‘porcupine’):
                return qs.filter(porcupine=request.user.porcupine)
            else:
                return qs

filters choices for all foreignkey fields on the admin site:

过滤器选择的所有外国人关键字在管理网站:

    def formfield_for_foreignkey(self, db_field, request, **kwargs):
        if request.employee.is_superuser:
            return super(FrontEndAdmin, self).formfield_for_foreignkey(db_field, request, **kwargs)

        else:
            if hasattr(db_field.rel.to, 'user'):
                kwargs["queryset"] = db_field.rel.to.objects.filter(user=request.user)
            if hasattr(db_field.rel.to, 'porcupine'):
                kwargs["queryset"] = db_field.rel.to.objects.filter(porcupine=request.user.porcupine)
            return super(ModelAdminFront, self).formfield_for_foreignkey(db_field, request, **kwargs)

#4


15  

To do this with a generic view, like CreateView...

要使用通用视图来实现这一点,比如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'))

the most important part of that...

最重要的是……

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

, read my post here

在这里阅读我的文章

#5


4  

If you haven't created the form and want to change the queryset you can do:

如果您还没有创建表单并想要更改queryset,您可以这样做:

formmodel.base_fields['myfield'].queryset = MyModel.objects.filter(...)

This is pretty useful when you are using generic views!

这在使用通用视图时非常有用!

#6


2  

So, I've really tried to understand this, but it seems that Django still doesn't make this very straightforward. I'm not all that dumb, but I just can't see any (somewhat) simple solution.

所以,我真的试着去理解它,但是Django似乎并没有把它变得非常简单。我并不是那么笨,但我只是看不到任何(或多或少)简单的解决方案。

I find it generally pretty ugly to have to override the Admin views for this sort of thing, and every example I find never fully applies to the Admin views.

我发现,为这类事情重写管理视图通常是很难看的,而且我发现的每个示例都不能完全适用于管理视图。

This is such a common circumstance with the models I make that I find it appalling that there's no obvious solution to this...

这是我制作的模型中常见的情况,我发现没有明显的解决方案是令人震惊的。

I've got these classes:

我有这些类:

# 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)

This creates a problem when setting up the Admin for Company, because it has inlines for both Contract and Location, and Contract's m2m options for Location are not properly filtered according to the Company that you're currently editing.

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

In short, I would need some admin option to do something like this:

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

# 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')

Ultimately I wouldn't care if the filtering process was placed on the base CompanyAdmin, or if it was placed on the ContractInline. (Placing it on the inline makes more sense, but it makes it hard to reference the base Contract as 'self'.)

最终,我不会关心过滤过程是否被放置在基础公司管理上,或者是否被放置在ContractInline上。(把它放在内联上更有意义,但它很难将基本契约引用为“自我”。)

Is there anyone out there who knows of something as straightforward as this badly needed shortcut? Back when I made PHP admins for this sort of thing, this was considered basic functionality! In fact, it was always automatic, and had to be disabled if you really didn't want it!

有没有人知道有什么东西像这条急需的捷径一样直截了当?当我为这类事情做PHP管理员时,这被认为是基本的功能!事实上,它总是自动的,如果你真的不想要它,就必须被禁用!

#7


0  

A more public way is by calling get_form in Admin classes. It also works for non-database fields too. For example here i have a field called '_terminal_list' on the form that can be used in special cases for choosing several terminal items from get_list(request), then filtering based on request.user:

更公开的方法是在管理类中调用get_form。它也适用于非数据库字段。例如,在这里我有一个名为“_terminal_list”的字段,它可以用于从get_list(请求)中选择多个终端项,然后根据请求进行过滤。

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

#1


207  

ForeignKey is represented by django.forms.ModelChoiceField, which is a ChoiceField whose choices are a model QuerySet. See the reference for ModelChoiceField.

ForeignKey由django.forms(表格)表示。ModelChoiceField是一个ChoiceField,它的选择是一个模型QuerySet。参见ModelChoiceField的引用。

So, provide a QuerySet to the field's queryset attribute. Depends on how your form is built. If you build an explicit form, you'll have fields named directly.

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

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

If you take the default ModelForm object, form.fields["rate"].queryset = ...

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

This is done explicitly in the view. No hacking around.

这是在视图中显式完成的。没有黑客。

#2


118  

In addition to S.Lott's answer and as becomingGuru mentioned in comments, its possible to add the queryset filters by overriding the ModelForm.__init__ function. (This could easily apply to regular forms) it can help with reuse and keeps the view function tidy.

除了年代。Lott的回答和注释中提到的成为guru,可以通过覆盖ModelForm添加queryset过滤器。__init__函数。(这可以很容易地应用于规则表单),它可以帮助重用并保持视图功能的整洁。

class ClientForm(forms.ModelForm):
    def __init__(self,company,*args,**kwargs):
        super (ClientForm,self ).__init__(*args,**kwargs) # populates the post
        self.fields['rate'].queryset = Rate.objects.filter(company=company)
        self.fields['client'].queryset = Client.objects.filter(company=company)

    class Meta:
        model = Client

def addclient(request, company_id):
        the_company = get_object_or_404(Company, id=company_id)

        if request.POST:
            form = ClientForm(the_company,request.POST)  #<-- Note the extra arg
            if form.is_valid():
                form.save()
                return HttpResponseRedirect(the_company.get_clients_url())
        else:
            form = ClientForm(the_company)

        return render_to_response('addclient.html', 
                                  {'form': form, 'the_company':the_company})

This can be useful for reuse say if you have common filters needed on many models (normally I declare an abstract Form class). E.g.

如果在许多模型上都需要公共过滤器(通常我声明一个抽象表单类),这对于重用是有用的。如。

class UberClientForm(ClientForm):
    class Meta:
        model = UberClient

def view(request):
    ...
    form = UberClientForm(company)
    ...

#or even extend the existing custom init
class PITAClient(ClientForm):
    def __init__(company, *args, **args):
        super (PITAClient,self ).__init__(company,*args,**kwargs)
        self.fields['support_staff'].queryset = User.objects.exclude(user='michael')

Other than that I'm just restating Django blog material of which there are many good ones out there.

除此之外,我还重申了Django的博客材料,其中有很多很好的材料。

#3


39  

This is simple, and works with Django 1.4:

这很简单,适用于Django 1.4:

class ClientAdminForm(forms.ModelForm):
    def __init__(self, *args, **kwargs):
        super(ClientAdminForm, self).__init__(*args, **kwargs)
        # access object through self.instance...
        self.fields['base_rate'].queryset = Rate.objects.filter(company=self.instance.company)

class ClientAdmin(admin.ModelAdmin):
    form = ClientAdminForm
    ....

You don't need to specify this in a form class, but can do it directly in the ModelAdmin, as Django already includes this built-in method on the ModelAdmin (from the docs):

您不需要在表单类中指定它,但是可以在ModelAdmin中直接指定,因为Django已经在ModelAdmin(来自文档)中包含了这个内置方法:

ModelAdmin.formfield_for_foreignkey(self, db_field, request, **kwargs)¶
'''The formfield_for_foreignkey method on a ModelAdmin allows you to 
   override the default formfield for a foreign keys field. For example, 
   to return a subset of objects for this foreign key field based on the
   user:'''

class MyModelAdmin(admin.ModelAdmin):
    def formfield_for_foreignkey(self, db_field, request, **kwargs):
        if db_field.name == "car":
            kwargs["queryset"] = Car.objects.filter(owner=request.user)
        return super(MyModelAdmin, self).formfield_for_foreignkey(db_field, request, **kwargs)

An even niftier way to do this (for example in creating a front-end admin interface that users can access) is to subclass the ModelAdmin and then alter the methods below. The net result is a user interface that ONLY shows them content that is related to them, while allowing you (a super-user) to see everything.

实现这一点的一种更简单的方法(例如创建用户可以访问的前端管理界面)是子类化ModelAdmin,然后修改下面的方法。最终的结果是用户界面只显示与它们相关的内容,同时允许您(超级用户)查看所有内容。

I've overridden four methods, the first two make it impossible for a user to delete anything, and it also removes the delete buttons from the admin site.

我已经重写了四种方法,前两种方法使用户不可能删除任何内容,它还从管理站点删除了delete按钮。

The third override filters any query that contains a reference to (in the example 'user' or 'porcupine' (just as an illustration).

第三个覆盖筛选任何包含引用的查询(在示例“user”或“porcupine”中)(作为示例)。

The last override filters any foreignkey field in the model to filter the choices available the same as the basic queryset.

最后的覆盖筛选模型中的任何foreignkey字段,以筛选与基本的queryset相同的选项。

In this way, you can present an easy to manage front-facing admin site that allows users to mess with their own objects, and you don't have to remember to type in the specific ModelAdmin filters we talked about above.

通过这种方式,您可以提供一个易于管理的前端管理站点,该站点允许用户处理自己的对象,并且您不必记住输入我们上面讨论过的特定的ModelAdmin过滤器。

class FrontEndAdmin(models.ModelAdmin):
    def __init__(self, model, admin_site):
        self.model = model
        self.opts = model._meta
        self.admin_site = admin_site
        super(FrontEndAdmin, self).__init__(model, admin_site)

remove 'delete' buttons:

删除“删除”按钮:

    def get_actions(self, request):
        actions = super(FrontEndAdmin, self).get_actions(request)
        if 'delete_selected' in actions:
            del actions['delete_selected']
        return actions

prevents delete permission

防止删除权限

    def has_delete_permission(self, request, obj=None):
        return False

filters objects that can be viewed on the admin site:

筛选可在管理站点上查看的对象:

    def get_queryset(self, request):
        if request.user.is_superuser:
            try:
                qs = self.model.objects.all()
            except AttributeError:
                qs = self.model._default_manager.get_queryset()
            return qs

        else:
            try:
                qs = self.model.objects.all()
            except AttributeError:
                qs = self.model._default_manager.get_queryset()

            if hasattr(self.model, ‘user’):
                return qs.filter(user=request.user)
            if hasattr(self.model, ‘porcupine’):
                return qs.filter(porcupine=request.user.porcupine)
            else:
                return qs

filters choices for all foreignkey fields on the admin site:

过滤器选择的所有外国人关键字在管理网站:

    def formfield_for_foreignkey(self, db_field, request, **kwargs):
        if request.employee.is_superuser:
            return super(FrontEndAdmin, self).formfield_for_foreignkey(db_field, request, **kwargs)

        else:
            if hasattr(db_field.rel.to, 'user'):
                kwargs["queryset"] = db_field.rel.to.objects.filter(user=request.user)
            if hasattr(db_field.rel.to, 'porcupine'):
                kwargs["queryset"] = db_field.rel.to.objects.filter(porcupine=request.user.porcupine)
            return super(ModelAdminFront, self).formfield_for_foreignkey(db_field, request, **kwargs)

#4


15  

To do this with a generic view, like CreateView...

要使用通用视图来实现这一点,比如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'))

the most important part of that...

最重要的是……

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

, read my post here

在这里阅读我的文章

#5


4  

If you haven't created the form and want to change the queryset you can do:

如果您还没有创建表单并想要更改queryset,您可以这样做:

formmodel.base_fields['myfield'].queryset = MyModel.objects.filter(...)

This is pretty useful when you are using generic views!

这在使用通用视图时非常有用!

#6


2  

So, I've really tried to understand this, but it seems that Django still doesn't make this very straightforward. I'm not all that dumb, but I just can't see any (somewhat) simple solution.

所以,我真的试着去理解它,但是Django似乎并没有把它变得非常简单。我并不是那么笨,但我只是看不到任何(或多或少)简单的解决方案。

I find it generally pretty ugly to have to override the Admin views for this sort of thing, and every example I find never fully applies to the Admin views.

我发现,为这类事情重写管理视图通常是很难看的,而且我发现的每个示例都不能完全适用于管理视图。

This is such a common circumstance with the models I make that I find it appalling that there's no obvious solution to this...

这是我制作的模型中常见的情况,我发现没有明显的解决方案是令人震惊的。

I've got these classes:

我有这些类:

# 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)

This creates a problem when setting up the Admin for Company, because it has inlines for both Contract and Location, and Contract's m2m options for Location are not properly filtered according to the Company that you're currently editing.

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

In short, I would need some admin option to do something like this:

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

# 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')

Ultimately I wouldn't care if the filtering process was placed on the base CompanyAdmin, or if it was placed on the ContractInline. (Placing it on the inline makes more sense, but it makes it hard to reference the base Contract as 'self'.)

最终,我不会关心过滤过程是否被放置在基础公司管理上,或者是否被放置在ContractInline上。(把它放在内联上更有意义,但它很难将基本契约引用为“自我”。)

Is there anyone out there who knows of something as straightforward as this badly needed shortcut? Back when I made PHP admins for this sort of thing, this was considered basic functionality! In fact, it was always automatic, and had to be disabled if you really didn't want it!

有没有人知道有什么东西像这条急需的捷径一样直截了当?当我为这类事情做PHP管理员时,这被认为是基本的功能!事实上,它总是自动的,如果你真的不想要它,就必须被禁用!

#7


0  

A more public way is by calling get_form in Admin classes. It also works for non-database fields too. For example here i have a field called '_terminal_list' on the form that can be used in special cases for choosing several terminal items from get_list(request), then filtering based on request.user:

更公开的方法是在管理类中调用get_form。它也适用于非数据库字段。例如,在这里我有一个名为“_terminal_list”的字段,它可以用于从get_list(请求)中选择多个终端项,然后根据请求进行过滤。

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