2009-02-03 1 views
55

Я хочу использовать представление, которое я создал в моей базе данных в качестве источника для своего django-view.Можно ли использовать представление базы данных в качестве модели в Django?

Возможно ли это, без использования пользовательского sql?

****** 13/02/09 UPDATE ***********

Как многие ответы предполагают, что вы можете просто сделать свой собственный вид в базу данных, а затем используйте его в API, определив его в models.py.

некоторые предупреждения, хотя:

  • manage.py SyncDB больше не будет работать
  • мнение нужно то же самое в начале своего имени, как и все остальные модели (таблицы), например, если ваше приложение называемой «вещью», тогда ваше мнение нужно будет называть thing_ $ viewname
+0

Чтобы команда syncdb работала, не ставьте класс модели для представления в models.py, а отдельный файл! –

+2

Лучше: см. Ответ ниже об управляемом = False в классе Meta на вашей модели. –

+3

Представление не должно иметь то же имя, что и приложение. Просто используйте поле Meta db_table. Например, view с именем its_a_View. class Meta: db_table = u'its_a_view ' – grantk

ответ

33

С Django 1.1 вы можете использовать для этого Options.managed.

Для более старых версий вы можете легко определить класс модели для представления и использовать его как другие ваши представления. Я просто протестировал его с помощью приложения на базе Sqlite и, похоже, работает нормально. Просто добавьте поле первичного ключа, если столбец «первичного ключа» вашего представления не назван «id» и укажите имя представления в параметрах Meta, если ваше представление не называется «app_classname».

Единственная проблема заключается в том, что команда «syncdb» вызовет исключение, поскольку Django попытается создать таблицу. Вы можете предотвратить это, указав «модели просмотра» в отдельном файле Python, отличном от models.py. Таким образом, Django не увидит их при интроспекции models.py, чтобы определить модели для создания приложения, и поэтому не будет пытаться создать таблицу.

+0

Любая идея, как это будет обрабатывать вызов метода сохранения на нем? Некоторые dbms имеют обновляемые представления. –

+0

Я не уверен. Скорее всего, Django просто пытается запустить запрос INSERT или UPDATE в представлении, но я не слишком разбираюсь в исходном коде Django :-) –

+13

* Sigh *. ** Нет необходимости в downvotes, люди! ** Это древний ответ на древний вопрос. В феврале 2009 года еще не было 'Options.managed', которое появилось в Django 1.1 29 июля 2009 года ... –

3

Мы сделали это довольно широко в наших приложениях с MySQL для работы с единственным ограничением базы данных Django. Наше приложение имеет пару баз данных, работающих в одном экземпляре MySQL. Мы можем добиться, чтобы модель кросс-базы данных объединялась таким образом, пока мы создали представления для каждой таблицы в «текущей» базе данных.

Что касается вложений/обновлений в представлениях, то в наших прецедентах вид в основном представляет собой «select * from [db.table];». Другими словами, мы не делаем никаких сложных объединений или фильтрации, поэтому триггер insert/updates из save() работает просто отлично. Если ваш случай использования требует таких сложных объединений или расширенной фильтрации, я подозреваю, что у вас не будет проблем с сценариями только для чтения, но может возникнуть проблема с вставкой/обновлением. Я думаю, что в MySQL существуют некоторые основные ограничения, которые препятствуют обновлению представлений, которые пересекают таблицы, имеют сложные фильтры и т. Д.

В любом случае, ваш пробег может отличаться, если вы используете РСУБД, отличную от MySQL, но Django doesn ' t действительно заботится, если он сидит поверх физического стола или вида. Это будет РСУБД, которая определяет, работает ли она на самом деле, как вы ожидаете. Как отметил предыдущий комментатор, вы, скорее всего, выбросите syncdb из окна, хотя мы успешно работали вокруг него с помощью сигнала post-syncdb, который удаляет физическую таблицу, созданную Django, и запускает нашу команду «create view ...». Тем не менее, сигнал post-syncdb немного эзотеричен в том виде, в котором он срабатывает, поэтому также следует предупредить emptor.

EDIT: Конечно, по «пост-SyncDB сигнал» Я имею в виду «пост-SyncDB слушателя»

90

Просто обновление для тех, кто будет сталкиваться на этот вопрос (от Google или любой другой) ...

В настоящее время Django имеет простой "правильный путь" к define model without managing database tables:

Options.managed

значения по умолчанию для True, то есть Django будет создать соответствующие таблицы базы данных в syncdb и удалить их как часть команды управления reset. То есть Django управляет жизненными циклами таблиц базы данных.

Если False, для этой модели не будут созданы операции создания или удаления таблицы базы данных. Это полезно, если модель представляет собой существующую таблицу или представление базы данных, которое было создано другими способами. Это только разница, когда managed is False. Все остальные аспекты обработки модели абсолютно совпадают с нормальными.

+2

Чтобы обеспечить некоторый контекст; эта функция доступна в Django 1.1 вверх. – spence91

+1

Имейте в виду, что вы столкнетесь с TransactionErrors при попытке удалить объекты, на которые ссылаются объекты в представлении базы данных, на 'models.ForeignKey'. – jnns

+0

Если вы используете Django 1.3+, вы можете избежать TransactionErrors, используя [ForeignKey.on_delete] (https://docs.djangoproject.com/en/dev/ref/models/fields/#django.db.models.ForeignKey. on_delete): 'user = models.ForeignKey (User, on_delete = models.DO_NOTHING)' – rhunwicks

2

От Django Official Documentation, вы могли бы назвать мнение так:

#import library 
from django.db import connection 

#Create the cursor 
cursor = connection.cursor() 

#Write the SQL code 
sql_string = 'SELECT * FROM myview' 

#Execute the SQL 
cursor.execute(sql_string) 
result = cursor.fetchall() 

Надеется, что это помогает ;-)

9

Я просто реализовал модель, используя представление с Postgres 9.4 и Джанго 1.8.

Я создал пользовательские классы миграции, как это:

# -*- coding: utf-8 -*- 
from __future__ import unicode_literals 

from django.db import migrations 


class Migration(migrations.Migration): 

    dependencies = [ 
     ('myapp', '0002_previousdependency'), 
    ] 

    sql = """ 
    create VIEW myapp_myview as 
    select your view here 
    """ 

    operations = [ 
     migrations.RunSQL("drop view if exists myapp_myview;"), 
     migrations.RunSQL(sql) 
    ] 

Я написал модель, как я обычно. Это работает для моих целей.

Примечание - Когда я запускал makemigrations, для модели был создан новый файл миграции, который я вручную удалил.

Полное раскрытие - мое представление читается только потому, что я использую представление, полученное из типа данных jsonb, и не написал правило ON UPDATE INSTEAD.

+0

Замечательная дополнительная информация, очень полезно, спасибо –

+0

Если вы не хотите устанавливать 'sqlparse', вы можете обернуть аргументы в' RunSQL' в '[]'. – Dan

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