Ich möchte eine prefetch_related-Beziehung festlegen, die unter bestimmten Bedingungen auf ein bestimmtes Modell eingegrenzt werden kann.
Angenommen, es gibt Modelle X und Y mit einer M: N-Beziehung.
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")
Ich möchte die Beziehung von X durch die folgenden Bedingungen für ein Objekt mit Y eingrenzen lassen.
--bestellen nach -ctime
--filter mit is_valid = True
Wenn Sie es direkt aufschreiben, sieht es wie folgt aus
y.xs.all().filter(is_valid=True).order_by("-ctime")
Wenn Sie beispielsweise die Beziehung, die die obigen Bedingungen erfüllt, als "valid_xs" bezeichnen, können Sie sie wie folgt verwenden.
#von der Instanz
y.valid_xs # => [X,X,X,X]
# prefetch_related (N+1 Abfrage kann unterdrückt werden)
for y in Y.objects.all().prefetch_related("valid_xs"):
print(y, y.valid_xs)
prefetch_related (" valid_xs ")
war schwierig, daher ist prefetch_related (Y.prefetch_valid_xs ())
in Ordnung.
Definieren Sie die folgende Funktion.
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
Ändern Sie die Definition des Modells wie folgt
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")
Es kann wie folgt verwendet werden.
#von der Instanz
Y.objects.get(id=1).valid_xs # => [X,X,X,X]
# prefetch_related (N+1 Abfrage kann unterdrückt werden)
for y in Y.objects.all().prefetch_related(Y.prefetch_valid_xs()):
print(y, y.valid_xs)
Referenz
Es ist ein Blog, den ich selbst geschrieben habe.