2009-02-03 26 views
55

me gustaría utilizar una vista que he creado en mi base de datos como fuente para mi django-view.¿Puedo usar una vista de base de datos como modelo en Django?

¿Es esto posible, sin usar sql personalizado?

****** ACTUALIZACIÓN 13/02/09 ***********

Al igual que muchas de las respuestas sugieren, puede simplemente hacer su propio punto de vista en la base de datos y luego Úselo dentro de la API definiéndolo en models.py.

alguna advertencia:

  • syncdb manage.py no funcionará más
  • la vista necesitan lo mismo que al comienzo de su nombre como todos los otros modelos (tablas) por ejemplo, si su aplicación es llamada "thing", su vista necesitará llamarse thing_ $ viewname
+0

Para que el comando syncdb funcione, ¡no coloque su clase de modelo para la vista en models.py sino un archivo separado! –

+2

Mejor: vea la respuesta a continuación sobre managed = False en la clase Meta en su modelo. –

+3

La vista dows no necesita tener el mismo nombre que la aplicación. Solo usa el campo meta db_table. Por ejemplo, vista llamada its_a_View. clase Meta: db_table = u'its_a_view ' – grantk

Respuesta

33

Desde Django 1.1, puede usar Options.managed para eso.

Para versiones anteriores, puede definir fácilmente una clase de modelo para una vista y usarla como sus otras vistas. Acabo de probarlo usando una aplicación basada en Sqlite y parece funcionar bien. Solo asegúrese de agregar un campo de clave principal si la columna de "clave principal" de su vista no se llama 'id' y especifique el nombre de la vista en las opciones Meta si su vista no se llama 'nombre_clase_apl'.

El único problema es que el comando "syncdb" generará una excepción ya que Django intentará crear la tabla. Puede evitar eso definiendo los 'modelos de vista' en un archivo de Python separado, diferente de models.py. De esta forma, Django no los verá cuando introspecta models.py para determinar los modelos a crear para la aplicación y, por lo tanto, no intentará crear la tabla.

+0

¿Alguna idea de cómo manejaría llamar al método guardar en ella? Algunos dbms tienen vistas actualizables. –

+0

No estoy seguro. Lo más probable es que Django simplemente intente ejecutar una consulta INSERT o UPDATE en la vista, pero no tengo mucha información en el código fuente de Django :-) –

+13

* Sigh *. ** ¡No hay necesidad de downvotes, amigos! ** Esta es una antigua respuesta a una antigua pregunta. En febrero de 2009, todavía no había 'Options.managed', que apareció en Django 1.1 el 29 de julio de 2009 ... –

3

Hemos hecho esto extensamente en nuestras aplicaciones con MySQL para evitar la limitación de la base de datos única de Django. Nuestra aplicación tiene un par de bases de datos que viven en una sola instancia de MySQL. Podemos lograr combinaciones de modelos de bases de datos cruzadas de esta manera siempre que hayamos creado vistas para cada tabla en la base de datos "actual".

En cuanto a las inserciones/actualizaciones en las vistas, con nuestros casos de uso, una vista es básicamente un "select * from [db.table];". En otras palabras, no realizamos ninguna combinación compleja ni filtro, así que insertar/actualizar el desencadenador de save() funciona muy bien. Si su caso de uso requiere combinaciones tan complejas o un filtrado extenso, sospecho que no tendrá ningún problema para los escenarios de solo lectura, pero puede encontrarse con problemas de inserción/actualización. Creo que hay algunas restricciones subyacentes en MySQL que le impiden actualizar en vistas que cruzan tablas, tienen filtros complejos, etc.

De todos modos, su kilometraje puede variar si está utilizando un RDBMS que no sea MySQL, pero Django doesn ' realmente me importa si está sentado encima de una mesa o vista física. Será el RDBMS el que determine si realmente funciona como esperabas. Como señaló un comentador anterior, probablemente lanzará syncdb por la ventana, aunque lo solucionamos con una señal post-syncdb que elimina la tabla física creada por Django y ejecuta nuestro comando "create view ...". Sin embargo, la señal post-syncdb es un poco esotérica en la forma en que se desencadena, por lo que también debes tener precaución.

EDIT: Por supuesto, por "señal post-syncdb" quiero decir "escucha post-syncdb"

90

Apenas una actualización para los que se les presente esta cuestión (de Google o cualquier otra cosa) ...

Actualmente Django tiene un simple "forma correcta" para define model without managing database tables:

Options.managed

predeterminados a True, es decir, Django creará las tablas de bases de datos apropiadas en syncdb y eliminarlos como parte de un comando de administración reset. Es decir, Django gestiona los ciclos de vida de las tablas de la base de datos.

Si False, no se realizarán operaciones de creación o eliminación de tablas de base de datos para este modelo. Esto es útil si el modelo representa una tabla existente o una vista de base de datos que ha sido creada por algún otro medio. Esta es la única diferencia cuando managed es False. Todos los demás aspectos del manejo del modelo son exactamente los mismos que los normales.

+2

Para proporcionar un contexto; esta característica está disponible en Django 1.1 en adelante. – spence91

+1

Tenga en cuenta que ejecutará TransactionErrors cuando intente eliminar objetos a los que los objetos hacen referencia en su vista de base de datos con 'models.ForeignKey'. – jnns

+0

Si está utilizando Django 1.3+, puede evitar TransactionErrors utilizando [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

De Django Official Documentation, se podría llamar la vista como esta:

#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() 

espero que ayude ;-)

9

simplemente he implementado un modelo que utiliza una vista con Postgres 9.4 y Django 1.8.

creé clases de migración personalizados como este:

# -*- 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) 
    ] 

escribí el modelo como lo haría normalmente. Funciona para mis propósitos.

Nota - Cuando ejecuté makemigrations, se creó un nuevo archivo de migración para el modelo, que eliminé manualmente.

Divulgación completa: mi vista es de solo lectura porque estoy usando una vista derivada de un tipo de datos jsonb y no he escrito una regla ON UPDATE INSTEAD.

+0

maravillosa información adicional, realmente útil, gracias –

+0

Si no desea instalar 'sqlparse', puede ajustar los argumentos a' RunSQL' en '[]'. – Dan

Cuestiones relacionadas