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

Django多门店场景下为所有视图添加业务上下文的优雅实现方案

Django多门店视图改造的优雅实现方案

方案选择分析

  • URL参数方案:直观可分享,但每个视图需单独处理参数,用户切换门店需手动操作
  • Session存储方案:一次选择全局生效,无需重复操作,但状态绑定会话,无法通过链接分享,清缓存会丢失筛选状态
  • 混合方案(推荐):优先读取URL参数(支持链接分享),无参数时取Session保存的位置(提升体验),两者都无则用默认门店,兼顾两种方案的优点

具体实现步骤

1. 模型层改造

先定义Location模型,并给Employee、Item添加外键关联:

from django.db import models

class Location(models.Model):
    name = models.CharField(max_length=100, unique=True)
    address = models.TextField(blank=True)

    def __str__(self):
        return self.name

class Employee(models.Model):
    name = models.CharField(max_length=100)
    position = models.CharField(max_length=50)
    location = models.ForeignKey(Location, on_delete=models.CASCADE, related_name='employees')

class Item(models.Model):
    name = models.CharField(max_length=100)
    price = models.DecimalField(max_digits=10, decimal_places=2)
    location = models.ForeignKey(Location, on_delete=models.CASCADE, related_name='items')

2. 通用位置筛选逻辑

写一个工具函数统一处理位置获取逻辑,避免重复代码:

def get_selected_location(request):
    # 优先读取URL参数中的location_id
    location_id = request.GET.get('location_id')
    if location_id:
        try:
            location = Location.objects.get(id=location_id)
            # 更新Session,保存用户最近选择的门店
            request.session['selected_location_id'] = location_id
            return location
        except Location.DoesNotExist:
            pass
    
    # URL无参数时,读取Session中保存的门店
    session_loc_id = request.session.get('selected_location_id')
    if session_loc_id:
        try:
            return Location.objects.get(id=session_loc_id)
        except Location.DoesNotExist:
            # 清除无效的Session记录
            del request.session['selected_location_id']
    
    # 都无匹配时,返回第一个门店(可根据需求改为提示用户选择)
    return Location.objects.first()

3. 改造视图函数

基于现有函数视图,集成位置筛选逻辑:

# 员工列表视图
def EmployeeList(request):
    selected_loc = get_selected_location(request)
    # 筛选当前门店的员工
    employee_list = Employee.objects.filter(location=selected_loc)
    # 传递所有门店选项给模板
    all_locations = Location.objects.all()
    
    return render(request, 'Employee/list.html', {
        'objList': employee_list,
        'selected_location': selected_loc,
        'locations': all_locations
    })

# 商品列表视图(同理改造)
def ItemList(request):
    selected_loc = get_selected_location(request)
    item_list = Item.objects.filter(location=selected_loc)
    all_locations = Location.objects.all()
    
    return render(request, 'Item/list.html', {
        'objList': item_list,
        'selected_location': selected_loc,
        'locations': all_locations
    })

4. 模板添加筛选器

在列表模板顶部添加下拉筛选器,自动提交切换门店:

<!-- 员工列表模板 Employee/list.html -->
<form method="get" action="{% url 'EmployeeList' %}">
    <select name="location_id" onchange="this.form.submit()">
        {% for loc in locations %}
            <option value="{{ loc.id }}" {% if loc.id == selected_location.id %}selected{% endif %}>
                {{ loc.name }}
            </option>
        {% endfor %}
    </select>
</form>

<!-- 员工列表展示 -->
<div class="employee-list">
    {% for emp in objList %}
        <div class="employee-item">
            {{ emp.name }} | {{ emp.position }} | {{ emp.location.name }}
        </div>
    {% empty %}
        <p>当前门店暂无员工</p>
    {% endfor %}
</div>

5. 优化:用装饰器减少重复代码

如果有多个需要筛选的视图,可以写装饰器统一注入筛选逻辑:

from functools import wraps

def location_filtered(model):
    def decorator(view_func):
        @wraps(view_func)
        def wrapper(request, *args, **kwargs):
            selected_loc = get_selected_location(request)
            queryset = model.objects.filter(location=selected_loc)
            all_locations = Location.objects.all()
            
            # 将筛选结果和门店信息传入视图
            kwargs.update({
                'filtered_queryset': queryset,
                'selected_location': selected_loc,
                'all_locations': all_locations
            })
            return view_func(request, *args, **kwargs)
        return wrapper
    return decorator

# 使用装饰器简化视图
@location_filtered(Employee)
def EmployeeList(request, filtered_queryset, selected_location, all_locations):
    return render(request, 'Employee/list.html', {
        'objList': filtered_queryset,
        'selected_location': selected_location,
        'locations': all_locations
    })

方案优势

  • 用户体验友好:用户选择门店后,后续访问其他视图自动沿用该选择,无需重复操作
  • 支持链接分享:带location_id参数的URL可直接分享,对方打开后直接看到对应门店的数据
  • 代码复用性高:通用工具函数和装饰器可快速扩展到其他需要筛选的视图
  • 容错性强:自动处理无效的Session记录,避免报错

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.21 15:22:17