31

I have a Django app where my main Model has ForeignKey fields to other DB tables.

class Bugs(models.Model):
    bug_id = models.PositiveIntegerField(primary_key=True)
    bug_severity = models.ForeignKey(Bug_severity,null=True)
    priority = models.ForeignKey(Priority,null=True)
    bug_status = models.ForeignKey(Bug_Status,null=True)
    resolution = models.ForeignKey(Resolution,null=True)
    etc...

All of the ForeignKey tables have a unicode function that returns the name that I want displayed in the template.

class Priority(models.Model):
    value = models.CharField(max_length=64)
    sortkey = models.PositiveSmallIntegerField()
    isactive = models.NullBooleanField()
    visibility_value_id = models.SmallIntegerField(null=True,blank=True)

    def __unicode__(self):
        return self.value

In the view, I am running the query as:

    bugs = Bugs.objects.filter(active=True).order_by('priority__sortkey','bug_severity__sortke

In the template, I can iterate through them, and display the ForeignKey value correctly.

{% for bug in bugs %}
   <tr class="bugrow" >
   <td>{{bug.bug_id}}</td>
   <td>{{bug.priority}}</td>
   <td>{{bug.bug_severity}}</td>
   <td>{{bug.bug_status}}</td>
   <td>{{bug.resolution}}</td>

The problem I am having is that I need to manipulate the Bugs data before sending it to the template, so I use the values() method to return a dictionary. When I pass that dictionary to the template it does not show any fields that point to a ForeignKey.

I'm pretty sure that the reason is that the values only returns the actual database value, so it cannot follow the FK.

The question is, how can I manipulate the data sending it to the template, and still follow the ForeignKey?

zoidberg
  • 1,969
  • 4
  • 22
  • 33

1 Answers1

62

I use this method all of the time. You are correct. It only returns the values, so you have to use the "__" notation to get the value from the ForeignKey. For example:

# Get all of the bugs
bugs = Bugs.objects.filter(
    active=True,
).order_by(
    'priority__sortkey',
    'bug_severity__sortkey',
).values(
    'bug_id',
    'priority', # Only the pk (id) of the bug priority FK
    'priority__value', # Equal to bug.priority.value
    'bug_severity',
    'bug_severity__some_value', # Equal to bug.priority.some_value
)

Now, in your template, you do:

{% for bug in bugs %}
    <tr class="bugrow">
        <td>{{ bug.bug_id }}</td>
        <td>{{ bug.priority }}</td>
        <td>{{ bug.priority__value }}</td>
        <td>{{ bug.bug_severity }}</td>
        <td>{{ bug.bug_severity__some_value }}</td>
    </tr>
{% endfor %}

This is covered in the QuerySet.values() documentation, near the bottom:

You can also refer to fields on related models with reverse relations through OneToOneField, ForeignKey and ManyToManyField attributes:

Blog.objects.values('name', 'entry__headline')
[{'name': 'My blog', 'entry__headline': 'An entry'},
 {'name': 'My blog', 'entry__headline': 'Another entry'}, ...]
Michael B
  • 5,148
  • 1
  • 28
  • 32
  • 4
    That worked perfectly. I swear I read that Queryset.values() documentation 10 times trying to figure this out and never read that bottom block about the FK relations. – zoidberg Nov 28 '14 at 08:12
  • 1
    Don't feel bad - I missed that multiple times when I first started. I personally think that should be a featured piece of the documentation, not an afterthought. – Michael B Nov 28 '14 at 08:36
  • Is there any way to return the actual result of `__unicode__`? This solution would be ideal for me, but there are multiple fields that `__unicode__` uses in my model, so just a single `__value` doesn't work. – 17slim Jun 06 '18 at 15:02
  • 1
    @17slim - your specific use case in your question would require another question to be asked, I believe. Overall, `__unicode__` is sometimes a representation of multiple fields in unicode. You would either have to combine the results in the template using the different values or you would need to pass in the QuerySet, and not use `.values()`. – Michael B Jun 06 '18 at 15:21
  • Thanks for your reply! I have asked a new question actually (I've linked to this one from there), but your comment clears things up for me. – 17slim Jun 06 '18 at 15:47
  • @MichaelB what about calling a method in the model of the foreign key. I tried __get_absolute_url in values it didn't work. – yashas123 Jan 08 '19 at 04:14