web-dev-qa-db-fra.com

models.py devient énorme, quelle est la meilleure façon de le casser?

Instructions de mon superviseur: "Je veux éviter de mettre toute logique dans le models.py. À partir de maintenant, utilisons-le comme seules classes pour accéder à la base de données, et conservons toute la logique dans les classes externes qui utilisent les classes modèles, ou encapsulons-les. "

J'ai l'impression que c'est la mauvaise façon de procéder. Je pense que garder la logique hors des modèles juste pour garder le fichier petit est une mauvaise idée. Si la logique est la meilleure dans le modèle, c'est là qu'elle devrait vraiment aller, quelle que soit la taille du fichier.

Existe-t-il un moyen simple d'utiliser uniquement les inclusions? En langage PHP, je voudrais proposer au superviseur que nous venons de models.py include () les classes de modèle d'autres endroits. Conceptuellement, cela permettrait aux modèles d'avoir toute la logique que nous voulons, tout en réduisant la taille des fichiers en augmentant le nombre de fichiers (ce qui conduit à moins de problèmes de contrôle des révisions comme les conflits, etc.).

Donc, existe-t-il un moyen simple de supprimer les classes de modèle du fichier models.py, mais de continuer à faire fonctionner les modèles avec tous les outils Django? Ou, existe-t-il une solution complètement différente mais élégante au problème général d'un "grand" fichier models.py? Toute entrée serait appréciée.

87
Eddified

Django est conçu pour vous permettre de créer de nombreuses petites applications au lieu d'une seule grande application.

Chaque grande application contient de nombreuses petites applications qui ont du mal à être gratuites.

Si ton models.py se sent grand, vous en faites trop. Arrêtez. Se détendre. Décomposer.

Trouvez des composants ou des pièces d'application plus petits et potentiellement réutilisables. Vous n'avez pas à en fait les réutiliser. Il suffit de les considérer comme potentiellement réutilisables.

Considérez vos chemins de mise à niveau et décomposez les applications que vous voudrez peut-être remplacer un jour. Vous n'avez pas à en fait les remplacer, mais vous pouvez les considérer comme un "module" de programmation autonome qui pourrait être remplacé par quelque chose de plus cool à l'avenir.

Nous avons environ une douzaine d'applications, chacune model.py ne représente pas plus de 400 lignes de code. Ils sont tous assez concentrés sur moins d'une demi-douzaine de définitions de classe discrètes. (Ce ne sont pas des limites strictes, ce sont des observations sur notre code.)

Nous nous décomposons tôt et souvent.

63
S.Lott

Il est naturel que les classes de modèle contiennent des méthodes pour fonctionner sur le modèle. Si j'ai un modèle Book, avec une méthode book.get_noun_count(), c'est là qu'il appartient - je ne veux pas avoir à écrire "get_noun_count(book)", à moins que la méthode n'appartienne réellement à un autre paquet. (Cela pourrait - par exemple, si j'ai un package pour accéder à l'API d'Amazon avec "get_Amazon_product_id(book)".)

J'ai grincé des dents lorsque la documentation de Django a suggéré de mettre les modèles dans un seul fichier, et j'ai pris quelques minutes dès le début pour comprendre comment le diviser en un sous-package approprié.

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

__init__.py ressemble à:

from .book import Book

donc je peux toujours écrire "depuis site.models import Book".


Ce qui suit n'est requis que pour les versions antérieures à Django 1.7, voir https://code.djangoproject.com/ticket/3591

La seule astuce est que vous devez définir explicitement l'application de chaque modèle, en raison d'un bogue dans Django: il suppose que le nom de l'application est l'avant-dernière entrée du chemin du modèle. "site.models.Book" donne "site", ce qui est correct; "site.models.book.Book" fait penser que le nom de l'application est "modèles". C'est un hack assez méchant de la part de Django; il devrait probablement rechercher dans la liste des applications installées une correspondance de préfixe.

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

Vous pourriez probablement utiliser une classe de base ou une métaclasse pour généraliser cela, mais je ne m'en suis pas encore soucié.

104
Glenn Maynard

Je n'arrive pas à comprendre lequel des nombreux problèmes possibles vous pourriez avoir. Voici quelques possibilités de réponses:

  • plusieurs modèles dans le même fichier

    Mettez-les dans des fichiers séparés. S'il existe des dépendances, utilisez l'importation pour extraire les modèles supplémentaires.

  • fonctions logiques/utilitaires superflues dans models.py

    Mettez la logique supplémentaire dans des fichiers séparés.

  • méthodes statiques pour sélectionner certaines instances de modèle dans la base de données

    Créez un nouveau Manager dans un fichier séparé.

  • méthodes évidemment liées au modèle

    save, __unicode__ et get_absolute_url sont des exemples.

4
hughdbrown