How do I get the actual object id in a Django admin page (inside formfield_for_foreignkey)?
Solution 1
As far as i know it is not possible to access the current instance through the formfield_for_...
-methods, because they will only be called for a single field instance!
A better point to hook into this logic where you can access the whole instance/form would be get_form
. You can also overwrite a form field's queryset there!
Solution 2
After some digging around, we were able to grab the arguments that get passed to the admin view (after being parsed by django admin's urls.py) and use that (self_pub_id) to grab the object:
class PublicationAdmin(admin.ModelAdmin):
def formfield_for_manytomany(self, db_field, request, **kwargs):
if db_field.name == "authors":
#this line below got the proper primary key for our object of interest
self_pub_id = request.resolver_match.args[0]
#then we did some stuff you don't care about
pub = Publication.objects.get(id=self_pub_id)
kwargs["queryset"] = pub.authors.all()
return super(PublicationAdmin, self).formfield_for_manytomany(db_field, request, **kwargs)
A more elegant solution is to use the accepted answers recomendation and leverage the get_form ModelAdmin member function. Like so:
class ProfileAdmin(admin.ModelAdmin):
my_id_for_formfield = None
def get_form(self, request, obj=None, **kwargs):
if obj:
self.my_id_for_formfield = obj.id
return super(ProfileAdmin, self).get_form(request, obj, **kwargs)
def formfield_for_foreignkey(self, db_field, request, **kwargs):
if db_field.name == "person":
kwargs["queryset"] = Person.objects.filter(profile=self.my_id_for_formfield)
return super(ProfileAdmin, self).formfield_for_foreignkey(db_field, request, **kwargs)
Solution 3
The following code snippet will give you the object id:
request.resolver_match.kwargs['object_id']
Sample usage: (I'm filtering the phone numbers shown, to only show customer's phone numbers)
def formfield_for_foreignkey(self, db_field, request, **kwargs):
if db_field.name == 'preferred_contact_number':
kwargs['queryset'] = CustomerPhone.objects.filter(customer__pk=request.resolver_match.kwargs['object_id'])
return super().formfield_for_foreignkey(db_field, request, **kwargs)
P.S: Found it by debugging and walking through accessible variables.
Solution 4
I made it work by rewrite change_view()
class CartAdmin(admin.ModelAdmin):
def change_view(self, request, object_id, form_url='', extra_context=None):
self.object_id = object_id
return self.changeform_view(request, object_id, form_url, extra_context)
def formfield_for_foreignkey(self, db_field, request, **kwargs):
print self.object_id
return super(CartAdmin, self).formfield_for_foreignkey(db_field, request, **kwargs)
then you can call self.object_id
inside formfield_for_foreignkey()
Jayme Tosi Neto
I'm a developer focused on Python and learning everyday as many related technologies as possible since advanced algorithms to techniques on how to handle a hoe or a pickaxe. Yes, I have both at home. ;) I've been working with web development last years, but also have interest in database administration, data science - my major - and software quality/tests automation. Well, if you want more details. I'll be glad to answer - and make this profile more complete. Thanks in advance
Updated on July 12, 2022Comments
-
Jayme Tosi Neto almost 2 years
I 've already solved the problem of getting the object id being edited using this code:
class CompanyUserInline(admin.StackedInline): """ Defines tabular rules for editing company users direct in company admin """ model = CompanyUser def formfield_for_foreignkey(self, db_field, request, **kwargs): if db_field.name == "user": users = User.objects.filter( Q(is_superuser=False) ) query = Q() for u in users: aux = CompanyUser.objects.filter(user=u) if aux.count() == 0: query |= Q(pk=u.id) try: cpu = CompanyUser.objects.filter(company__id=int(request.path.split('/')[4])) for p in cpu: query |= Q(pk=p.user.id) except: pass kwargs["queryset"] = User.objects.filter(query).order_by('username') return super(CompanyUserInline, self).formfield_for_foreignkey(db_field, request, **kwargs)
But, the int(request.path.split('/')[4]) is really ugly. I want to know how I get the id from the Django AdminModel. I'm sure it's somewhere inside it, anyone knows?
Thank you in advance! ;D