سؤال

أقوم بإنشاء موجز للأنشطة ولكن لا يمكنني معرفة كيفية تجنب استعلامات 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 هي نفسها.القليل من معالجة لغة بايثون وتادا، لديك جميع الأنشطة المتعلقة بالمستخدم الحالي في استعلامين.

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top