models.py sta diventando enorme, qual è il modo migliore per romperlo?


91

Indicazioni del mio supervisore: "Voglio evitare di inserire alcuna logica in models.py. Da questo momento in poi, usiamola come solo classi per accedere al database e manteniamo tutta la logica nelle classi esterne che utilizzano le classi dei modelli, o le racchiudiamo".

Mi sento come se questa fosse la strada sbagliata. Ritengo che mantenere la logica fuori dai modelli solo per mantenere il file piccolo sia una cattiva idea. Se la logica è la migliore nel modello, è lì che dovrebbe andare a prescindere dalle dimensioni del file.

Quindi esiste un modo semplice per utilizzare solo gli include? In PHP-speak, vorrei proporre al supervisore che abbiamo solo models.pyinclude () le classi del modello da altri luoghi. Concettualmente, ciò consentirebbe ai modelli di avere tutta la logica che desideriamo, mantenendo però la dimensione del file ridotta aumentando il numero di file (il che porta a meno problemi di controllo delle revisioni come conflitti, ecc.).

Quindi, esiste un modo semplice per rimuovere le classi del modello dal file models.py, ma i modelli funzionano ancora con tutti gli strumenti Django? Oppure esiste una soluzione completamente diversa ma elegante al problema generale di un file models.py "grande"? Qualsiasi input sarebbe apprezzato.


7
Conosci la dichiarazione di importazione, giusto?
balpha

7
PS. Non lo dico in modo offensivo, voglio solo sapere dove ti trovi.
balpha

1
Sì, ma non sapevo se gli strumenti di amministrazione di django avrebbero funzionato semplicemente usando le istruzioni di importazione per inserire i modelli. Preferirei chiedere qui piuttosto che passare un sacco di tempo a provare usando semplici importazioni ole solo per scoprire che gli strumenti di django non funzionano bene con loro. Ammetto di essere nuovo di python e django, quindi probabilmente sono solo a una semplice comprensione
dell'istruzione

Risposte:


64

Django è progettato per consentirti di creare molte piccole applicazioni invece di un'unica grande applicazione.

All'interno di ogni grande applicazione ci sono molte piccole applicazioni che lottano per essere libere.

Se ti models.pysenti grande, stai facendo troppo. Fermare. Rilassare. Decomporsi.

Trova componenti o pezzi di piccole applicazioni più piccoli e potenzialmente riutilizzabili. Non è necessario riutilizzarli effettivamente . Pensa a loro come potenzialmente riutilizzabili.

Considera i tuoi percorsi di aggiornamento e decomponi le applicazioni che potresti voler sostituire un giorno. Non è necessario sostituirli effettivamente , ma è possibile considerarli come un "modulo" autonomo di programmazione che potrebbe essere sostituito con qualcosa di più interessante in futuro.

Abbiamo una dozzina di applicazioni, ciascuna model.pynon supera le 400 righe di codice. Sono tutti piuttosto concentrati su meno di una mezza dozzina di definizioni di classi distinte. (Questi non sono limiti rigidi, sono osservazioni sul nostro codice.)

Ci decomponiamo presto e spesso.


1
proprio sul punto. qualsiasi webapp non banale sarebbe diverse piccole "app". dai un suggerimento al contrib e ad altre app popolari, l'autenticazione utente è un'app, la codifica è un'altra, i profili utente ancora uno, ecc.
Javier

4
Anche se questo è il modo "giusto" e utile da sapere, non è proprio quello che stavo cercando. Mi scuso se non c'era modo di sapere che tipo di risposta stavo cercando. :)
Eddified il

@Eddified: se non lo fai, peggiorerà solo. Inizia a dividere adesso.
S.Lott

