Personnalisé QuerySet et Gestionnaire sans casser SEC?
J'essaie de trouver un moyen de mettre en œuvre à la fois une coutume QuerySet
et personnalisé Manager
sans casser SÈCHE. C'est ce que j'ai à ce jour:
class MyInquiryManager(models.Manager):
def for_user(self, user):
return self.get_query_set().filter(
Q(assigned_to_user=user) |
Q(assigned_to_group__in=user.groups.all())
)
class Inquiry(models.Model):
ts = models.DateTimeField(auto_now_add=True)
status = models.ForeignKey(InquiryStatus)
assigned_to_user = models.ForeignKey(User, blank=True, null=True)
assigned_to_group = models.ForeignKey(Group, blank=True, null=True)
objects = MyInquiryManager()
Cela fonctionne bien, jusqu'à ce que je fais quelque chose comme ceci:
inquiries = Inquiry.objects.filter(status=some_status)
my_inquiry_count = inquiries.for_user(request.user).count()
Ce rapidement des sauts de tout en raison de la QuerySet
n'ont pas les mêmes méthodes que la Manager
. J'ai essayé de créer un personnalisé QuerySet
classe, et de la mettre en œuvre dans MyInquiryManager
, mais j'arrive à la fin de la réplication de l'ensemble de mes définitions de méthode.
J'ai aussi trouvé cet extrait qui fonctionne, mais j'ai besoin de passer en argument supplémentaire pour for_user
de sorte qu'il se décompose, car il s'appuie fortement sur la nécessité de redéfinir get_query_set
.
Est-il un moyen de le faire sans redéfinir tous mes méthodes dans les deux QuerySet
et la Manager
sous-classes?
- Avertissement: La réponse sélectionnée par T. de Pierre résultats dans une grave dégradation de la performance (de l'ordre de la milliseconde temps de réponse multi-deuxième réponses) quand .de différer ou d' .seules les méthodes sont utilisées. Par exemple, dans Django 1.3 une requête telle que: Monmodèle.objets.seulement('some_field').get(id=1) => retourne en 3,7 ms mais, ajouter le CustomManager comme décrit ci-dessus, et j'obtiens: Monmodèle.objets.seulement('some_field').get(id=1) => retourne dans ~ 357ms
- Quelqu'un d'autre a reproduit ce? Avec Django 1.4?
- Ok. Mais pourquoi et comment est-ce possible? Sont les requêtes différentes, ou avez-vous le profil de cette opération, sans réellement frapper la base de données?
Vous devez vous connecter pour publier un commentaire.
Django a changé! Avant d'utiliser le code dans cette réponse, qui a été écrit en 2009, assurez-vous de vérifier le reste des réponses et de la documentation de Django pour voir si il y a une solution plus appropriée.
La façon dont je l'ai mis en place c'est par l'ajout de la réelle
get_active_for_account
comme une méthode personnaliséeQuerySet
. Ensuite, pour le faire fonctionner hors de l'manager, vous pouvez simplement piège de la__getattr__
et le retourner par conséquentPour faire de ce modèle réutilisable, j'ai extrait le
Manager
bits pour un autre modèle de manager:custom_queryset/models.py
Une fois que vous avez que, sur vos modèles, tout ce que vous devez faire est de définir un
QuerySet
comme une coutume intérieur de la classe et de définir le gestionnaire personnalisé de votre manager:your_app/models.py
Avec ce modèle, aucun de ces travaux:
UPD si vous l'utilisez avec des personnalisés de l'utilisateur(
AbstractUser
), vous avez besoin de changerde
à
defer
etonly
appels... à cause pathologique des requêtes supplémentaires effectuées. Fixe maintenant avec modification en cours.Le Django 1.7 a publié un nouvelle et simple façon de créer combiné queryset et le modèle du manager:
Voir La création de Gestionnaire de QuerySet méthodes pour plus de détails.
for_user
la méthode est un utilisateur et retourself.[...]
pour enchaîner de multiples opérations.Vous pouvez fournir les méthodes sur le gestionnaire et le queryset à l'aide d'un mixin. Voir la technique suivante:
http://hunterford.me/django-custom-model-manager-chaining/
Cela permet aussi d'éviter l'utilisation d'un
__getattr__()
approche.Une légère amélioration de la version de T. de Pierre de l'approche:
Classe décorateurs de rendre l'usage aussi simple que:
Mise à jour: support non standard de Gestionnaire et de QuerySet les classes de base e. g. @objects_extra(django.contrib.sig.db.modèles.GeoManager, django.contrib.sig.db.modèles.de la requête.GeoQuerySet):
get_queryset
d'être écrasé, pasget_query_set
.Vous pouvez maintenant utiliser le from_queryset() méthode sur vous manager pour modifier sa base de Queryset.
Cela vous permet de définir votre Queryset méthodes et votre gestionnaire de méthodes qu'une seule fois
de la documentation
La suivante fonctionne pour moi.
C'est sur la valeur par défaut du gestionnaire; je l'ai donc utilisé pour faire quelque chose comme:
Mais il n'y a aucune raison qu'il ne devrait pas travailler pour un secondaire manager.
filter
, puis à l'aideget_active_for_account
. Il fonctionne dans votre exemple, mais pas une fois que vous avez déjà utilisé unfilter
, et sont ensuite travailler avec unQuerySet
, qui a été mon exemple.