Dividir views.py en varios archivos

153

Mi se views.pyha vuelto demasiado grande y es difícil encontrar la vista correcta.

¿Cómo lo divido en varios archivos y luego lo importo? ¿Implica alguna pérdida de velocidad?

¿Puedo hacer lo mismo con models.py?

barin
fuente
44
Dividí mi archivo grande (7k líneas) views.py para separar los archivos y el aumento en la velocidad fue significativo.
user1261774

Respuestas:

190

En Django todo es un módulo de Python (* .py). Puede crear una carpeta de vista con un __init__.pyinterior y aún podrá importar sus vistas, porque esto también implementa un módulo Python. Pero un ejemplo sería mejor.

Su original views.pypodría verse así:

def view1(arg):
    pass

def view2(arg):
   pass

Con la siguiente estructura de carpetas / archivos funcionará igual:

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

La explicación rápida sería: cuando escriba from views import view1Python buscará view1 en

  1. views.py, que es lo que sucede en el primer caso (original)

  2. views/__init__.py, que es lo que sucede en el segundo caso. Aquí, __init__.pypuede proporcionar el método view1 porque lo importa.

Con este tipo de solución, es posible que tenga ninguna necesidad de cambiar importo de urlpatternlas alegaciones deurls.py

Si tiene muchos métodos en cada nuevo archivo de vista, puede resultarle útil hacer las importaciones en views/__init__.pyuso *, de esta manera:

from viewsa import *
from viewsb import *

En realidad no sé sobre problemas de velocidad (pero dudo que haya alguno).

Para los modelos puede ser un poco difícil.

Vincent Demeester
fuente
2
¿Podría agregar un patrón de URL que coincida con view1 o view2 en su ejemplo? Porque tengo problemas con eso ...
Pascal Klein
2
Intenté hacer esto, pero cuando voy a importar mis modelos (desde app.models import MyModel o desde models import MyModel) Python se queja de que el modelo no existe.
Chris Miller
¿Está bien si eliminamos el archivo views.py en el directorio raíz?
Roel
66
Esta solución no funciona para mí (el mismo error que para @ChrisMiller. Mi solución: en __init__.py:. from myapp.views.viewsa import *Tenga en cuenta que ya no puede tener views.py (o al menos no se leerá @ShiftNTab: Error por no . búsqueda de sus puntos de vista en views.py) espero que ayude!
ThePhi
¿Qué pasa con la convención de nomenclatura: el nombre del archivo debe ser singular o plural? Por ejemplo: views.car.pyvsviews.cars.py
Guival
21

He tenido que hacer esto antes (por razones de claridad)

La forma en que hice esto fue crear un viewsdirectorio, luego, en eso, crear un archivo llamado__init__.py

Ahora, cuando está llamando a su urls.py, simplemente necesita agregar otra parte

Por ejemplo, anteriormente, puede haber llamado: -

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')

Ahora puede llamar a algo en la línea de

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')

Esto es, por supuesto, suponiendo que tenía que views/year.pycontener las funciones indexy user;)

Mez
fuente
10

Básicamente, puede poner su código, donde lo desee. Solo asegúrese de cambiar las declaraciones de importación en consecuencia, por ejemplo, para las vistas en el urls.py.

Sin conocer su código real, es difícil sugerir algo significativo. Tal vez se puede utilizar algún tipo de prefijo del nombre, por ejemplo views_helper.py, views_fancy.py, views_that_are_not_so_often_used.pyo algo así ...

Otra opción sería crear un viewsdirectorio con un __init__.py, donde importe todas las subvistas . Si necesita una gran cantidad de archivos, puede crear más subvistas anidadas a medida que crecen sus vistas ...

miku
fuente
8

Solo por compartir, tuve algunos problemas con la respuesta de Vincent Demeester. Todo está bien, excepto en el archivo init .py, tengo que escribir de esta manera:

__init__.py :

from .viewsa import *
from .viewsb import *

De esta manera, todavía no necesito cambiar mi importmétodo en urls.py. Estoy en Python 3.6.1 y Django 1.11.4 .

fanático
fuente
5

Respuesta simple: sí.

Lo mejor es hacer un directorio llamado vistas y luego en su urls.py hacer:

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

Dividí casi todas las vistas en mis aplicaciones en una carpeta de vistas (con un init .py, por supuesto). Sin embargo, no importo todas las subvistas en init .py como algunas de las respuestas han sugerido. Parece funcionar bien.

DrBloodmoney
fuente
1

Dado que Django solo espera que una vista sea un objeto invocable, puede colocarlo donde desee en su PYTHONPATH. Entonces, por ejemplo, podría hacer un nuevo paquete myapp.views y colocar vistas en múltiples módulos allí. Naturalmente, tendrá que actualizar su urls.py y otros módulos que hacen referencia a estas vistas invocables.

Horst Gutmann
fuente
1
Esto es realmente incorrecto, se puede hacer con modelos. Ver: code.djangoproject.com/ticket/4470
Jonathan Berger
1
Ah, es bueno saberlo, gracias :-) Siempre pensé que había un poco más de magia involucrada con los modelos y cómo viven en el paquete de la aplicación. Se eliminó la línea sobre modelos en mi respuesta.
Horst Gutmann el
Me alegro de poder ayudar, más tarde me di cuenta de que este enlace realmente explica cómo se hace con los modelos mucho mejor: blog.amber.org/2009/01/19/…
Jonathan Berger
1

He estado jugando con poner esto en mi 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))

Todavía soy nuevo en Python, así que todavía estoy viendo qué efecto tiene en la velocidad / seguridad / facilidad de uso.

EToS
fuente
1

Supongamos que si tiene un archivo llamado: password_generator.pyluego views.pyagregue:from password_generator import *

Entonces puede llamar a la función de ese módulo desde views.py.

Abhay
fuente
1

¡La respuesta de Vincent Demeester es excelente! pero para mí la respuesta de los adictos funcionó de maravilla. Enfrenté dificultades en la migración de la base de datos. El error indica la línea donde se importa el primer modelo y dice que no se pudo reconocer el módulo de mi aplicación. Busqué mucho pero no pude encontrar una solución, pero luego importé el modelo así:

from ..models import ModelName

¡¡Funcionó!!

Bashar
fuente