我需要一个包含ForeignKey的Amodel自定义管理器。
class AvailableManager(models.Manager):
use_for_related_fields = True
def sample(self):
from django.db import connection
cursor = connection.cursor()
cursor.execute(""" SELECT * FROM anapp_amodel """)
result_list = []
for row in cursor.fetchall():
p = self.model(id=row[0])
result_list.append(p)
return result_list
class Amodel(models.Model):
related_model = models.ForeignKey('AnotherModel', unique=True)
name = models.CharField(max_length=255, blank=True, null=True)
objects = models.Manager()
available = AvailableManager()
def __unicode__(self):
return 'Amodel related to '+unicode(self.related_model)
使用manager时,此实现引发了一个RelatedObjectDoesNotExist异常:
>>> Amodel.available.sample()
Traceback (most recent call last):
File "<console>", line 1, in <module>
File ".../.virtualenvs/venv/lib/python2.7/site-packages/django/db/models/base.py", line 459, in __repr__
u = six.text_type(self)
File ".../anapp/models.py", line 32, in __unicode__
return u'Amodel at '+unicode(self.related_model)
File ".../.virtualenvs/venv/lib/python2.7/site-packages/django/db/models/fields/related.py", line 578, in __get__
"%s has no %s." % (self.field.model.__name__, self.field.name)
RelatedObjectDoesNotExist: Amodel has no related_model.
关于相关字段执行原始sql的正确方法是什么?目标是实现复杂的SQL查询并注释结果。
UPDATE:由于行p = self.model(id=row[0])
而引发RelatedObjectDoesNotExist异常是正常的。用self.model.objects.get(id=row[0])
替换它来获取实例是否聪明,从而允许解析相关字段?
答案 0 :(得分:1)
您的sample
方法仅使用主键实例化模型,而不包含其余行数据:
p = self.model(id=row[0])
因此实例没有related_model_id
字段的值。
至少你应该这样做:
p = self.model(*row)
但你为什么要这样做?创建单独的管理器方法,但用直接数据库查询替换ORM代码 - 然后返回列表而不是查询集 - 这是一个不错的主意并且必然导致意外问题
修改强>
这并不是你如何使用经理方法。 Django已经提供了一种运行SQL查询并返回模型实例的方法:raw
。所以你的方法就变成了:
def sample(self):
return self.raw(""" SELECT * FROM anapp_amodel """)
答案 1 :(得分:0)
而不是:
self.model(id=row[0])
实例化一个只有id self.model.objects.get(id=row[0])
为每个实例执行SELECT请求我宁愿用整行实例化Model,以便我可以继续为每个实例添加注释:
from django.db import connection
class AvailableManager(models.Manager):
use_for_related_fields = True
def sample(self):
cursor = connection.cursor()
cursor.execute(""" SELECT *, 'annotation' FROM ... """)
result_list = []
for row in cursor.fetchall():
annotation = row[-1]
p = self.model(*row[:-1])
p.annotation = annotation
result_list.append(p)
return result_list