正确使用django的模型。相关对象的管理器

时间:2015-03-30 11:32:48

标签: django

我需要一个包含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])替换它来获取实例是否聪明,从而允许解析相关字段?

2 个答案:

答案 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