Je veux définir une relation prefetch_related qui peut être réduite à un certain modèle dans des conditions spécifiques.
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")
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)
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