2011-07-03 5 views
6

저는 기능 웹 사이트가 자습서의 일반적인보기와 함께 얼마나 빨리 갈 수 있는지 감탄했습니다. 또한 양식 처리를위한 워크 플로도 좋습니다. ModelForm helper 클래스를 사용하여 만든 모델에서 양식을 만들었으며 많은 기능이 함께 제공되는 것을 보았습니다. 일반적인 list_detail.object_detail을 사용했을 때 내가 보여줄 수있는 모든 것이 개별적으로 필드라는 사실에 실망했습니다. ModelForm 클래스에는 렌더링 정보가 포함되어 있으므로 ModelForm을 일반 뷰와 함께 사용하려고했습니다.클래스 기반의 일반 뷰 DetailView를 ModelForm과 함께 사용하면 버그가 있음 - 진행 방법?

나는 몇 가지 방향을 알아 내기 위해 stackoverflow에서 묻고 있었고 여러 포스터의 답변과 의견을 높이 평가했습니다. 이 방법을 사용하는 방법을 알아 냈지만 DetailView에는 버그가 있습니다. 이 솔루션에는 해결 방법이 포함되어 있습니다.

은 일반 볼 수있는 모델 뷰를 사용하여 자동으로 다음 작품을 렌더링하기 위해 모든 필드를 얻으려면 :

이 프로젝트를 생성하고, 응용 프로그램 입원 환자를 작성합니다.

당신이

# inpatients/models.py 

class Inpatient(models.Model): 
    last_name = models.CharField(max_length=30) 
    first_name = models.CharField(max_length=30,blank=True) 
    address = models.CharField(max_length=50,blank=True) 
    city = models.CharField(max_length=60,blank=True) 
    state = models.CharField(max_length=30,blank=True) 
    DOB = models.DateField(blank=True,null=True) 
    notes = models.TextField(blank=True) 

    def __unicode__(self): 
     return u'%s, %s %s' % (self.last_name, self.first_name, self.DOB) 

class InpatientForm(ModelForm): 
    class Meta: 
     model = Inpatient 

# inpatients/views.py 

from django.http import HttpResponse, HttpResponseRedirect 
from django.shortcuts import render_to_response 
from django.views.generic import DetailView 
from portal.inpatients.models import * 

def formtest(request): 
    if request.method == 'POST': 
     form = InpatientForm(request.POST) 
     if form.is_valid(): 
      form.save() 
      return HttpResponseRedirect('/inpatients') 
    else: 
     form = InpatientForm() 
    return render_to_response("formtest.html", {'form': form}) 

class FormDetailView(DetailView): 
    model=Inpatient 
    context_object_name='inpatient' # defines the name in the template 
    template_name_field='inpatient_list_page.html' 

    def get_object(self): 
     inpatient=super(FormDetailView,self).get_object() 
     form=InpatientForm(instance=inpatient) 
     return form 

    def get_template_names(self): 
     return ['inpatient_list_page.html',] 

작동
#urls.py 

from django.conf.urls.defaults import patterns, include, url 
from django.views.generic import ListView 
from portal.inpatients.models import Inpatient, InpatientForm 
from portal.inpatients.views import FormDetailView 

urlpatterns = patterns('', 
    (r'^formtest/$','portal.inpatients.views.formtest'), 
    (r'^inpatients/$', ListView.as_view(
     model=Inpatient, template_name='inpatient_list_page.html')), 
    (r'^inpatient-detail/(?P<pk>\d+)/$', FormDetailView.as_view()), 
) 

# with a template containing 

{% block content %} 
    <h2>Inpatients</h2> 
    <ul> 
     {% for aninpatient in object_list %} 
      <li><a href='/inpatient-detail/{{ aninpatient.id }}/'> 
      {{ aninpatient }}, id={{ aninpatient.id }}</a></li> 
     {% endfor %} 
    </ul> 
    {{ inpatient.as_p }} 
{% endblock %} 
# Yeah, kind of hokey. The template is for both the list view and detail view. 
# Note how the form is rendered with one line - {{ inpatient.as_p }} 

이있는 경우. 클래스 기반 일반 뷰를 사용하는 방법은 https://docs.djangoproject.com/en/1.3/topics/class-based-views/에 있습니다. 지침이 매우 명확합니다. 일을 만들기위한 열쇠는 get_object를 다시 정의하는 것입니다. "추가 작업 수행"절의 문서에서이 작업을 수행하는 방법, get_object의 원래 버전을 호출하는 단계 및 추가 작업을 설명합니다. 내가 깨달은 비트는 반환 객체가 ModelForm 객체가 될 수 있다는 것입니다. get_object가 반환하는 객체는 렌더링에서 템플릿으로 바로갑니다. 검색된 입원 객체를 가져 와서 InpatientForm을 통해 실행하면보기로 양식으로 전달되어 양식을 렌더링 할 수 있습니다.

버그 : DetailView의 버그는 get_template_names 함수가 존재하지 않는 구조에서 템플릿 이름을 만들려고한다는 것입니다. 라인 https://code.djangoproject.com/browser/django/trunk/django/views/generic/detail.py 에서 140-127 우리 SingleObjectTemplateResponseMixin.get_template_names 내에 가지고

127  # The least-specific option is the default <app>/<model>_detail.html; 
128   # only use this if the object in question is a model. 
129   if hasattr(self.object, '_meta'): 
130    names.append("%s/%s%s.html" % (
131     self.object._meta.app_label, 
132     self.object._meta.object_name.lower(), 
133     self.template_name_suffix 
134   )) 
135   elif hasattr(self, 'model') and hasattr(self.model, '_meta'): 
136    names.append("%s/%s%s.html" % (
137     self.model._meta.app_label, 
138     self.model._meta.object_name.lower(), 
139     self.template_name_suffix 
140   )) 

