queryset not equal __gte django django-orm

not - Django: ¿relacionado con Force Select?



filter django (3)

Aquí también hay un truco divertido:

class DefaultSelectOrPrefetchManager(models.Manager): def __init__(self, *args, **kwargs): self._select_related = kwargs.pop(''select_related'', None) self._prefetch_related = kwargs.pop(''prefetch_related'', None) super(DefaultSelectOrPrefetchManager, self).__init__(*args, **kwargs) def get_queryset(self, *args, **kwargs): qs = super(DefaultSelectOrPrefetchManager, self).get_queryset(*args, **kwargs) if self._select_related: qs = qs.select_related(*self._select_related) if self._prefetch_related: qs = qs.prefetch_related(*self._prefetch_related) return qs class Sandwich(models.Model): bread = models.ForeignKey(Bread) extras = models.ManyToManyField(Extra) # ... objects = DefaultSelectOrPrefetchManager(select_related=(''bread'',), prefetch_related=(''extras'',))

Luego puede reutilizar el administrador fácilmente entre clases modelo. Como caso de uso de ejemplo, esto sería apropiado si tuviera un método __unicode__ en el modelo que representara una cadena que incluyera cierta información de un modelo relacionado (o cualquier otra cosa que implique que casi siempre se requiere un modelo relacionado).

... y si realmente quieres volverte loco, aquí tienes una versión más generalizada. Le permite llamar a cualquier secuencia de métodos en el conjunto de consultas predeterminado con cualquier combinación de kwargs o kwargs . Puede haber algunos errores en el código, pero entiendes la idea.

from django.db import models class MethodCalls(object): """ A mock object which logs chained method calls. """ def __init__(self): self._calls = [] def __getattr__(self, name): c = Call(self, name) self._calls.append(c) return c def __iter__(self): for c in self._calls: yield tuple(c) class Call(object): """ Used by `MethodCalls` objects internally to represent chained method calls. """ def __init__(self, calls_obj, method_name): self._calls = calls_obj self.method_name = method_name def __call__(self, *method_args, **method_kwargs): self.method_args = method_args self.method_kwargs = method_kwargs return self._calls def __iter__(self): yield self.method_name yield self.method_args yield self.method_kwargs class DefaultQuerysetMethodCallsManager(models.Manager): """ A model manager class which allows specification of a sequence of method calls to be applied by default to base querysets. `DefaultQuerysetMethodCallsManager` instances expose a property `default_queryset_method_calls` to which chained method calls can be applied to indicate which methods should be called on base querysets. """ def __init__(self, *args, **kwargs): self.default_queryset_method_calls = MethodCalls() super(DefaultQuerysetMethodCallsManager, self).__init__(*args, **kwargs) def get_queryset(self, *args, **kwargs): qs = super(DefaultQuerysetMethodCallsManager, self).get_queryset(*args, **kwargs) for method_name, method_args, method_kwargs in self.default_queryset_method_calls: qs = getattr(qs, method_name)(*method_args, **method_kwargs) return qs class Sandwich(models.Model): bread = models.ForeignKey(Bread) extras = models.ManyToManyField(Extra) # Other field definitions... objects = DefaultQuerysetMethodCallsManager() objects.default_queryset_method_calls.filter( bread__type=''wheat'', ).select_related( ''bread'', ).prefetch_related( ''extras'', )

El objeto MethodCalls inspirado en python-mock es un intento de hacer que la API sea más natural. Algunos pueden encontrar eso un poco confuso. Si es así, puede __init__ ese código para un __init__ o kwarg que solo acepta una tupla de información de llamada de método.

Creé un modelo y estoy representando el modelo predeterminado / no modificado para él. Esto solo genera 64 consultas SQL porque tiene bastantes claves externas, y éstas a su vez tienen más claves foráneas.

¿Es posible obligarlo a que siempre (de forma predeterminada) realice una select_related cada vez que se devuelve uno de estos modelos?


Cree un models.Manager personalizado. models.Manager y anule todos los métodos ( filter , get , etc.) y añada select_related a cada consulta. Luego configure este administrador como el atributo de objects en el modelo.

Yo recomendaría simplemente select_related su código y agregar select_related donde sea necesario, porque hacer select_related en todo va a causar problemas graves de rendimiento más adelante (y no estaría del todo claro de dónde viene).


Puede crear un administrador personalizado y simplemente anular get_queryset para que se aplique en todas partes. Por ejemplo:

class MyManager(models.Manager): def get_queryset(self): return super(MyManager, self).get_queryset().select_related(''foo'', ''bar'')

(Antes de Django 1.6, era get_query_set ).