2009-02-03 16 views
55

Mi piacerebbe utilizzare una vista che ho creato nel mio database come sorgente per la mia vista django.Posso utilizzare una vista del database come modello in Django?

È possibile, senza utilizzare sql personalizzato?

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

Come molte delle risposte suggeriscono, si può solo fare il vostro punto di vista nel database e quindi utilizzalo all'interno dell'API definendolo in models.py.

qualche avvertimento però:

  • syncdb manage.py non funzionerà più
  • la vista hanno bisogno della stessa cosa all'inizio del suo nome come tutti gli altri modelli (tabelle), ad esempio se la vostra applicazione è chiamato "cosa", allora la vostra vista dovrà essere chiamato thing_ $ viewname
+0

Per il comando syncdb, non inserire la classe del modello per la vista in models.py ma in un file separato! –

+2

Migliore: vedere la risposta seguente su managed = False nella classe Meta sul modello. –

+3

Alla vista non è necessario avere lo stesso nome dell'app. Basta usare il campo Meta db_table. Ad esempio, visualizza named its_a_View. class Meta: db_table = u'its_a_view ' – grantk

risposta

33

Dal Django 1.1, è possibile utilizzare Options.managed per questo.

Per le versioni precedenti, è possibile definire facilmente una classe Modello per una vista e utilizzarla come le altre visualizzazioni. L'ho appena testato usando un'app basata su Sqlite e sembra funzionare bene. Assicurati di aggiungere un campo chiave primaria se la colonna "chiave primaria" della tua vista non è denominata "id" e specifica il nome della vista nelle opzioni Meta se la tua vista non è denominata "nome_cassa app".

L'unico problema è che il comando "syncdb" solleverà un'eccezione poiché Django proverà a creare la tabella. Puoi evitarlo definendo i 'modelli di vista' in un file Python separato, diverso da models.py. In questo modo, Django non li vedrà quando introspecting models.py per determinare i modelli da creare per l'app e quindi non tenterà di creare la tabella.

+0

Qualche idea su come gestire il metodo di salvataggio su di esso? Alcuni dbms hanno viste aggiornabili. –

+0

Non sono sicuro. Probabilmente Django tenta semplicemente di eseguire una query INSERT o UPDATE sulla vista, ma non ho troppe informazioni sul codice sorgente di Django :-) –

+13

* Sigh *. ** Non c'è bisogno di downvotes, gente! ** Questa è una risposta antica a una domanda antica. Nel febbraio 2009, non c'era ancora 'Options.managed', che è apparso in Django 1.1 il 29 luglio 2009 ... –

3

Abbiamo fatto abbastanza estesamente nelle nostre applicazioni con MySQL per aggirare il limite del database singolo di Django. La nostra applicazione ha un paio di database che vivono in una singola istanza MySQL. Possiamo ottenere un modello di database incrociato in questo modo, purché abbiamo creato visualizzazioni per ogni tabella nel database "corrente".

Per quanto riguarda gli inserti/aggiornamenti nelle viste, con i nostri casi d'uso, una vista è fondamentalmente una "selezione * da [db.table];". In altre parole, non facciamo alcun joins o filtro complesso, quindi il trigger insert/updates da save() funziona correttamente. Se il tuo caso d'uso richiede join così complessi o estesi filtri, sospetto che non avrai problemi con gli scenari di sola lettura, ma potresti incontrare problemi di inserimento/aggiornamento. Penso che ci siano alcuni vincoli sottostanti in MySQL che ti impediscono di aggiornare le viste che attraversano tabelle, hanno filtri complessi, ecc.

In ogni caso, il tuo chilometraggio può variare se stai usando un RDBMS diverso da MySQL, ma Django non lo fa mi interessa davvero se è seduto sopra un tavolo fisico o una vista. Sarà il RDBMS a determinare se funzioni effettivamente come previsto. Come notato in precedenza da un commentatore, è probabile che stiate proiettando syncdb fuori dalla finestra, anche se abbiamo lavorato con successo con un segnale post-syncdb che elimina la tabella fisica creata da Django e lancia il comando "create view ...". Tuttavia, il segnale post-syncdb è un po 'esoterico nel modo in cui viene attivato, per cui anche qui c'è l'emptor.

EDIT: Naturalmente da "segnale post-syncdb" Voglio dire "post-syncdb ascoltatore"

90

Solo un aggiornamento per coloro che si incontrano questa domanda (da Google o qualsiasi altra cosa) ...

Attualmente Django ha una semplice "modo giusto" per define model without managing database tables:

Options.managed

predefiniti per True, il che significa Django creerà le tabelle del database appropriate syncdb e rimuoverli come parte di un comando di gestione reset. Cioè, Django gestisce i cicli di vita delle tabelle del database.

Se False, per questo modello non verranno eseguite operazioni di creazione o cancellazione della tabella del database. Ciò è utile se il modello rappresenta una tabella esistente o una vista del database che è stata creata con altri mezzi. Questa è la differenza solo quando managed è False. Tutti gli altri aspetti della gestione del modello sono esattamente gli stessi del normale.

+2

Per fornire un contesto; questa funzione è disponibile in Django 1.1 verso l'alto. – spence91

+1

Ricorda che eseguirai TransactionErrors quando proverai a eliminare gli oggetti referenziati dagli oggetti nella vista del tuo database da 'models.ForeignKey'. – jnns

+0

Se si utilizza Django 1.3+, è possibile evitare TransactionErrors utilizzando [ForeignKey.on_delete] (https://docs.djangoproject.com/en/dev/ref/models/fields/#django.db.models.ForeignKey. on_delete): 'user = models.ForeignKey (Utente, on_delete = models.DO_NOTHING)' – rhunwicks

2

Da Django Official Documentation, si potrebbe chiamare la vista in questo modo:

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

Speranza che aiuta ;-)

9

Ho appena implementato un modello con una vista con Postgres 9.4 e 1.8 Django.

ho creato classi di migrazione personalizzato come questo:

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

ho scritto il modello come farebbe normalmente. Funziona per i miei scopi.

Nota - Durante l'esecuzione di makemigrations è stato creato un nuovo file di migrazione per il modello, che ho eliminato manualmente.

Full disclosure- la mia vista è di sola lettura perché sto usando una vista derivata da un tipo di dati jsonb e non ho scritto una regola INSERITA AGGIORNAMENTO.

+0

meravigliose informazioni aggiuntive, davvero utili, grazie –

+0

Se non si desidera installare 'sqlparse', è possibile racchiudere gli argomenti in' RunSQL' in '[]'. – Dan