Let’s say I have these models:
class A(models.Model):
name = models.CharField(max_length=32)
b = models.ForeignKey("B", null=True)
def __unicode__(self):
return self.name
class B(models.Model):
name = models.CharField(max_length=32)
def __unicode__(self):
return self.name
And this view:
def DisplayIt(request):
html = ""
for a in A.objects.all():
html += "<input type='text' value='" + a.b.name + "' />"
This works fine as long as every A has a reference to a B in field b. But, I have null=True on the b reference field. When b is None, an exception is thrown that NoneType has no function name, which is completely expected.
Obviously, I can do this:
def DisplayIt(request):
somestring = ""
for a in A.objects.all():
if a.b is not None:
somestring += a.b.name
BUT, I don’t want to do this if I don’t have to. So, is there a way to get b.name or None if b is None, WITHOUT putting an if a.b is not None: in each loop? My real world example is much more complex, and I am creating a temporary object for display out of actual database fields… suffice it to say I’d prefer not to have all of those if statements, and wasn’t sure if there was another built-in function to get there. I could also create a class method to get each of these foreign fields if they exist or blank if they don’t, but I’m not sure this is the best way to go, either.
Make the database do it for you.
Use a cross-relation filter to get all
Awith abwithnamewhich is not null:To do this such that dummy values are included when
a.bis None, use the following:Also, as a side note, don’t do string concatenation that way — it’s horribly inefficient, since Python strings aren’t mutable. The following is much better:
Second side note: The code above will perform a query to fetch a.b on each iteration of the for loop. That can be suuuuper slow. Consider using
select_relatedto grab everything all in one go. Be wary, though – this can be slow too if your indexes aren’t set up correctly. After enabling this I’d sniff the queries and spend some quality time with your query planner to make sure you’re not doing any nasty non-indexed lookups.Revised code: