python - para - Eficaz paginación y consulta de bases de datos en django
include django (3)
Hubo algunos ejemplos de código para la paginación django que utilicé hace un tiempo. Puede que esté equivocado, pero al revisar el código parece que desperdicia toneladas de memoria. Estaba buscando una mejor solución, aquí está el código:
# in views.py
from django.core.paginator import Paginator, EmptyPage, PageNotAnInteger
...
...
def someView():
models = Model.objects.order_by(''-timestamp'')
paginator = Paginator(models, 7)
pageNumber = request.GET.get(''page'')
try:
paginatedPage = paginator.page(pageNumber)
except PageNotAnInteger:
pageNumber = 1
except EmptyPage:
pageNumber = paginator.num_pages
models = paginator.page(pageNumber)
return render_to_resp ( ..... models ....)
No estoy seguro de las subtitulaciones de este código, pero por lo que parece, la primera línea de código recupera todos los modelos de la base de datos y los introduce. Luego se pasa a Paginator, que lo fragmenta en función de la página en la que se encuentra el usuario desde un html GET. ¿El paginador de alguna manera está haciendo esto aceptable, o es esto totalmente ineficiente? Si es ineficiente, ¿cómo se puede mejorar?
Además, un tema relacionado. Si alguien lo hace:
Model.objects.all()[:40]
¿Este código significa que todos los modelos se insertan en la memoria, y empalmamos 40 de ellos? Cual es malo. ¿O quiere decir que consultamos y presionamos solo 40 objetos en el período de memoria?
¡Gracias por tu ayuda!
No hay nada de memoria ineficiente cuando se utiliza paginator. Los conjuntos de consulta se evalúan con pereza. En su llamada Paginator(models, 7)
, los models
son un conjunto de consulta que no ha sido evaluado hasta este punto. Por lo tanto, hasta ahora la base de datos no se ha visto afectada. Además, no hay una lista que contenga todas las instancias del modelo en la memoria en este punto.
Cuando desea obtener una página, es decir, en paginatedPage = paginator.page(pageNumber)
, se realiza el corte en este conjunto de consulta, solo en este punto se golpea la base de datos y la base de datos le devuelve un conjunto de consulta que contiene instancias del modelo. Y luego cortar solo devuelve los objetos que deberían estar allí en la página. Entonces, solo los objetos cortados irán en una lista que estará allí en la memoria. Diga en una página que desea mostrar 10 objetos, solo estos 10 objetos permanecerán en la memoria.
Cuando alguien lo hace;
Model.objects.all()[:40]
Cuando recorta una lista, se crea una nueva lista. En su caso, se creará una lista con solo 40 elementos y se almacenará en algún lugar de la memoria. Ninguna otra lista estará allí, por lo que no habrá ninguna lista que contenga todas las instancias de Model
en la memoria.
Usando la información anterior, se me ocurrió un decorador de funciones de visualización. Json_list_objects toma los objetos djanog para los dictados json-ready python de los campos de relación conocidos de los objetos django y devuelve la lista jsonificada como {count: results:}.
Otros pueden encontrarlo útil.
def with_paging(fn):
"""
Decorator providing paging behavior. It is for decorating a function that
takes a request and other arguments and returns the appropriate query
doing select and filter operations. The decorator adds paging by examining
the QueryParams of the request for page_size (default 2000) and
page_num (default 0). The query supplied is used to return the appropriate
slice.
"""
@wraps(fn)
def inner(request, *args, **kwargs):
page_size = int(request.GET.get(''page_size'', 2000))
page_num = int(request.GET.get(''page_num'', 0))
query = fn(request, *args, **kwargs)
start = page_num * page_size
end = start + page_size
data = query[start:end]
total_size = query.count()
return json_list_objects(data, overall_count=total_size)
return inner
mymodel.objects.all()
produce un queryset, no una lista. Los conjuntos de consulta son flojos: no se emite ninguna solicitud y no se hace nada hasta que realmente intenta usarlos. Además, dividir un conjunto de consultas no carga toda la maldita cosa en la memoria solo para obtener un subconjunto, sino que agrega límite y desplazamiento a la consulta SQL antes de llegar a la base de datos.