你能优化这段代码吗? (姜戈,蟒蛇)

Posted

技术标签:

【中文标题】你能优化这段代码吗? (姜戈,蟒蛇)【英文标题】:Can you optimize this code? (Django, python) 【发布时间】:2018-03-02 15:00:14 【问题描述】:

我正在添加“已添加”字段以检查将用户的帖子(服装)添加到哪些类别。这听起来很可怕,所以让我们深入研究代码。

我要优化 get_categories(self, obj) 函数。

class CategorySerializer(serializers.ModelSerializer):
    added = serializers.BooleanField()
    class Meta:
        model = Category
        fields = (
            'id',
            'name',
            'added'
        )


class OutfitDetailSerializer(serializers.ModelSerializer):

    def get_categories(self, obj):
        user = self.context['request'].user
        categories = Category.objects.filter(owner=user)
        added = categories.extra(select='added': '1').filter(outfits__pk=obj.pk)
        added = list(added.values('added', 'name', 'id'))
        added_f = categories.extra(select='added': '0').exclude(outfits__pk=obj.pk)
        added_f = list(added_f.values('added', 'name', 'id'))
        categories = added + added_f
        return CategorySerializer(categories, many=True).data

输出如下!

"categories": [
        "id": 1,
        "name": "Gym",
        "added": true
    , 
        "id": 2,
        "name": "School",
        "added": false
    , 
        "id": 3,
        "name": "hollymo",
        "added": true
    , 
        "id": 4,
        "name": "Normal",
        "added": false
    , 
        "id": 6,
        "name": "New Category",
        "added": false
    
]

这里是models.py

class Outfit(models.Model):
    ...
    user = models.ForeignKey(settings.AUTH_USER_MODEL, null=True, blank=True)
    content = models.CharField(max_length=30)
    ...

class Category(models.Model):
    name = models.CharField(max_length=20)
    owner = models.ForeignKey(settings.AUTH_USER_MODEL, null=True, blank=True)
    outfits = models.ManyToManyField(Outfit, related_name="categories", blank=True)
    main_img = models.ImageField(
                            upload_to=upload_location_category,
                            null=True,
                            blank=True)
    ...

这里是repo for test

【问题讨论】:

最好将模型添加到当前问题中,对其他人更具可读性 好吧,等一下 【参考方案1】:

如果我猜对了,您可以通过django raw sql 获取必要的数据:

q = """\
SELECT yourappname_category.id,
       yourappname_category.name,
       COUNT(outfit_id) > 0 as added 
FROM yourappname_category
  LEFT JOIN yourappname_category_outfits 
      ON yourappname_category.id = yourappname_category_outfits.category_id 
         AND yourappname_category_outfits.outfit_id=%s
WHERE yourappname_category.owner_id=%s
GROUP BY yourappname_category.id, yourappname_category.name"""

categories = Category.objects.raw(q, [obj.id, user.id])
results = ['id': c.id, 'name': c.name, 'added': c.added for c in categories]

【讨论】:

Category"added": false 将如何出现在您的查询中?你的逻辑是什么? OP 通过added_f = categories.extra(select='added': '0').exclude(outfits__pk=obj.pk)获取它 @devxplorer 你能解释一下吗? @BearBrown 它将 LEFT 加入具有指定 id 的服装,然后按类别分组并计算类别的服装项目,如果类别没有服装,它将得到 COUNT(outfit_id) > 0 为 false。但也许我没有完全理解作者想要什么 @JohnBaek 请看上面的评论,告诉你你试过这个,它返回正确的结果吗? @devxplorer 我测试你的解决方案,这是错误的,repo for test【参考方案2】:

如果我正确理解您的用例,您只想“检查用户帖子(服装)添加到哪些类别”。为此,您只需要返回已添加的 = true 对吗?然后您可以将添加的密钥留在外面。

如:

"categories": [
        "id": 1,
        "name": "Gym"
    , 
        "id": 3,
        "name": "hollymo"
    
]

如果是这样,您可以使用:

import Category from category.models

class CategoriesSerializer(serializers.ModelSerializer):

    class Meta:
        model = Category
        fields = ('id', 'name')

class OutfitDetailSerializer(serializers.ModelSerializer):
    categories = CategoriesSerializer(many=True)

如果您的用例是显示所有类别的列表,然后仅对添加当前装备的类别执行某些操作,我建议执行 2 个 API 调用而不是您当前的逻辑;一个带有我在上面提供的答案,一个用于获取所有类别。然后在前端执行“添加”逻辑作为其表示层逻辑imo。

我当然会尽量避免在 Django 中执行原始 SQL 查询,它会削减迁移的目的并且很少需要。

【讨论】:

问题中的代码可以正常工作,但是目前OP想知道有没有办法最小化对数据库的查询。 我明白了,因此使用原始 SQL 的答案可能是正确的(我当然不是想抨击那个答案!)。但我认为有问题的代码可能不是您在性能方面设置 API 架构的最佳方式,因此我建议重新考虑输出而不是尝试创建它。

以上是关于你能优化这段代码吗? (姜戈,蟒蛇)的主要内容,如果未能解决你的问题,请参考以下文章

你能告诉我这段代码在做啥吗?

C# 编译器会优化这段代码吗?

有人可以解释所有代码的含义吗?蟒蛇[关闭]

你觉得我的这段Java代码还有优化的空间吗?

你觉得我的这段Java代码还有优化的空间吗?

姜戈。如何从多个复选框中获取值