我构建了一个具有大量类似视图的应用程序,应该可以使用相同的基本代码。然而,每种方法在方法中的各种拐点处具有某些独特的特征,使得我无法找到构造它以实际重用任何代码的方法。相反,我创建了一种剪切和粘贴方法,并单独调整每个方法。应用程序的这一部分是我编写的第一个Python代码,并且知道必须有一个更好的方法来做到这一点,但我被锁定这样做并且“它工作”所以我看不出出路
以下是基本视图模板的基本外观:
def view_entity(request, entity_id=None):
if request.method == 'POST':
return _post_entity(request, entity_id)
else:
return _get_entity(request, entity_id)
def _get_entity(request, entity_id):
data = _process_entity(request, entity_id)
if 'redirect' in data:
return data['redirect']
else:
return _render_entity(request, data['form'])
def _post_entity(request, entity_id):
data = _process_entity(request, entity_id)
if 'redirect' in data:
return data['redirect']
elif data['form'].is_valid():
# custom post processing here
instance = data['form'].save()
return HttpResponseRedirect(reverse('entity', args=[instance.id]))
else:
return _render_entity(request, data['form'])
def _process_entity(request, entity_id):
data = {}
if entity_id != 'new': # READ/UPDATE
# sometimes there's custom code to retrieve the entity
e = entity_id and get_object_or_404(Entity.objects, pk=entity_id)
# sometimes there's custom code here that deauthorizes e
# sometimes extra values are added to data here (e.g. parent entity)
if e:
if request.method == 'POST':
data['form'] = EntityForm(request.POST, instance=e)
# sometimes there's a conditional here for CustomEntityForm
else:
data['form'] = EntityForm(instance=e)
else: # user not authorized for this entity
return {'redirect': HttpResponseRedirect(reverse('home'))}
# sometimes there's custom code here for certain entity types
else: # CREATE
if request.method == 'POST':
data['form'] = EntityForm(request.POST)
else:
data['form'] = EntityForm()
# sometimes extra key/values are added to data here
return data
我甚至没有包含所有可能的变体,但正如您所看到的,_process_entity
方法需要根据正在处理的实体类型进行大量的个性化定制。这是我无法找出干嘛方法来解决这个问题的主要原因。
感谢任何帮助,谢谢!
答案 0 :(得分:1)
使用基于类的视图。您可以使用类中的继承和其他功能来使您的视图更具可重用性。您还可以使用内置通用视图来简化某些基本任务。
检查class-based views documentation。您还可以阅读此this
答案 1 :(得分:0)
所以我最终将代码重构为基类,我的所有视图都继承自。我还没有最终重构到多个视图(但是),而是通过在处理方法中插入钩子来解决自定义处理方法的问题。
以下是继承自DetailView
的基类的要点:
class MyDetailView(DetailView):
context = {}
def get(self, request, *args, **kwargs):
self._process(request, *args, **kwargs)
if 'redirect' in self.context:
return HttpResponseRedirect(self.context['redirect'])
else:
return self._render(request, *args, **kwargs)
def post(self, request, *args, **kwargs):
self._process(request, *args, **kwargs)
if 'redirect' in self.context:
return HttpResponseRedirect(self.context['redirect'])
elif self.context['form'].is_valid():
self._get_hook('_pre_save')(request, *args, **kwargs)
return self._save(request, *args, **kwargs)
else:
return self._render(request, *args, **kwargs)
def _process(self, request, *args, **kwargs):
form = getattr(app.forms, '%sForm' % self.model.__name__)
if kwargs['pk'] != 'new': # READ/UPDATE
self.object = self.get_object(request, *args, **kwargs)
self._get_hook('_auth')(request, *args, **kwargs)
if not self.object: # user not authorized for this entity
return {'redirect': reverse(
'%s_list' % self.model.__name__.lower())}
self.context['form'] = form(
data=request.POST if request.method == 'POST' else None,
instance=self.object if hasattr(self, 'object') else None)
self._get_hook('_post_process')(request, *args, **kwargs)
def _get_hook(self, hook_name):
try:
return getattr(self, '%s_hook' % hook_name)
except AttributeError, e:
def noop(*args, **kwargs):
pass
return noop
需要注意的关键部分是_get_hook
方法以及我使用它的其他方法中的位置。这样,在一些复杂的视图中,我可以像这样注入自定义代码:
class ComplexDetailView(MyDetailView):
def _post_process_hook(self, request, *args, **kwargs):
# here I can add stuff to self.context using
# self.model, self.object, request.POST or whatever
这使我的自定义视图保持较小,因为它们继承了大部分功能,但我可以为该特定视图添加必要的调整。