Diviser views.py en plusieurs fichiers

153

Mon views.pyest devenu trop grand et il est difficile de trouver la bonne vue.

Comment puis-je le diviser en plusieurs fichiers puis l'importer? Cela implique-t-il une perte de vitesse?

Puis-je faire la même chose avec models.py?

Barin
la source
4
J'ai divisé mon grand fichier views.py (7k lignes) pour séparer les fichiers et l'augmentation de la vitesse était significative.
user1261774

Réponses:

190

Dans Django, tout est un module Python (* .py). Vous pouvez créer un dossier de vues avec un __init__.pyintérieur et vous pourrez toujours importer vos vues, car cela implémente également un module Python. Mais un exemple serait mieux.

Votre original views.pypourrait ressembler à ceci:

def view1(arg):
    pass

def view2(arg):
   pass

Avec la structure de dossier / fichier suivante, cela fonctionnera de la même manière:

views/
   __init__.py
   viewsa.py
   viewsb.py

viewsa.py :

def view1(arg):
    pass

viewsb.py :

def view2(arg):
    pass

__init__.py :

from viewsa import view1
from viewsb import view2

L' explication rapide serait: lorsque vous écrivez, from views import view1Python recherchera view1 dans

  1. views.py, ce qui se passe dans le premier cas (d'origine)

  2. views/__init__.py, ce qui se passe dans le second cas. Ici, __init__.pyest capable de fournir la méthode view1 car il l'importe.

Avec ce genre de solution, vous pourriez avoir pas besoin de changer importou urlpatterns argumentsurls.py

Si vous avez de nombreuses méthodes dans chaque nouveau fichier de vue, vous trouverez peut-être utile d'effectuer les importations en cours d' views/__init__.pyutilisation *, comme ceci:

from viewsa import *
from viewsb import *

En fait, je ne connais pas les problèmes de vitesse (mais je doute qu'il y en ait).

Pour les modèles, cela peut être un peu difficile.

Vincent Demeester
la source
2
Pourriez-vous s'il vous plaît ajouter un modèle d'URL qui correspond à view1 ou view2 dans votre exemple? Parce que j'ai des problèmes avec ça ...
Pascal Klein
2
J'ai essayé de faire cela, mais quand je vais importer mes modèles (depuis app.models import MyModel ou depuis models import MyModel) Python se plaint que le modèle n'existe pas.
Chris Miller
Est-ce correct si nous supprimons le views.py dans le répertoire racine?
Roel
6
Cette solution ne fonctionne pas pour moi (même erreur que pour @ChrisMiller Ma solution:. En __init__.py: from myapp.views.viewsa import *. Notez que vous ne pouvez pas avoir un views.py plus (ou du moins il ne sera pas lu @ShiftNTab: erreur pour ne pas trouver votre point de vue dans views.py). J'espère que cela vous aidera!
ThePhi
Qu'en est-il de la convention de dénomination: le nom de fichier doit-il être au singulier ou au pluriel? Par exemple: views.car.pyvsviews.cars.py
guival
21

J'ai dû faire ça avant (pour plus de clarté)

La façon dont j'ai fait cela a été de créer un viewsrépertoire, puis, en cela, de créer un fichier appelé__init__.py

Maintenant, lorsque vous appelez votre urls.py, il vous suffit d'ajouter une autre partie

Par exemple, auparavant, vous avez peut-être appelé: -

url(r'^calendar/(?P<year>\d\d\d\d)/$', 'myproject.calendar.views.year')
url(r'^calendar/(?P<year>\d\d\d\d)/(?P<user>[a-z]+)/$', 'myproject.calendar.views.year_by_user')

Vous pouvez maintenant appeler quelque chose du genre

url(r'^calendar/(?P<year>\d\d\d\d)/$', 'myproject.calendar.views.year.index')
url(r'^calendar/(?P<year>\d\d\d\d)/(?P<user>[a-z]+)/$', 'myproject.calendar.views.year.user')

Ceci, bien sûr, en supposant que vous aviez views/year.pycontenant les fonctions indexet user;)

Mez
la source
10

En gros, vous pouvez mettre votre code, où vous le souhaitez. Assurez-vous simplement de modifier les instructions d'importation en conséquence, par exemple pour les vues dans le urls.py.

Ne pas connaître votre code réel, c'est difficile de suggérer quelque chose de significatif. Peut-être vous pouvez utiliser une sorte de préfixe de nom de fichier, par exemple views_helper.py, views_fancy.py, views_that_are_not_so_often_used.pyou si ...

Une autre option serait de créer un viewsrépertoire avec un __init__.py, où vous importez toutes les sous- vues . Si vous avez besoin d'un grand nombre de fichiers, vous pouvez créer davantage de sous-vues imbriquées au fur et à mesure que vos vues grandissent ...

Miku
la source
8

Juste pour partager, j'ai eu quelques problèmes avec la réponse de Vincent Demeester. Tout va bien sauf dans le fichier init .py, je dois écrire de cette façon:

__init__.py :

from .viewsa import *
from .viewsb import *

De cette façon, je n'ai toujours pas besoin de changer ma importméthode dans urls.py. Je suis sur Python 3.6.1 et Django 1.11.4 .

intoxiqué
la source
5

Réponse simple: oui.

Le mieux est de créer un répertoire appelé views, puis dans votre urls.py faire:

import views
...
url(r'^classroom$', views.school.klass, name="classroom"),
Peter Bengtsson
la source
1

J'ai divisé presque toutes les vues de mes applications dans un dossier de vues (avec un init .py bien sûr). Cependant, je n’importe pas toutes les sous-vues dans le fichier init .py, comme certaines réponses l’ont suggéré. Cela semble fonctionner très bien.

DrBloodmoney
la source
1

Puisque Django s'attend simplement à ce qu'une vue soit un objet appelable, vous pouvez la placer où vous voulez dans votre PYTHONPATH. Ainsi, vous pouvez par exemple simplement créer un nouveau package myapp.views et y placer des vues dans plusieurs modules. Vous devrez naturellement mettre à jour vos urls.py et les autres modules qui référencent ces callables de vue.

Horst Gutmann
la source
1
C'est en fait incorrect - cela peut être fait avec des modèles. Voir: code.djangoproject.com/ticket/4470
Jonathan Berger
1
Ah, bon à savoir, merci :-) J'ai toujours pensé qu'il y avait un peu plus de magie dans les modèles et leur mode de vie dans le package de l'application. Suppression de la ligne sur les modèles dans ma réponse.
Horst Gutmann
Heureux d'avoir pu aider, j'ai réalisé plus tard que ce lien explique en fait comment c'est fait beaucoup mieux avec les modèles: blog.amber.org/2009/01/19
Jonathan Berger
1

J'ai joué avec mettre ceci dans mon init .py:

import os

currPath = os.path.realpath(os.path.dirname(__file__))

dirFiles = []
for root, dirs, files in os.walk(currPath):
    for name in files:
        if name.endswith('.py') and not name.startswith('_'): 
            dirFiles.append(name.strip('.py'))

for f in dirFiles:
    exec("from %s import %s" % (f,f))

Je suis encore nouveau dans Python, donc je suis toujours à la recherche de son effet sur la vitesse / la sécurité / la facilité d'utilisation.

EToS
la source
1

Supposons que si vous avez un fichier nommé: password_generator.pyalors à l'intérieur views.pyajoutez:from password_generator import *

Ensuite, vous pouvez appeler la fonction de ce module à partir de views.py.

Abhay
la source
1

La réponse de Vincent Demeester est superbe! mais pour moi, la réponse du toxicomane a fonctionné comme un charme. J'ai rencontré des difficultés lors de la migration de la base de données. L'erreur indique la ligne où le premier modèle est importé et indique que je ne peux pas reconnaître mon module d'application. J'ai beaucoup cherché mais je n'ai pas trouvé de solution, mais plus tard j'ai importé le modèle comme ceci:

from ..models import ModelName

Ça a marché!!

Bashar
la source