Reputation: 6553
I am using getattr to access properties of a model dynamically like so (Assuming the Student model has a property called name):
students = Student.objects.all()
property = 'name'
for student in students:
print getattr(student, property)
This works fine, however I'm wondering if it is possible to access a property of a related record in the same way, for example (Assuming each Student has a related Group with a property called title):
students = Student.objects.selected_related()
property = 'group.title'
for student in students:
print getattr(student, property)
With this, I just get the error 'Student has no attribute group.title'
Is there anyway to achieve this?
Any advice appreciated.
Thanks
Upvotes: 2
Views: 1922
Reputation: 23281
you can always use from functools import reduce
and procced like this:
reduce(getattr, "some.nested.property".split("."), student)
Upvotes: 2
Reputation: 6968
While the following code will do what you asked:
students = Student.objects.all()
attr_chain = "group.title".split(".")
for student in students:
item = student
for attr in attr_chain:
item = getattr(item, attr)
print "%s is in the group %s" % (student, item)
Depending on your needs I would suggest that you look into Django's values_list
function on the Queryset class, it can shorten and simplify code in many cases.
name_attr = "name"
#If you look in the documentation you will see why I use "__" here
group_title_attr = "group__title"
for student_name, group_title in Student.objects.all().values_list(name_attr, group_title_attr):
print "%s is in the group %s" % (student_name, group_title)
The relevant docs are here and here.
Upvotes: 7
Reputation: 22841
Unless every object in select_related has a property called 'title', that's going to blow up. What does select_related bring back for a Student model? I'm guessing it's more than just a Group object. You'd need to wrap this in a try/ except block or test the object to see if it is of the same type as Group (e.g., isinstance(x, Group)).
What are you actually trying to achieve? This seems a little tortured. Also, I would suggest a re-labelling to make things clearer:
for obj in student_related:
# print type(obj)
print getattr(obj, property)
You're not actually getting Student objects in that list.
Upvotes: 0
Reputation: 28637
looks like you are looking for
getattr(getattr(student, property), subproperty)
you may be able to do with by looping over property.split('.')
Upvotes: 3