Django: как отобразить результаты необработанного SQL-запроса на экземпляры модели в представлении списка администратора? - PullRequest
4 голосов
/ 31 декабря 2011

Рассмотрим простую модель:

class Item(models.Model):
    name                = models.CharField(...)
    unit_cost           = models.DecimalField(...)
    unit_price          = models.DecimalField(...)

Он имеет следующий класс администратора:

class ItemAdmin(admin.ModelAdmin):
    def queryset(self, request):
        qs = self.model._default_manager.get_query_set()
        qs2 = self.model._default_manager.raw('''
        SELECT
            "stock_item"."id",
            "stock_item"."name",
            "stock_item"."unit_cost",
            "stock_item"."unit_price"
        FROM
            "stock_item"
        ''')
        qs3 = RawQuerySet('''
        SELECT
            "stock_item"."id",
            "stock_item"."name",
            "stock_item"."unit_cost",
            "stock_item"."unit_price"
        FROM
            "stock_item"
        ''', self.model)
        return qs   # WORKS
        return qs2  # DOESN'T WORK
        return qs3  # DOESN'T WORK

Я переопределяю метод queryset (), чтобы контролировать поведение администратораПосмотреть список.Я хочу выполнить необработанный SQL-запрос в queryset (), отобразить результаты обратно в модель элементов перед отправкой их в представление списка.Проблема в том, что при возврате qs2 или qs3 в шаблоне возникает следующая ошибка (без исключения):

Database error
Something's wrong with your database installation. Make sure the appropriate database tables have been created, and make sure the database is readable by the appropriate user.

Помните, что выполнение необработанного запроса в отдельном сценарии работает, например:

items = Item._default_manager.raw('''
    SELECT
        "stock_item"."id",
        "stock_item"."name",
        "stock_item"."unit_cost",
        "stock_item"."unit_price"
    FROM
        "stock_item"
    ''')        

for item in items:
    print item.name, item.unit_price # WORKS!

На самом деле, у меня больше амбиций, чтобы я мог создать своего рода «виртуальную модель», у которой не должно быть соответствующей таблицы базы данных, целью которой является инкапсуляция запросов проекции sql в свой класс администратора.(чтобы модель могла отображаться в виде списка администратора).

Я попробовал другой подход, вообще не используя ItemAdmin, а вместо этого:

class ItemManager(models.Manager):
    def get_query_set(self):
        return Item._default_manager.raw('''
        SELECT
            "stock_item"."id",
            "stock_item"."name",
            "stock_item"."unit_cost",
            "stock_item"."unit_price"
        FROM
            "stock_item"
        ''')

с:

class Item(models.Model):
    objects = ItemManager()
    etc...

Но теперь я получаю исключение шаблона в представлении списка администратора:

Объект 'RawQuerySet' не имеет атрибута 'complex_filter'

Что делать?Спасибо ...

Ответы [ 2 ]

1 голос
/ 31 декабря 2011

Решено.

Самый простой подход состоял в том, чтобы создать представление базы данных в sqlite3 (бэкэнд базы данных, который я использую), а затем добавить нормальную модель с именем, совместимым с представлением.Модель должна иметь набор полей с именами, аналогичными именам полей, возвращаемых представлением.Для моих целей не требуются администраторы или менеджеры.

Просмотр сценария создания базы данных:

CREATE VIEW <view_name> AS SELECT etc...

Просмотр сценария удаления базы данных (запуск в качестве предварительного шага на случай, если вам потребуется заново создать представление):

DROP VIEW <view_name>

Единственное, с чем вам следует быть осторожным при создании представления, это убедиться, что вы установили:

class Meta:
    managed = False
    #ordering = ( '-date', )

, чтобы не создавать таблицу при запуске syncdb.

Еще одна вещь, вам нужно выбрать уникальное поле в вашем представлении в качестве первичного ключа (и отразить это в модели), иначе django будет жаловаться на что-то вроде:

no such column: stock_itemdbview.id

Ура!

0 голосов
/ 31 декабря 2011

Хорошо глядя на src , QuerySet и RawQuerySet - это похожие, но очень разные классы, где QuerySet превосходит RawQuerySet с точки зрения предоставляемой функциональности.

Если я правильно понимаю, последняя ошибка, о которой вы упомянули, понятна, так как RawQuerySet не имеет метода complex_filter, и я предполагаю, что вы в какой-то момент вызываете model.objects.filter, что, как я полагаю, вызывает вышеупомянутое.

Понятно также, как вы можете перебирать RawQuerySet, потому что при отсутствии лучшего термина «базовая модель» по-прежнему представлена ​​в RawQuerySet, как и в QuerySet.

Не будет ли достаточно использовать extra () ?

Я все еще размышляю над тем, вернется ли первая проблема, если / когда я ее найду.

...