كيفية الاستعلام عبر العلاقات العامة في جانغو
-
21-12-2019 - |
سؤال
أقوم بإنشاء موجز للأنشطة ولكن لا يمكنني معرفة كيفية تجنب استعلامات N+1.
في الأساس، يكون للفريق أو المكان متابعين/أنشطة، وكل مستخدم هو متابع لديه خلاصة أنشطة مأخوذة من الفرق/الأماكن التي يتابعونها.
مقتطفات من نماذجي:
class Follower(models.Model):
user = models.ForeignKey(User)
content_type = models.ForeignKey(ContentType)
object_id = models.PositiveIntegerField()
content_object = GenericForeignKey('content_type', 'object_id')
class Activity(models.Model):
...
content_type = models.ForeignKey(ContentType)
object_id = models.PositiveIntegerField()
content_object = GenericForeignKey('content_type', 'object_id')
class Team(models.Model):
...
followers = GenericRelation('Follower')
activities = GenericRelation('Activity')
class Place(models.Model):
...
followers = GenericRelation('Follower')
activities = GenericRelation('Activity')
أنا أستخدم DRF ولدي برنامج تسلسلي أساسي للنشاط، وأعتقد أن الجزء الصعب موجود داخل العرض:
class ActivityViewSet(viewsets.ModelViewSet):
def list(self, request):
#N+1 query
activities = [f.content_object.activities.all() for f in request.user.follower_set.all()]
...
هذا يعمل، ولكن هل هناك طريقة أفضل للقيام بهذا الاستعلام؟
المحلول
def list(self, request):
items = {}
for f in request.user.follower_set.all():
items.setdefault(f.content_type_id, []).append(f.object_id)
activities = Activity.objects.get_empty_queryset() # get_empty_query_set in <1.5
for k, v in items.iteritems():
activities |= Activity.objects.filter(content_type=k, object_id__in=v)
هذا يتلخص في استعلامين.إنه يستفيد من حقيقة أنه إذا كان أ Follower
و Activity
ترتبط بنفس الكائن (الفريق أو المكان)، و content_type
و object_id
هي نفسها.القليل من معالجة لغة بايثون وتادا، لديك جميع الأنشطة المتعلقة بالمستخدم الحالي في استعلامين.
لا تنتمي إلى StackOverflow