오류가 라인 (131)상의 코드를 실행 및 < 'ModelFormOptions'오브젝트가 속성 'app_label를'없는 오류 메시지 죽는다 것을 >. 나는 _meta 객체가 정의되었다고 결론을 내린다. 문제는 ModelForm에서 Meta 클래스가 정의되었다는 것입니다. 그 메타는 아마도 예상되는 필드를 가지고 있지 않을 것입니다. 해결 방법은 get_template_names를 다시 작성하고 올바른 템플리트를 리턴하는 것입니다.

Django와 Python을 처음 사용했습니다. 이전 질문에 대한 질문에 기고자들의 답변과 의견을 보내 주시면 감사하겠습니다. ( Putting links in list_detail.object_list to list_detail.object_detail, Using form in object_detail, Rolling your own generic views in Django)

나는 버그를보고하려면 어떻게해야합니까?

+0

나는 이것이 버그라고 생각하지 않으며'get_object'는 항상'ModelForm' 인스턴스가 아닌 모델 인스턴스를 리턴해야한다고 생각합니다. [편집 CBV] (https://docs.djangoproject.com/en/dev/ref/class-based-views/#editing-views)를 사용해보십시오. –

+0

여러 가지 이유로 버그라고 생각합니다. 설명서에 그것이 유효하지 않다고하지는 않습니다. 할당 전에 실제 필드가 아닌 _meta가 있는지 테스트하기 전에 유효한 데이터를 테스트합니다. 템플릿을 찾는 루틴이 템플릿을 찾지 못했습니다. 또한, 자신을 반복하지 마십시오의 교장에, ModelForm은 렌더링을위한 템플릿으로 전달 될 수 있어야합니다. – kd4ttc

답변

2

당신이 옳다고 생각합니다. 이것은 ModelForm과 모델 모두 _meta 속성을 가지고 있다는 사실에서 비롯된 버그입니다._meta 특성을 포함하는 get_object()에서 개체가 반환 될 때마다 동일한 버그가 발생합니다.

get_object은 Model 인스턴스를 반환 할 필요가 없습니다. 당신은 DetailView의 소스보고하고 문서화 문자열있어 읽는하여 확인할 수 있습니다 :

class DetailView(SingleObjectTemplateResponseMixin, BaseDetailView): 
    """ 
    Render a "detail" view of an object. 

    By default this is a model instance looked up from `self.queryset`, but the 
    view will support display of *any* object by overriding `self.get_object()`. 
    """ 

공지 사항을 문서화 문자열이 명시 적으로 객체가 self.get_object을 재정 지원하는 것을 말한다().

확실한 증거 중 하나는 get_template_names methodSingleObjectTemplateResponseMixin 인 버그 자체가 발생한 위치입니다.

# The least-specific option is the default <app>/<model>_detail.html; 
    # only use this if the object in question is a model. 
    if hasattr(self.object, '_meta'): 
     names.append("%s/%s%s.html" % (
      self.object._meta.app_label, 
      self.object._meta.object_name.lower(), 
      self.template_name_suffix 
     )) 
    elif hasattr(self, 'model') and hasattr(self.model, '_meta'): 
     names.append("%s/%s%s.html" % (
      self.model._meta.app_label, 
      self.model._meta.object_name.lower(), 
      self.template_name_suffix 
     )) 

이 코드를 다시 살펴보면, 주석 자체는 "해당 객체가 모델 일 경우"라고 말합니다. 이 주석에서 우리는 객체가 항상 모델 일 필요는 없다고 추론 할 수 있습니다.

그러나 누군가가 모델을 편집/생성/삭제할 수있는보기를 만들려면 FormView, CreateView, EditView 및 DeleteView가 포함 된 편집보기를 실제로 살펴야합니다. https://docs.djangoproject.com/en/1.3/ref/class-based-views/#editing-views에서 자세한 내용을 볼 수 있습니다.

버그를 신고하는 방법에 대한 질문에 대답하려면 https://docs.djangoproject.com/en/1.3/internals/contributing/#reporting-bugs에 설명 된 지침을 따라야합니다.

+0

편집/삭제 문제에 동의합니다. 편집/삭제 기능을 불러 오려면 해당 페이지의 컨트롤을 따라 가면서 자동 디스플레이를 구상합니다. 물론 제네릭 뷰를 최대한 많이 사용하겠습니다. 귀하의 허락을 받아 들여야한다는 것에 대해 감사드립니다. Django가 많은 프로젝트의 길을 간다면 추가 복잡성이 추가되고 임계점에 도달하면 더 간단하고 더 큰 기능을 제공 할 수 있습니다. 이미 기능 기반에서 클래스 기반으로 넘어갔습니다. 나는 장고가 이미 그것을 많이 통과했다 확신합니다. 고마워, Steve – kd4ttc

+0

여전히 버그라고 확신하지 못합니다. 'DetailView'는'FormView'가 더 적절한 곳에 사용하면 안됩니다. 'get_template_names'에 대해서는'isinstance'로 테스트했을 수도 있습니다.이 경우 템플리트 이름을 알아 내기 위해 Model 인스턴스를 리턴해야합니다. 이렇게하면'_meta'로 무엇이든 반환 할 수 있고 템플릿 이름을 얻을 수 있습니다. 양식 제외. 폼 뷰를 사용해야합니다. –

+0

이것은 모델이 아닌 _meta 인스턴스가있는 모든 클래스에서 발생하기 때문에 버그입니다. 폼 클래스 일 필요는 없습니다 (FormView를 사용하는 것이 더 적절합니다). –