【问题标题】:Django queryset specific order by based on values of foreign key基于外键值的 Django 查询集特定顺序
【发布时间】:2014-05-02 17:05:28
【问题描述】:

我有两个模型,位置和球员,用于棒球网站。位置命名为投手、接球手、一垒、二垒、三垒等。

class Position(models.Model):
    name = models.CharField(max_length=100)
    slug = models.SlugField()

class Player(models.Model):
    name = models.CharField(max_length=300)
    slug = models.SlugField()
    position = models.ForeignKey(Position)

有没有办法让一个查询按特定顺序返回玩家?例如,我想做这样的事情:

Player.objects.all().order_by(position=('first base', 'second base', 'third base', 'pitcher', 'catcher',))

这将返回按位置字段排序的所有球员,按照指定的顺序为一垒、二垒、三垒、投手、接球手等。

【问题讨论】:

    标签: django django-models django-queryset


    【解决方案1】:

    您可以在 python 中使用sorted()

    order = ['first base', 'second base', 'third base', 'pitcher', 'catcher']
    players = sorted(Player.objects.all(), key = lambda p: order.index(p.position.name))
    

    另请参阅这些相关主题:

    【讨论】:

    • 如果有 100 万玩家,这将永远持续下去。
    • @PatrickBassut 是的,这是一个公平的观点,但它仍然是一个选项,并且适用于简单的用例。谢谢。
    • @Rollo 很难不同意。
    【解决方案2】:

    我有一个很长的配置文件表,有时需要预览其中一个,所以想法是从 DRF 加载此配置文件的第一块数据,这里是如何解决的:

    from django.db.models import Case, When, BooleanField
    Profile.objects.all().annotate(is_preview_profile=Case(When(id__exact=preview_profile_id, then=1), default=0, output_field=BooleanField())).order_by('-is_preview_profile')
    

    更多信息可以在这里找到: https://docs.djangoproject.com/en/1.10/ref/models/conditional-expressions/#case

    【讨论】:

      【解决方案3】:

      我建议将另一个字段添加到 Position 模型并检索按此字段排序的结果。

      class Position(models.Model):
          order = models.IntegerField()
          name = models.CharField(max_length=100)
          slug = models.SlugField()
      
          class Meta:
              ordering = ['order']
      

      然后,当您创建一个新的职位字段时,您可以设置它的顺序。当您需要它们时,您只需:

      Position.objects.all()
      

      然后他们将被订购。

      编辑:

      正如@AndrewGorcester 所说,将 unique=True 添加到 order 属性以避免编程错误(如果您将相同的订单添加到两个不同的位置),如下所示:

      order = models.IntegerField(unique=True)
      

      【讨论】:

      • 我同意这一点,但如果这符合您的用例,我也会将 unique=True 添加到 order 列中。
      【解决方案4】:

      如果您不想添加其他字段来跟踪排序,您可以覆盖默认的 id 字段以不自动分配,并确保添加的职位 ID 与其排序相对应。

      id = models.PositiveIntegerField()
      
      class Meta:
          ordering = ['id']
      

      现在你可以这样做了:

      Player.objects.all().order_by('position_id')
      

      【讨论】:

        【解决方案5】:

        虽然上述所有方法都是正确的,但这里是一种更 Pythonic 的方法来实现相同的目的。您可以使用双下划线链接另一个表中的键(作为外键链接)。相同的参考是here

        其中 user 是一个内置模型,可以使用 from django.contrib.auth.admin import User 导入

        例如

        我有一个模型Post 与作者姓名相关联,该作者姓名链接到外键模型User。其中 user 是一个内置模型,可以使用from django.contrib.auth.admin import User 导入

        from django.contrib.auth.admin import User
        class Post(models.Model):
            author = models.ForeignKey(User, on_delete=models.CASCADE)
        

        现在,用您可以使用的用户名对Posts 进行排序

        Post.objects.order_by('author__username')
        

        (注意是双下划线)

        【讨论】:

          猜你喜欢
          • 2015-07-30
          • 2012-10-10
          • 1970-01-01
          • 2019-10-26
          • 2015-03-09
          • 1970-01-01
          • 2017-11-19
          • 2011-12-25
          • 1970-01-01
          相关资源
          最近更新 更多