2012-07-12 2 views
1

동일한 기본 코드를 사용할 수 있어야하는 유사한보기가 많은 응용 프로그램을 만들었습니다. 그러나 각 메서드는 메서드 내의 여러 변곡점에서 특정 고유 한 특성을 가지고 있으므로 실제로 코드를 다시 사용하도록 구조화 할 방법을 찾을 수 없습니다. 대신 나는 cut-and-paste 방법론을 만들고 각 방법을 개별적으로 조정했습니다. 이 부분은 내가 작성한 첫 번째 파이썬 코드 중 일부 였고 거기에 더 나은 방법이 있어야한다는 것을 알았지 만 이런 방식으로 작업을 수행하고 "작동"하므로 잠깐 나가는 길을 찾을 수 없습니다 . 여기 장고의 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 방법은에 따라 개별 맞춤이 많이 필요합니다 처리중인 엔티티의 유형. 이것이 내가 이것을 처리 할 수있는 DRY 방법을 찾지 못하는 주된 이유입니다.

도움 주시면 감사하겠습니다.

+2

어떤 장고 버전을 사용하고 있습니까? 장고 1.3 이상인 경우 클래스 기반 뷰를 사용하여 뷰를 훨씬 더 DRY하게 만들 수 있습니다. –

+0

장고 1.3을 사용하고 있습니다. 당신은 정교 할 수 있습니까? – mVChr

+0

https://docs.djangoproject.com/en/dev/topics/class-based-views/ - 각보기는 다른보기 기능을 사용하고 재사용 할 수있게 해주는 클래스입니다. 하지만 당신의 견해는 많은 것을 할 것 같습니다 : 그것은 객체를 생성하고, 객체를로드하고, 여러 다른 형태를 제공하고, 리디렉션을 수행합니다. 너무 많이합니다. URL에서 모두 수행해야합니까? 그렇지 않으면 여러 견해로 리펙토링합니다. –

답변

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 

이 작은 내 사용자 정의보기를 유지하지만 특정 뷰에 필요한 어떤 비틀기 추가 할 수 있습니다 : 그런 식으로, 일부 복잡한 뷰에서 I는 다음과 같이 정의 코드를 삽입 할 수 있습니다.

1

클래스 기반보기를 사용하십시오. 클래스의 상속 및 기타 기능을 사용하여보기를 더 재사용 할 수 있습니다. 내장 된 일반 뷰를 사용하여 기본 작업 중 일부를 단순화 할 수도 있습니다.

체크 class-based views documentation. 또한 이것을 읽을 수 있습니다 this

+0

좋은 블로그 게시물 설명, 감사합니다. – mVChr