2011-11-08 31 views
7

Ho un modello che è sostenuta da una vista di database.Django - Come prevenire banca dati estera creazione vincolo di chiave

class OrgCode(models.Model): 
    org_code    = models.CharField(db_column=u'code',max_length=15) 
    org_description   = models.CharField(max_length=250) 
    org_level_num   = models.IntegerField() 

    class Meta: 
     db_table = u'view_FSS_ORG_PROFILE' 

Ho bisogno di fare riferimento a questo in un altro modello di

class AssessmentLocation(models.Model): 
    name    = models.CharField(max_length=150) 
    org     = models.ForeignKey(OrgCode) 

non posso correre syncdb perché i vincoli di chiave non possono essere creati riferimento a una vista.

u"Foreign key 'FK__main_asse__org__1D114BD1' 
references object 'view_FSS_ORG_PROFILE' 
which is not a user table.", None, 0, -214 
7217900), None) 
Command: 
CREATE TABLE [main_assessmentlocation] (
    [id] int IDENTITY (1, 1) NOT NULL PRIMARY KEY, 
    [name] nvarchar(150) NOT NULL, 
    [org] int NOT NULL REFERENCES [view_FSS_ORG_PROFILE] ([id]), 
) 

La soluzione è quello di prendere la Meta: puntamento db_table alla vista e lasciare db sincronizzazione creare la tabella del OrgCode, poi mettere la Meta: db_table indietro nel dopo syncdb.

C'è un modo per impedire la creazione di vincoli di chiave esterna per alcuni modelli o campi?

Aggiornamento: ho aggiunto un metodo statico al modello relativo che indica che è una vista

class OrgCode(models.Model): 
    org_code    = models.CharField(max_length=15) 
    org_description   = models.CharField(max_length=250) 

    @staticmethod 
    def is_backend_view(): 
     return True 

Poi overrode DatabaseCreation.sql_for_inline_foreign_key_references in creation.py django_mssql:

def sql_for_inline_foreign_key_references(self, field, known_models, style): 
    try: 
     field.rel.to.is_backend_view() 
     return "", False 
    except: 
     return super(DatabaseCreation,self).sql_for_inline_foreign_key_references(field, known_models, style)  

L'SQL generato da syncDB lascia fuori il vincolo:

CREATE TABLE [main_assessmentlocation] (
    [id] int IDENTITY (1, 1) NOT NULL PRIMARY KEY, 
    [name] nvarchar(150) NOT NULL, 
    [org] int, -- NO FK CONSTRAINT ANYMORE -- 
); 

Essa comporta l'hacking django_mssql così ho intenzione di continuare a provare, forse agganciando nel segnale django.db.backends.signals.connection_created funzionerà ...

risposta

10

versione di sviluppo django ha un campo db_constraint per il campo modello ForeignKey - docs.

+0

Grazie! Questo è quello di cui avevo bisogno, ora dovrò aspettare che arrivi in ​​un rilascio e posso rimuovere il mio trucco. –

+1

'db_constraint' può essere tranquillamente utilizzato dalla versione 1.6 –

4

Se si imposta managed=False (Django docs) nel modello di Classe Meta, Django non creerà la tabella quando si esegue syncdb.

class AssessmentLocation(models.Model): 
    name = models.CharField(max_length=150) 
    org = models.ForeignKey(OrgCode) 

    class Meta: 
     managed = False 

Django ha un gancio per provide initial sql data. Possiamo (ab?) Usarlo per fare in modo che Django crei la tabella immediatamente dopo aver eseguito syncdb.

Creare un file myapp/sql/assessmentlocation.sql, contenente l'istruzione CREATE TABLE:

CREATE TABLE [main_assessmentlocation] (
    [id] int IDENTITY (1, 1) NOT NULL PRIMARY KEY, 
    [name] nvarchar(150) NOT NULL, 
    [org] int, -- NO FK CONSTRAINT ANYMORE -- 
); 

Se si dispone di altri modelli con chiavi esterne al modello AssessmentLocation, si possono avere problemi se Django cerca di applicare il vincolo di chiave esterna prima di eseguire lo sql personalizzato per creare la tabella. Altrimenti, penso che questo approccio funzionerà.

+0

Grazie! Ho esaminato questo e funziona. Il modello di oggetto correlato alla vista è parte di un framework che sto costruendo per essere utilizzato da altri sviluppatori. Sto cercando di non allontanarmi dalla creazione del modello syncdb e dai documenti standard di django. –