python - Get list_display in django admin to display the 'many' end of a many-to-one relationship -
i display pet owners (clients) using list_display , each owner comma-separate list of of pets (patients).
the foreign key in patient table, such owner can have many pets, pet can have 1 owner.
i've got following work advise whether acceptable approach.
from .models import client, patient class clientadmin(admin.modeladmin): list_display = ('first_name', 'last_name', 'mobile', 'patients') def patients(self,obj): p = patient.objects.filter(client_id=obj.pk) return list(p)
thanks guidance.
update: here's i'm @ far:
here's i've managed working far
class clientadmin(admin.modeladmin): list_display = ('first_name', 'last_name', 'mobile', 'getpatients') def getpatients(self, request): c = client.objects.get(pk=1) p = c.patient_fk.all() return p
this following docs re: following relationships backwards.
of course, above example 'fixes' number of client objects 1 (pk=1) i'm not sure how i'd results of clients.
@pleasedontbelong - i've tried code, thank much. i'm doing wrong i'm getting error.but know fk has
related_name = 'patient_fk'
which explains why i'm not using patient_set (since foo_set overriden)
so here's have:
class clientadmin(admin.modeladmin): list_display = ('first_name', 'last_name', 'mobile', 'getpatients') def get_queryset(self, request): qs = super(clientadmin, self).get_queryset(request) return qs.prefetch_related('patient_fk') def getpatients(self, obj): return self.patient_fk.all()
the error "'clientadmin' object has no attribute 'patient_fk'" , relates last line of code above.
any ideas?
thanks!
edit
i've tried brian's code:
class clientadmin(admin.modeladmin): list_display = ('first_name', 'last_name', 'mobile', 'getpatients') def getpatients(self, obj): p = obj.patient_pk.all() return list(p)
...and getting error 'client' object has no attribute 'patient_fk'
if run original code, still works ok:
class clientadmin(admin.modeladmin): list_display = ('first_name', 'last_name', 'mobile', 'getpatients') def getpatients(self, obj): p = patient.objects.filter(client_id=obj.pk) return list(p)
for reference, here classes:
class client(timestampedmodel): first_name = models.charfield(max_length=30) last_name = models.charfield(max_length=30) .... class patient(timestampedmodel): client = models.foreignkey(client, on_delete=models.cascade, related_name='patient_fk') name = models.charfield(max_length=30) ....
if works :+1: !!
few notes however: execute 1 query each client, if display 100 clients on admin, django execute 100 queries
you maybe improve changing main queryset (like this) on admin , using prefetch_related('patients')
should like:
class clientadmin(admin.modeladmin): list_display = ('first_name', 'last_name', 'mobile', 'patients') def get_queryset(self, request): qs = super(clientadmin, self).get_queryset(request) return qs.prefetch_related('patients') # read doc, maybe 'patients' not correct lookup def patients(self,obj): return self.patients_set.all() # since have prefetched patients think wont hit database, tested
hope helps
note:
you can patients related client using related object reference, like:
# 1 client client = client.objects.last() # client's patient patients = client.patient_set.all()
the last line similar to:
patients = patient.objects.get(client=client)
finally can override patient_set
name , make prettier, read https://docs.djangoproject.com/en/1.9/topics/db/queries/#following-relationships-backward
i haven't tested it, nice have feedback see if prevent n+1 problem
Comments
Post a Comment