Django:从ModelAdmin中访问模型实例?

我有一个网上商店应用程序的订单模型,自动增加主键和外键本身,因为订单可以分成多个订单,但必须保持与原始订单的关系。

class Order(models.Model): ordernumber = models.AutoField(primary_key=True) parent_order = models.ForeignKey('self', null=True, blank=True, related_name='child_orders') # .. other fields not relevant here 

我为pipe理网站注册了一个OrderAdmin类。 对于详细视图,我在fieldsets属性中包含了parent_order 。 当然,默认情况下,这会列出select框中的所有订单,但这不是所需的行为。 相反,对于没有父订单的订单(即, parent_order从其他订单拆分; parent_order为NULL /无),则不应显示订单。 对于已拆分的订单,这应该只显示单亲订单。

有一个相当新的ModelAdmin方法可用, formfield_for_foreignkey ,这似乎是完美的,因为queryset可以在里面过滤。 假设我们正在查看订单#11234的细节视图,该订单已从订单#11208中拆分。 代码如下

 def formfield_for_foreignkey(self, db_field, request, **kwargs): if db_field.name == 'parent_order': # kwargs["queryset"] = Order.objects.filter(child_orders__ordernumber__exact=11234) return db_field.formfield(**kwargs) return super(OrderAdmin, self).formfield_for_foreignkey(db_field, request, **kwargs) 

注释行在Python shell中运行时工作,返回包含#11234的订单#11208的单个项目查询集以及可能已经从中拆分的所有其他订单。

当然,我们不能在那里硬编码订单号。 我们需要对订单实例的ordernumber字段的引用,该实例的详细信息页面正在查看。 喜欢这个:

 kwargs["queryset"] = Order.objects.filter(child_orders__ordernumber__exact=?????) 

我发现没有工作方式来取代????? 参考“当前”订单实例,我挖得很深。 self内部formfield_for_foreignkey是指ModelAdmin实例,虽然它确实有一个model属性,它不是顺序模型实例(它是一个ModelBase引用; self.model()返回一个实例,但它的顺序号是无)。

一个解决scheme可能是从request.path(/ admin / orders / order / 11234 /)中提取订单号,但这真的很难看。 我真的希望有更好的办法。

我想你可能需要以一种稍微不同的方式来解决这个问题 – 通过修改ModelForm而不是admin类。 像这样的东西:

 class OrderForm(forms.ModelForm): def __init__(self, *args, **kwargs): super(OrderForm, self).__init__(*args, **kwargs) self.fields['parent_order'].queryset = Order.objects.filter( child_orders__ordernumber__exact=self.instance.pk) class OrderAdmin(admin.ModelAdmin): form = OrderForm 

我用这种方法模拟了我的内联类。 它是如何得到父窗体id来过滤内联数据有点难看,但它的工作原理。 它从父窗体按公司过滤单元。

原来的概念在这里解释http://www.stereoplex.com/blog/filtering-dropdown-lists-in-the-django-admin

 class CompanyOccupationInline(admin.TabularInline): model = Occupation # max_num = 1 extra = 0 can_delete = False formset = RequiredInlineFormSet def formfield_for_dbfield(self, field, **kwargs): if field.name == 'unit': parent_company = self.get_object(kwargs['request'], Company) units = Unit.objects.filter(company=parent_company) return forms.ModelChoiceField(queryset=units) return super(CompanyOccupationInline, self).formfield_for_dbfield(field, **kwargs) def get_object(self, request, model): object_id = request.META['PATH_INFO'].strip('/').split('/')[-1] try: object_id = int(object_id) except ValueError: return None return model.objects.get(pk=object_id) 

Erwin Julius的上述答案为我工作,除了我发现名称“get_object”与Django函数冲突,所以命名函数“my_get_object”。

 class CompanyOccupationInline(admin.TabularInline): model = Occupation # max_num = 1 extra = 0 can_delete = False formset = RequiredInlineFormSet def formfield_for_dbfield(self, field, **kwargs): if field.name == 'unit': parent_company = self.my_get_object(kwargs['request'], Company) units = Unit.objects.filter(company=parent_company) return forms.ModelChoiceField(queryset=units) return super(CompanyOccupationInline, self).formfield_for_dbfield(field, **kwargs) def my_get_object(self, request, model): object_id = request.META['PATH_INFO'].strip('/').split('/')[-1] try: object_id = int(object_id) except ValueError: return None return model.objects.get(pk=object_id) 

它告诉我不要“回复”别人的答案,但是我不允许“回答”,而且我一直在寻找这个东西,所以希望这会对别人有所帮助。 我也不允许upvote或我完全会!