2015-03-30 2 views
1

Мне нужен пользовательский менеджер для Amodel, содержащий ForeignKey.Правильное использование моделей django.Manager для связанных объектов

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) 

Этой реализация поднимает 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: Это нормально, что исключение RelatedObjectDoesNotExist возникает из-за строки p = self.model(id=row[0]). Было бы разумно заменить его на self.model.objects.get(id=row[0]), чтобы получить экземпляр, что позволило разрешить смежные поля?

ответ

0

Вместо:

  • self.model(id=row[0]), который создает модель с идентификатором только
  • или self.model.objects.get(id=row[0]), который выполняет SELECT, запрос для каждого экземпляра

I 'd скорее создайте модель со всей строкой, чтобы я мог приступить к аннотации каждого экземпляра:

class AvailableManager(models.Manager): 
    use_for_related_fields = True 

    def sample(self): 
     from django.db import connection 
     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 
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 """) 
+0

Спасибо, Дэниэл, только что понял это. Пример кода (в частности, «" SELECT * FROM ... "" ") предназначен для иллюстративных целей. Мой вариант использования включает тяжелый SQL-запрос здесь и некоторые аннотации. Разве это не цель заказных менеджеров моделей? –

+0

Список «идея» происходит отсюда: https://docs.djangoproject.com/en/1.7/topics/db/managers/#adding-extra-manager-methods –

+0

re. ваше редактирование, как можно добавить аннотации? –

Смежные вопросы