user1261774
user1261774

Reputation: 3695

Newbie 1st atempt at prefetch_related - returns blank

I asked this question before, but I received no solutions, so I have tried to make the question concise & clearer this time.

My database has the following simplified schema:

class RIAchievement(models.Model):
  riAchievementID = models.AutoField(primary_key=True, db_column="riAchievementID")
  userLanguageVersionID = models.ForeignKey(UserLanguageVersion, db_column="userLanguageVersionID", related_name="riAchievement_userLanguageVersionID")
  class Meta:
    db_table="riAchievement"

class UserLanguageVersion(models.Model):
  userLanguageVersionID = models.AutoField(primary_key=True, db_column="userLanguageVersionID")
  languageCodeID = models.ForeignKey(LanguageCode, db_column="languageCodeID", related_name="userLanguageVersion_languageCodeID")
  class Meta:
    db_table="userLanguageVersion"

class LanguageCode(models.Model):
  languagecodeID = models.AutoField(primary_key=True, db_column="languageCodeID")
  class Meta:
    db_table="languageCode"

class Flag(models.Model):
  flagID = models.AutoField(primary_key=True, db_column="flagID")
  languageCodeID = models.ForeignKey(LanguageCode, db_column="languageCodeID", related_name="flag_languageCodeID")
  flagIconPath = models.CharField(max_length=255, db_column="flagIconPath")
  class Meta:
    db_table="flag"

Essentially, riachievement can have many userlanguageversion s and userlanguageversion can have many languagecode s, and flag can have many languagecode s.

Using select_related does not return flag.flagIconPath because of the 1 to many relationship, so the Django docs state I must use prefetch_related, with the related name of the 1 to many foreign key.

So I amend my code in my view.py:

from django.shortcuts import render
from app_data.models import RIAchievement

def ri_achievements(request):

  qs = RIAchievement.objects.select_related("riachievement", "userlanguageversion", "languagecode", "flag_languageCodeID").all()

  return render(request, 'index.html',{'qs': qs})

And my index.html:

{% for ri_achievement in qs %}
  {{ ri_achievement.userLanguageVersionID.langaugeCodeID.flag_languageCodeID.flagIconPath }}
{% endfor %}

But, this code returns nothing.

Can anyone offer some advice, as I cannot see what I have done wrong?

Upvotes: 0

Views: 357

Answers (1)

I suggest you use the django shell python manage.py shell to figure out your query - it's going to be very difficult to "figure it out" via the template as it supresses errors.

For example, it looks like you have a spelling error, but the template wouldn't complain about it.

Let's break down your attempted query into python so that we can use comments

flagIconPath = (ri_achievement
    .userLanguageVersionID # correct. direct FK 
    .langaugeCodeID # spelling error. but otherwise ok. direct FK
    # this is now a one to many relationship - you now have a related manager
    # NOT a single object. Many flags to one Code
    .flag_languageCodeID
    .latest('id') # you must pick which one you want - for example, the latest ID
    .flagIconPath)

As for making this query more efficient, your select related call would need to include the full paths through these models. You are passing attributes as if they are all foreign keys on the original model.

qs = RIAchievement.objects.select_related('userLanguageVersionID__languageCodeID')

I'm unsure of the prefetch call at this point but it should probably look something like

qs.prefetch_related('userLanguageVersionID__languageCodeID__flag_languageCodeID')

With all of these nested calls, a prefetch that far could.. make a gigantic query. Are you sure this is what you want?

Upvotes: 2

Related Questions