Abbastanza divertente, in questo preciso momento sto ascoltando Jacob Kaplan Moss (all'OSCON) che spiega esattamente questo con dettagli grandi e fortemente giustificati ;-).
Alex Martelli

13
La risposta di Glenn Maynard è molto meglio su questo. Dividere una webapp complessa in molte app è certamente una buona pratica, ma lo è anche il refactoring di un file model.py ALL'INTERNO di un'app. Le due azioni possono essere ortogonali.
Erik

108

È naturale che le classi del modello contengano metodi per operare sul modello. Se ho un modello Book, con un metodo book.get_noun_count(), è lì che appartiene - non voglio dover scrivere " get_noun_count(book)", a meno che il metodo non appartenga intrinsecamente a qualche altro pacchetto. (Potrebbe, ad esempio, se ho un pacchetto per accedere all'API di Amazon con " get_amazon_product_id(book)".)

Mi sono fatto rabbrividire quando la documentazione di Django ha suggerito di mettere i modelli in un singolo file, e ho impiegato alcuni minuti dall'inizio per capire come dividerlo in un sottopacchetto appropriato.

site/models/__init__.py
site/models/book.py

__init__.py sembra:

from .book import Book

così posso ancora scrivere "from site.models import Book".


Quanto segue è richiesto solo per le versioni precedenti a Django 1.7, vedere https://code.djangoproject.com/ticket/3591

L'unico trucco è che è necessario impostare esplicitamente l'applicazione di ogni modello, a causa di un bug in Django: si presume che il nome dell'applicazione sia la terzultima voce nel percorso del modello. "site.models.Book" risulta in "site", che è corretto; "site.models.book.Book" fa pensare che il nome dell'applicazione sia "modelli". Questo è un trucco piuttosto brutto da parte di Django; probabilmente dovrebbe cercare nell'elenco delle applicazioni installate una corrispondenza di prefisso.

class Book(models.Model):
    class Meta: app_label = "site"

Probabilmente potresti usare una classe base o una metaclasse per generalizzare questo, ma non me ne sono ancora preoccupato.


2
+1 L'ho usato con successo. Sebbene S. Lott abbia ragione sul fatto che più app sia una buona idea, questa è la soluzione qui e ora.
Alexander Ljungberg

35
Non vedo molti vantaggi nel dividere le cose in un gruppo di app, quando i tuoi modelli sono strettamente e intrinsecamente correlati.
Glenn Maynard,

2
Questo mi interessa. Ho letto il collegamento wiki di django scompt pubblicato e ho trovato questo: "Questo è stato verificato per funzionare senza la classe Meta app_labels, nel ramo principale corrente." Quindi questo significa che se stai lavorando con il ramo principale possiamo scartare la roba Meta: app_label? È fonte di confusione poiché è dopo il commento sul ticket per risolvere questo problema.
Dan.StackOverflow

2
Ho appena provato con il tronco (a partire da oggi, r11286); se app_name non è impostato, il modello semplicemente non viene visualizzato in "sqlall appname" e probabilmente non verrà creato da syncdb (ma non lo uso quindi non posso testarlo). È un caso di errore piuttosto confuso, perché non attiva alcun errore; semplicemente silenziosamente non si presenta.
Glenn Maynard

2
Wow, quasi 10 anni dopo e adoro ancora questa soluzione. Concordo sul fatto che sia un approccio molto migliore rispetto alla suddivisione del codice in app più piccole, il che a mio parere può portare a una base di codice su cui è difficile ragionare.
Michael Hays

5

Non riesco a capire quale dei molti possibili problemi potresti avere. Ecco alcune possibilità con le risposte:

  • più modelli nello stesso file

    Mettili in file separati. Se sono presenti dipendenze, utilizzare import per inserire i modelli aggiuntivi.

  • funzioni logiche / di utilità estranee in models.py

    Metti la logica in più in file separati.

  • metodi statici per selezionare alcune istanze del modello dal database

    Crea un nuovo Manager in un file separato.

  • metodi ovviamente legati al modello

    save, __unicode__ e get_absolute_url sono esempi.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.