2012-07-12 36 views
1

我已經構建了一個應用程序,它有許多類似的視圖,應該能夠使用相同的基本代碼。然而,每種方法在方法中的各種拐點處都有一些獨特的特徵,這樣我就不能找出一種方法來構造這個來真正重用任何代碼。相反,我創建了一個剪切粘貼方法,並分別調整每種方法。這部分應用程序是我編寫的第一批Python代碼中的一部分,並且知道必須有更好的方法來做到這一點,但是我被鎖定在這樣做和「它工作」,所以我看不到出路。Django中的DRY視圖

下面介紹一下基本視圖模板基本上是這樣的:

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方法需要基於大量的個人定製正在處理的實體的類型。這是我無法弄清楚這種干擾方式的主要原因。

任何幫助表示讚賞,謝謝!

+2

你使用的是什麼版本的Django?如果它是Django 1.3或更高版本,則可以使用基於類的視圖來使視圖更加乾燥。 – 2012-07-12 18:41:42

+0

我正在使用Django 1.3。你能詳細說明一下嗎? – mVChr 2012-07-12 18:42:11

+0

請參閱https://docs.djangoproject.com/en/dev/topics/class-based-views/ - 每個視圖都是一個允許您使用和重用其他視圖的功能的類。但是你的觀點似乎做了很多事情:它創建對象,加載對象,呈現多種不同的表單,它執行重定向 - 這一切都太多了。這一切都需要在URL完成嗎?否則,我會重構成多個視圖。 – 2012-07-12 18:46:57

回答

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 

這使我的自定義視圖小,因爲它們繼承了大部分的功能,但我可以添加任何的調整是必要的特定視圖。

1

使用基於類的視圖。您可以使用類的繼承和其他功能來使您的視圖更加可重用。您還可以使用內置的通用視圖來簡化一些基本任務。

檢查class-based views documentation。你也可以閱讀這this

+0

好博文解釋,謝謝。 – mVChr 2012-07-12 21:30:35