You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何精简这段Django视图函数?求Python框架熟手解决方案

优化你的Django视图:精简重复代码的几种实用方式

首先,你的原代码最大的问题是重复的过滤逻辑和上下文构建——16次几乎一样的filter调用,不仅写起来麻烦,后续维护也容易出错(比如漏改某个分类的关键词)。作为常年和Django打交道的开发者,我会优先用以下几种方式精简:

1. 用字典推导式+映射列表(最推荐的基础优化)

把分类关键词和对应的上下文键做成一个映射列表,然后用字典推导式一次性生成上下文。这是最直接的重构,完全保留原逻辑,同时大幅减少代码量:

# 可以把这个映射提到模块顶部,作为全局常量,方便后续维护
MENU_CATEGORY_MAPPINGS = [
    ('p', 'PANCAKE'),
    ('e', 'EGG'),
    ('pn', 'PANNIS'),
    ('s', 'SUBS'),
    ('w', 'WRAPS'),
    ('t', 'TEA'),
    ('f', 'FRAPPE'),
    ('sm', 'SMOOTHIE'),
    ('gf', 'GLUTENF'),
    ('wa', 'WAFFLES'),
    ('to', 'TOAST'),
    ('hp', 'HOTPASTA'),
    ('b', 'BAGELS'),
    ('fr', 'FRIES'),
    ('sa', 'SALADS'),
    ('d', 'DESSERTS'),
]

def test(request):
    context = {
        key: MenuItem.objects.filter(item_category__icontains=category)
        for key, category in MENU_CATEGORY_MAPPINGS
    }
    return render(request, 'posts/test.html', context)

为什么这是首选?

  • 易维护:以后要新增/修改分类,只需要在MENU_CATEGORY_MAPPINGS里加一行或改一行,不用重复写filter和上下文键值对;
  • 逻辑一致:完全保留原代码的icontains过滤行为,每个分类对应独立的QuerySet(延迟执行,不会立即查询数据库);
  • 代码简洁:去掉了大量重复代码,可读性更高。

2. 减少数据库查询次数(性能优化方向)

原代码会触发16次数据库查询(每个filter在模板中遍历的时候才会执行)。如果你的菜单数据量较大,或者想优化查询次数,可以用一次查询获取所有相关条目,再在内存中分组:

from django.db.models import Q

MENU_CATEGORY_MAPPINGS = [
    # 同上的映射列表
]

def test(request):
    # 构建OR查询,一次性获取所有匹配任一分类的菜品
    category_query = Q()
    for _, category in MENU_CATEGORY_MAPPINGS:
        category_query |= Q(item_category__icontains=category)
    
    all_matching_items = MenuItem.objects.filter(category_query)
    
    # 在内存中按分类分组(注意保持icontains的大小写不敏感特性)
    context = {}
    for key, category in MENU_CATEGORY_MAPPINGS:
        context[key] = [
            item for item in all_matching_items
            if category.lower() in item.item_category.lower()
        ]
    
    return render(request, 'posts/test.html', context)

优缺点说明

  • 优点:把数据库查询从16次降到1次,减少数据库IO开销;
  • 缺点:所有匹配的菜品会加载到内存中,如果数据量极大(比如上万条),内存占用会增加。适合中小型菜单场景。

3. 进阶:如果菜品分类是结构化数据(模型外键)

如果你的item_category不是字符串字段,而是关联到Category模型的外键,那可以用更优雅的方式:

# 假设Category模型有name字段
def test(request):
    # 先获取需要的分类对象
    target_categories = Category.objects.filter(
        name__in=[cat for _, cat in MENU_CATEGORY_MAPPINGS]
    )
    
    # 用prefetch_related一次性获取分类和对应的菜品
    context = {
        key: category.menuitem_set.all()
        for key, category_name in MENU_CATEGORY_MAPPINGS
        for category in target_categories if category.name == category_name
    }
    
    return render(request, 'posts/test.html', context)

不过这需要你调整数据模型结构,适合从一开始就规划好分类的场景,能彻底避免字符串匹配的麻烦。

最后一点小建议

如果这个视图是用来渲染菜单页面,建议给MenuItem的item_category字段加索引——因为你频繁用icontains查询,索引能大幅提升查询速度。可以在模型里这样定义:

class MenuItem(models.Model):
    item_category = models.CharField(max_length=100, db_index=True)
    # 其他字段...

内容的提问来源于stack exchange,提问作者Quinnyboy

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.07 16:27:36