How do I populate related Django models when using custom SQL in a custom manager?
I have some things I need to use custom SQL for. Just to start, I don't want to get into the discussion of why we're using custom SQL. That's old and irrelevant here.
Anyway, with this custom SQL, I'm populating the model and attempting to populate a related/sub model. That all seems to go fine, until that related model is accessed within a view or template. If I do that, django initiates another SQL query, which is totally unnecess开发者_如何学JAVAary as I already got that data out with the first query.
Here are example, trimmed up models:
class Preferredname(models.Model):
preferredname_id = models.CharField(primary_key=True, max_length=1)
name = models.CharField(max_length=255)
class PersonCustom(models.Manager):
def getSpecial(self):
from django.db import connection, transaction
curse = DictCursor(connection.cursor())
curse.execute("SELECT * FROM person WHERE special = 't'")
result_list = []
for row in curse.fetchall():
i = self.model(
firstname = row['firstname'],
middlename = row['middlename'],
nickname = row['nickname'],
lastname = row['lastname'],
suffix = row['suffix'],
)
i.preferredname = Preferredname()
i.preferredname.preferredname_id = row['preferredname_id']
result_list.append(i)
return result_list
class Person(models.Model):
person_id = models.IntegerField(primary_key=True)
firstname = models.CharField(max_length=255, blank=True)
middlename = models.CharField(max_length=255, blank=True)
lastname = models.CharField(max_length=255, blank=True)
nickname = models.CharField(max_length=255, blank=True)
suffix = models.CharField(max_length=255, blank=True)
preferredname = models.ForeignKey(Preferredname)
objects = PersonCustom()
def get_preferred_name(self):
try:
if self.preferredname.preferredname_id == 'N':
pref = self.nickname
elif self.preferredname.preferredname_id == 'M':
pref = self.middlename
else:
pref = self.firstname
except ObjectDoesNotExist:
if self._preferred_name == 'N':
pref = self.nickname
elif self._preferred_name == 'M':
pref = self.middlename
else:
pref = self.firstname
name = "%s %s %s" % (pref, self.lastname, self.suffix)
return name.strip()
def set_preferred_name(self, val):
self._preferred_name = val
preferred_name = property(get_preferred_name, set_preferred_name)
As an example:
>>> p = Person.objects.getSpecial()
>>> p[0].preferred_name
Since the get_preferred_name() method accesses self.preferredname.preferredname_id(which in theory, should already be populated) it makes another query for preferredname.
Am I off base here, or should this work as I intend? If I'm off here, is there a way to populate related models from within a custom manager?
Rather than assigning your object to i.preferredname
, try setting it to i._preferredname_cache
, which is the internal object Django uses to cache foreign key lookups. That should work.
精彩评论