如何在Django视图中合并重复context代码以遵循DRY原则?
Django视图中Context的DRY优化方案
问题背景
希望在Django视图的return render语句中选择性合并context,遵循DRY(不要重复自己)原则简化带角色权限判断的视图代码,避免各分支重复编写相同的context内容。
原show视图代码
def show(request): now_day = datetime.date.today() current_user = request.user if request.method == 'GET': if view_self(current_user) == True and more_rights(current_user) == False: if Employees.objects.filter(employee_number=current_user).exists(): context = {'names': Employees.objects.filter(employee_number=current_user)} else: context = {'info': "Für sie existiert (noch) kein Datensatz in dieser Datenbank"} else: context = {'names': Employees.objects.all().order_by('last_name').values()} return render(request, 'show.html', context) else: if view_self(current_user) == True and more_rights(current_user) == False: if request.POST['id'] == 'Mitarbeiter auswählen...': context = { 'names': Employees.objects.filter(employee_number=current_user), 'info': "Bitte treffen Sie zuerst eine Auswahl" } else: employee = request.POST['id'] context = { 'names': Employees.objects.filter(employee_number=current_user), 'entries': Employees.objects.filter(id=request.POST['id']), 'work_conditions': Employment.objects.filter(employee_id=request.POST['id']), 'functions': Functions.objects.filter(employee__functions=request.POST['id']).order_by('function'), 'fieldsoa': FieldsOfActivity.objects.filter(employee__fieldsofactivity=request.POST['id']).order_by('field_of_activity'), 'missions': Foreign_Missions.objects.filter(employee_id=request.POST['id']).order_by('-begin'), 'examinations': Examinations.objects.filter(employee_id=request.POST['id']).order_by('-date'), 'total_duration_days': Foreign_Missions.objects.total_duration_days(employee), 'today': now_day, 'special_header': "Datensätze anzeigen" } elif request.POST['id'] == 'Mitarbeiter auswählen...': context = { 'names': Employees.objects.all().order_by('last_name').values(), 'info': "Bitte treffen Sie zuerst eine Auswahl" } elif 'id' in request.POST: employee = request.POST['id'] #Employees.objects.get(pk=id) context = { 'names': Employees.objects.all().order_by('last_name').values(), 'entries': Employees.objects.filter(id=request.POST['id']), 'work_conditions': Employment.objects.filter(employee_id=request.POST['id']), 'functions': Functions.objects.filter(employee__functions=request.POST['id']).order_by('function'), 'fieldsoa': FieldsOfActivity.objects.filter(employee__fieldsofactivity=request.POST['id']).order_by('field_of_activity'), 'missions': Foreign_Missions.objects.filter(employee_id=request.POST['id']).order_by('-begin'), 'examinations': Examinations.objects.filter(employee_id=request.POST['id']).order_by('-date'), 'total_duration_days': Foreign_Missions.objects.total_duration_days(employee), 'today': now_day, 'special_header': "Datensätze anzeigen" } return render(request, 'show.html', context)
原delete视图代码
def delete(request): context = {} context['names'] = Employees.objects.all().order_by('last_name').values(), if request.method == 'GET': context = { # 'names': Employees.objects.all().order_by('last_name').values(), 'special_header': "Datensätze löschen", } # Wenn der Button ohne Auswahl gedrückt wird elif 'id' in request.POST and request.POST['id'] == 'Mitarbeiter löschen...': context = { # 'names': Employees.objects.all().order_by('last_name').values(), 'info': "Bitte treffen Sie zuerst eine Auswahl" } else: id = request.POST['id'] lastname = Employees.objects.get(id=id).last_name.upper() firstname = Employees.objects.get(id=id).first_name trash = Employees.objects.filter(id=id) # trash.delete() context = { # 'names': Employees.objects.all().order_by('last_name').values(), 'success': "Datensatz für " + lastname + ", " + firstname + " wurde gelöscht" } return render(request, 'delete.html', context)
优化方案
核心思路:先初始化基础context(包含所有分支共有的字段),再根据不同业务分支追加/修改特定字段,避免重复定义完整的context字典。
1. show视图优化
def show(request): now_day = datetime.date.today() current_user = request.user # 提前计算权限判断结果,避免重复写长条件 is_self_only = view_self(current_user) and not more_rights(current_user) # 初始化基础context,先处理所有分支都可能用到的names字段 context = {} if is_self_only: # 先查询当前用户的员工记录 self_employees = Employees.objects.filter(employee_number=current_user) if self_employees.exists(): context['names'] = self_employees else: context['info'] = "Für sie existiert (noch) kein Datensatz in dieser Datenbank" else: context['names'] = Employees.objects.all().order_by('last_name').values() if request.method == 'GET': return render(request, 'show.html', context) # 处理POST请求 post_id = request.POST.get('id') if is_self_only: if post_id == 'Mitarbeiter auswählen...': # 只追加info字段,保留已有的names context['info'] = "Bitte treffen Sie zuerst eine Auswahl" else: # 追加详细数据字段 employee = post_id context.update({ 'entries': Employees.objects.filter(id=post_id), 'work_conditions': Employment.objects.filter(employee_id=post_id), 'functions': Functions.objects.filter(employee__functions=post_id).order_by('function'), 'fieldsoa': FieldsOfActivity.objects.filter(employee__fieldsofactivity=post_id).order_by('field_of_activity'), 'missions': Foreign_Missions.objects.filter(employee_id=post_id).order_by('-begin'), 'examinations': Examinations.objects.filter(employee_id=post_id).order_by('-date'), 'total_duration_days': Foreign_Missions.objects.total_duration_days(employee), 'today': now_day, 'special_header': "Datensätze anzeigen" }) else: if post_id == 'Mitarbeiter auswählen...': context['info'] = "Bitte treffen Sie zuerst eine Auswahl" elif post_id: employee = post_id context.update({ 'entries': Employees.objects.filter(id=post_id), 'work_conditions': Employment.objects.filter(employee_id=post_id), 'functions': Functions.objects.filter(employee__functions=post_id).order_by('function'), 'fieldsoa': FieldsOfActivity.objects.filter(employee__fieldsofactivity=post_id).order_by('field_of_activity'), 'missions': Foreign_Missions.objects.filter(employee_id=post_id).order_by('-begin'), 'examinations': Examinations.objects.filter(employee_id=post_id).order_by('-date'), 'total_duration_days': Foreign_Missions.objects.total_duration_days(employee), 'today': now_day, 'special_header': "Datensätze anzeigen" }) return render(request, 'show.html', context)
优化点说明:
- 提前计算
is_self_only变量,避免重复编写权限判断逻辑 - 先初始化基础的
names或info字段,各分支只需追加差异字段 - 使用
context.update()批量追加字段,替代重复定义完整字典 - 用
request.POST.get('id')替代直接索引,避免KeyError
2. delete视图优化
原问题是每次重新赋值context导致基础的names字段被覆盖,优化后:
def delete(request): # 初始化基础context,包含所有分支都需要的names字段 context = { 'names': Employees.objects.all().order_by('last_name').values() } if request.method == 'GET': # 仅新增special_header字段,保留原有names context['special_header'] = "Datensätze löschen" elif 'id' in request.POST: post_id = request.POST['id'] if post_id == 'Mitarbeiter löschen...': context['info'] = "Bitte treffen Sie zuerst eine Auswahl" else: # 获取员工信息,优化查询减少DB访问 employee = Employees.objects.get(id=post_id) # trash = employee # 直接用实例 # trash.delete() context['success'] = f"Datensatz für {employee.last_name.upper()}, {employee.first_name} wurde gelöscht" return render(request, 'delete.html', context)
优化点说明:
- 先初始化包含
names的基础context,所有分支都不会覆盖这个字段 - 用
context['key'] = value追加字段,替代重新定义完整字典 - 优化员工信息查询,从两次
get改为一次,减少数据库访问
内容的提问来源于stack exchange,提问作者Krallenkroete
相关产品推荐
相关产品推荐

