Comment créer une propriété de relations qui peuvent être prefetch_related par des conditions spécifiques

Comment créer une propriété de relations qui peuvent être prefetch_related par des conditions spécifiques

Je veux définir une relation prefetch_related qui peut être réduite à un certain modèle dans des conditions spécifiques.

introduction

Par exemple, supposons qu'il existe des modèles X et Y avec une relation M: N.

class X(models.Model):
    name = models.CharField(max_length=32, null=False, default="")
    ctime = models.DateTimeField(auto_now_add=True, null=False)
    is_valid = models.BooleanField(default=True, null=False)


class Y(models.Model):
    name = models.CharField(max_length=32, null=False, default="")
    ctime = models.DateTimeField(auto_now_add=True, null=False)
    is_valid = models.BooleanField(default=True, null=False)

    xs = models.ManyToManyField(X, related_name="ys")

Je veux obtenir la relation de X réduite par les conditions suivantes pour un objet avec Y.

--ordonné par -ctime --Filtre avec ʻis_valid = True`

Si vous l'écrivez directement, cela ressemblera à ce qui suit

y.xs.all().filter(is_valid=True).order_by("-ctime")

Exigences

Par exemple, si vous nommez la relation qui satisfait les conditions ci-dessus comme «valid_xs», vous pouvez l'utiliser comme suit.

#à partir de l'instance
y.valid_xs  # =>  [X,X,X,X]

# prefetch_related (N+1 requête peut être supprimée)
for y in Y.objects.all().prefetch_related("valid_xs"):
    print(y, y.valid_xs)

la mise en oeuvre

prefetch_related (" valid_xs ") était difficile, donc prefetch_related (Y.prefetch_valid_xs ()) est bien.

Définissez la fonction suivante.

def custom_relation_property(getter):
    name = getter.__name__
    cache_name = "_{}".format(name)

    def _getter(self):
        result = getattr(self, cache_name, None)
        if result is None:
            result = getter(self)
            setattr(self, cache_name, result)
        return result

    def _setter(self, value):
        setattr(self, cache_name, value)

    prop = property(_getter, _setter, doc=_getter.__doc__)
    return prop

Modifiez la définition du modèle comme suit

class X(models.Model):
    name = models.CharField(max_length=32, null=False, default="")
    ctime = models.DateTimeField(auto_now_add=True, null=False)
    is_valid = models.BooleanField(default=True, null=False)

    @classmethod
    def valid_set(cls, qs=None):
        if qs is None:
            qs = cls.objects.all()
        return qs.filter(is_valid=True).order_by("-ctime")

class Y(models.Model):
    name = models.CharField(max_length=32, null=False, default="")
    ctime = models.DateTimeField(auto_now_add=True, null=False)
    is_valid = models.BooleanField(default=True, null=False)

    xs = models.ManyToManyField(X, related_name="ys")

    @custom_relation_property
    def valid_xs(self):
        return X.valid_set(self.xs.all())

    @classmethod
    def prefetch_valid_xs(cls):
        return Prefetch("xs", queryset=X.valid_set(), to_attr="valid_xs")

Il peut être utilisé comme suit.

#à partir de l'instance
Y.objects.get(id=1).valid_xs  # => [X,X,X,X]

# prefetch_related (N+1 requête peut être supprimée)
for y in Y.objects.all().prefetch_related(Y.prefetch_valid_xs()):
    print(y, y.valid_xs)

référence

C'est un blog que j'ai écrit moi-même.

Recommended Posts

Comment créer une propriété de relations qui peuvent être prefetch_related par des conditions spécifiques
Comment installer la bibliothèque Python qui peut être utilisée par les sociétés pharmaceutiques
Comment créer un bot Janken qui peut être facilement déplacé (commentaire)
Comment créer un wrapper qui préserve la signature de la fonction à envelopper
Je souhaite créer une file d'attente prioritaire pouvant être mise à jour avec Python (2.7)
Comment créer une clé USB que l'installateur Linux et Win10 et winpe peuvent démarrer UEFI
Comment extraire les conditions (acquérir tous les éléments du Groupe qui remplissent les conditions) pour Groupe par Groupe
[Python] Comment créer une liste de chaînes de caractères caractère par caractère
Implémentez un thread qui peut être suspendu en exploitant le rendement
Comment démarrer un serveur WEB simple qui peut exécuter des cgi de php et python
Comment configurer un serveur SMTP simple qui peut être testé localement en Python
Comment afficher le texte et le texte de survol qui peuvent être exécutés en cliquant avec le plug-in Minecraft
[Python] Un programme pour trouver le nombre de pommes et d'oranges qui peuvent être récoltées
Convertir les données de maillage exportées de SpriteUV2 dans un format pouvant être importé par Spine
[Python] Comment forcer une méthode d'une sous-classe à effectuer un processus spécifique
Enquête sur l'alimentation CC contrôlable par Python
Comment créer un pont virtuel
Comment créer un Dockerfile (basique)
Comment créer une grande quantité de données de test dans MySQL? ??
Comparaison de 4 styles pouvant être passés à seaborn avec set_context
[Python] Comment utiliser l'instruction for. Une méthode d'extraction en spécifiant une plage ou des conditions.
Comment créer un fichier de configuration
[Python] Un programme qui trouve une paire qui peut être divisée par une valeur spécifiée
Créez une application Web qui peut être facilement visualisée avec Plotly Dash
Un mémorandum sur la façon d'écrire des pandas que j'ai tendance à oublier personnellement
Comment créer un clone depuis Github
Comment créer un référentiel à partir d'un média
Je voulais créer rapidement un serveur de messagerie utilisable librement avec postfix + dovecot sur EC2
[Python3] Code qui peut être utilisé lorsque vous souhaitez découper une image dans une taille spécifique
Notes pour créer des figures pouvant être publiées dans des revues avec matplotlib
J'ai essayé de créer une classe qui peut facilement sérialiser Json en Python
Ce que j'ai appris en mettant en œuvre comment créer une boîte par défaut pour SSD
[python] Comment trier par le Nth Mth élément d'un tableau multidimensionnel
Je souhaite créer une application WEB en utilisant les données de League of Legends ①
Comment faire un Raspberry Pi qui parle les tweets d'un utilisateur spécifié
Une nouvelle forme d'application qui fonctionne avec GitHub: Comment créer des applications GitHub
Comment calculer la volatilité d'une marque
Un ensemble d'entiers qui satisfait ax + by = 1.
Comment créer un objet fonction à partir d'une chaîne
Comment créer un fichier JSON en Python
[Note] Comment créer un environnement de développement Ruby
Comment créer une boîte de saisie Kivy 1 ligne
Procédure de création d'application multi-plateforme avec kivy
Comment créer une API Rest dans Django
Comment compter les nombres dans une plage spécifique
[Note] Comment créer un environnement de développement Mac
Convertir des images du SDK FlyCapture en un formulaire pouvant être utilisé avec openCV
Ce que vous pouvez comprendre parce que vous êtes un débutant Comment créer un fichier (premier message)
Un script qui peut effectuer des tests de résistance en fonction du nombre de cœurs CPU
Comment mettre Pyenv sur Amazon Linux et Ubuntu pour créer un environnement Python 3.6.0
[Python] Introduction au scraping WEB | Résumé des méthodes pouvant être utilisées avec webdriver
J'ai essayé de faire une application mémo qui peut être pomodoro, mais un enregistrement de réflexion
[Ruby] Comment remplacer uniquement une partie de la chaîne de caractères correspondant à l'expression régulière?
Un mécanisme pour appeler des méthodes Ruby à partir de Python qui peut être fait en 200 lignes
Lire la source Python-Markdown: Comment créer un analyseur
Créer un ensemble de données d'images à utiliser pour la formation
Comment créer un sous-menu avec le plug-in [Blender]
[Go] Comment créer une erreur personnalisée pour Sentry