【问题标题】:Django sorting queryset with nested querysets in pythonDjango在python中使用嵌套查询集对查询集进行排序
【发布时间】:2020-10-23 10:35:59
【问题描述】:

我有一个带有嵌套查询集(成员资格)的查询集(组)和一个嵌套查询集(信用)。这是输出:

group = [
    {
        "name": "Group2",
        "memberships": [
            {
                "username": "test1",
                "credits": [
                    {
                        "credits": 1000,
                        "year": 2020,
                        "week": 42,
                        "game_count": 1,
                        "last_game_credits": 10,
                    }
                ],
            },
            {
                "username": "test2",
                "credits": [
                    {
                        "credits": 1500,
                        "year": 2020,
                        "week": 42,
                        "game_count": 1,
                        "last_game_credits": 0,
                    }
                ],
            },
            {
                "username": "test",
                "credits": [
                    {
                        "credits": 1000,
                        "year": 2020,
                        "week": 42,
                        "game_count": 1,
                        "last_game_credits": 0,
                    }
                ],
               
            }
        ]
    }
]

我想通过以下方式在会员中对会员进行排名:

学分(金额)

game_count(数量)

last_game_credits(金额)

因此,如果两名玩家的积分相同,则 game_count 最高的玩家获胜。如果相同,则 last_game_credits 最高的获胜。

我希望返回相同的结构。

Models: 
class Group(models.Model):
    name = models.CharField(max_length=128, unique=True)
    members = models.ManyToManyField(settings.AUTH_USER_MODEL, related_name="memberships", 
    through='Membership')
    
class Membership(models.Model):
    user = models.ForeignKey(settings.AUTH_USER_MODEL, related_name="membership", 
    on_delete=models.CASCADE)
    group = models.ForeignKey(Group, on_delete=models.CASCADE)
    
class Credits(models.Model):
    credits = models.IntegerField()
    year = models.IntegerField(default=date.today().isocalendar()[0])
    week = models.IntegerField(default=date.today().isocalendar()[1])
    user = models.ForeignKey(settings.AUTH_USER_MODEL, related_name="credits", 
    on_delete=models.CASCADE)
    game_count = models.IntegerField(default=0)
    last_game_credits = models.IntegerField(null=True)

class User(AbstractBaseUser, PermissionsMixin):
    email = models.EmailField(max_length=255, unique=True)
    username = NameField(max_length=25, unique=True,  

查看:

class GroupSet(generics.ListAPIView):
    lookup_field = 'name'
    serializer_class = GroupSerializer

def get_queryset(self):

    year = self.request.query_params.get('year', None)
    week = self.request.query_params.get('week', None)
    name = self.request.query_params.get('name', None)

    if name and week and year is not None:

      prefetchCredits = Prefetch('user__credits', queryset=Credits.objects.filter(year=year, 
      week=week))

      prefetchMembership = Prefetch('membership_set', 
      queryset=Membership.objects.prefetch_related(prefetchCredits))

      group = Group.objects.filter(name__iexact=name).prefetch_related(prefetchMembership)

      return group

                        

不幸的是,在 Credits 字段上使用 .annotate 然后使用 order_by 是行不通的。出于某种原因,使用了 de DB 中的所有 Credits 对象,而不是使用年和周过滤的 Prefetched 对象。所以 Prefetch 被忽略了。

我的问题是如何在 python 中如上所述进行排序/排序。由于嵌套查询集和成员模型是多对多的,我不断收到错误。

【问题讨论】:

    标签: python django django-models django-rest-framework django-views


    【解决方案1】:

    我设法通过以下方式获得了预期的结果:

    class GroupSet(generics.ListAPIView):
        lookup_field = 'name'
        serializer_class = GroupSerializer
    
        def get_queryset(self):
    
            year = self.request.query_params.get('year', None)
            week = self.request.query_params.get('week', None)
            name = self.request.query_params.get('name', None)
    
            if name and week and year is not None:
    
                weekStr = str(week)
                yearStr = str(year)
                yearweekStr = yearStr + '-W' + weekStr
                r = datetime.datetime.strptime(yearweekStr + '-7', "%G-W%V-%u").date()
    
                prefetchCredits = Prefetch('user__credits', queryset=Credits.objects.filter(year=year, week=week))
    
                prefetchMemberships = Prefetch('membership_set', queryset=Membership.objects.prefetch_related(prefetchCredits))
    
                sortedMemberships = sorted(prefetchMemberships.queryset, key=lambda e: (e.user.credits.all()[0].credits, e.user.credits.all()[0].game_count, e.user.credits.all()[0].last_game_credits),
                             reverse=True)
    
                group = Group.objects.filter(name__iexact=name)
    
                newGroup = [
                    {
                        'name': group[0].name,
                        'id': group[0].id,
                        'membership_set': sortedMemberships
    
                    }
                ]
    
                return newGroup
    

    在使用 Prefetched Credits 检索成员资格后,将对成员进行排序。这会创建一个列表,因此在调用 Group 对象时不能在 prefetch_related 中使用它。因此,newGroup 对象由来自 group 的数据和 storedMemberships 变量组成。

    如果有人有一个不那么狡猾的解决方案,我很想听听。

    【讨论】:

      猜你喜欢
      • 2020-10-04
      • 2011-06-19
      • 2021-11-30
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2018-02-09
      • 2017-10-06
      • 2016-03-23
      相关资源
      最近更新 更多