Django: accessing a model instance from ModelAdmin?

I have a model for Orders in an application for a web store with an automatically increasing primary key and a foreign key for myself, since orders can be divided into several orders, but communication with the original order must be supported.

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 

I registered the OrderAdmin class for the admin site. For a detailed view, I have included parent_order in the fieldsets attribute. Of course, by default, all orders are listed on this list, but this is not the desired behavior. Instead, for orders that do not have a parent order (i.e., were not separated from another order, parent_order is NULL / None), no orders should be displayed. For orders that have been split, this should only display one parent order.

A fairly new ModelAdmin method, formfield_for_foreignkey, is formfield_for_foreignkey , which seems ideal for this, since the request can be filtered out in it. Imagine that we are looking at the detailed view of order No. 11234, which was divided into order # 11208. The code below

 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) 

The commented line works when launched in the Python shell, returning a single-item selection request containing the order # 11208 for # 11234 and all other orders that can be divided into it.

Of course, we cannot hard code the order number. We need a link to the ordernumber field of the ordernumber instance whose detailed page we are looking at. Like this:

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

I did not find a replacement job with reference to the "current" instance of the order, and I dug quite deeply. self inside formfield_for_foreignkey refers to an instance of ModelAdmin, and although it has a model attribute, it is not an instance of the order model (this is a ModelBase reference; self.model () returns an instance, but its serial number is None).

One solution might be to pull the order number from request.path (/ admin / orders / order / 11234 /), but it is really ugly. I am very sorry that there is a better way.

+37
django django-admin modeladmin
Jun 04 '09 at 8:32
source share
3 answers

I think you might have to approach this a bit differently - by changing ModelForm, not the admin class. Something like that:

 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 
+54
Jun 04 '09 at 8:37
source share
β€” -

I modeled my inline class this way. It's a bit ugly about how it gets the parent form id to filter inline data, but it works. It filters the devices by the company from the parent form.

The original concept is explained here 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) 
+5
Apr 03 2018-12-12T00:
source share

The above answer from Erwin Julius worked for me, but I found that the name "get_object" conflicts with the Django function, so name the function "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) 

He told me not to β€œrespond” to the answers of others, but I have not yet been allowed to β€œanswer”, and I have been looking for this for some time, so I hope that it will be useful for others. I am also not allowed to move forward, otherwise I would be completely!

+3
Oct 29 '13 at 21:21
source share



All Articles