2013-06-05 3 views
2

그래서 등록 프로세스에 보안 질문을 구현 한 웹 응용 프로그램에서 작업하고 있습니다. 내 모델이 설정되는 방식과 Django의 클래스 기반 뷰 (CBV)를 사용하려고한다는 사실 때문에이 모든 것을 완벽하게 통합하는 데 문제가있었습니다.Django 클래스 기반보기 (CBV)에서 인라인 서식 저장

View.py

class AcctRegistration(CreateView): 
    template_name = 'registration/registration_form.html' 
    disallowed_url_name = 'registration_disallowed' 
    model = AcctUser 
    backend_path = 'registration.backends.default.DefaultBackend' 
    form_class = AcctRegistrationForm 
    success_url = 'registration_complete' 

def form_valid(self, form): 
    context = self.get_context_data() 
    securityquestion_form = context['formset'] 
    if securityquestion_form.is_valid(): 
     self.object = form.save() 
     securityquestion_form.instance = self.object 
     securityquestion_form.save() 
     return HttpResponseRedirect(self.get_success_url()) 
    else: 
     return self.render_to_response(self.get_context_data(form=form)) 

    def get_context_data(self, **kwargs): 
     ctx = super(AcctRegistration, self).get_context_data(**kwargs) 
     if self.request.POST: 
      ctx['formset'] = SecurityQuestionsInLineFormSet(self.request.POST, instance=self.object) 
      ctx['formset'].full_clean() 
     else: 
      ctx['formset'] = SecurityQuestionsInLineFormSet(instance=self.object) 
     return ctx 

그리고 : 여기

class AcctSecurityQuestions(models.Model): 
    class Meta: 
     db_table = 'security_questions' 
    id = models.AutoField(primary_key=True) 
    question = models.CharField(max_length = 250, null=False) 

    def __unicode__(self): 
     return u'%s' % self.question 


class AcctUser(AbstractBaseUser, PermissionsMixin): 
    ... 
    user_questions = models.ManyToManyField(AcctSecurityQuestions, through='SecurityQuestionsInter') 
    ... 


class SecurityQuestionsInter(models.Model): 
    class Meta: 
     db_table = 'security_questions_inter' 

    acct_user = models.ForeignKey(AcctUser) 
    security_questions = models.ForeignKey(AcctSecurityQuestions, verbose_name="Security Question") 
    answer = models.CharField(max_length=128, null=False) 

내 현재보기처럼 보이는 것입니다

Model.py : 여기 내 모델처럼 무엇인가 울부 짖음과 완전을 위해 나의 모양이 보이는 것 여기에서있다 :

Forms.py

class AcctRegistrationForm(ModelForm): 
    password1 = CharField(widget=PasswordInput(attrs=attrs_dict, render_value=False), 
          label="Password") 
    password2 = CharField(widget=PasswordInput(attrs=attrs_dict, render_value=False), 
          label="Password (again)") 

    class Meta: 
     model = AcctUser 

    ... 

    def clean(self): 
     if 'password1' in self.cleaned_data and 'password2' in self.cleaned_data: 
      if self.cleaned_data['password1'] != self.cleaned_data['password2']: 
       raise ValidationError(_("The two password fields didn't match.")) 
     return self.cleaned_data 


SecurityQuestionsInLineFormSet = inlineformset_factory(AcctUser, 
                 SecurityQuestionsInter, 
                 extra=2, 
                 max_num=2, 
                 can_delete=False 
                 ) 

이 게시물 그러나 선택한 대답의 가장 최근의 코멘트 나에게 많은 도움이 자사의 해당 formset 데이터를 얻을 오버라이드 (override)의 형태와 포스트에 통합해야한다고 언급 방법 :

django class-based views with inline model-form or formset

내 해당 formset에서 내 데이터에 추가 할 어떻게이 getpost을 overiding하고 있다면? 그리고 formset 데이터를 통해 루프를 호출하려면 어떻게해야합니까?

답변

11

인라인 형식은 데이터베이스에 이미 사용자 개체가있는 경우에 유용합니다. 그런 다음 초기화 할 때 올바른 보안 질문 등을 자동으로 미리로드합니다. 그러나 생성시에는 일반 모델 형식이 가장 좋을 것이고 사용자에게 연결되는 필드를 통과 테이블에 포함하지 않을 것입니다. 그런 다음 사용자를 만들고 생성 된 테이블에 사용자 필드를 수동으로 설정할 수 있습니다. 이 그것을 수행하는 방식으로 작동하는 이유에 대한 코멘트에 몇 가지 질문에 대해서는

forms.py: 

SecurityQuestionsFormSet = modelformset_factory(SecurityQuestionsInter, 
               fields=('security_questions', 'answer'), 
               extra=2, 
               max_num=2, 
               can_delete=False, 
               ) 

views.py: 

class AcctRegistration(CreateView): 

    # class data like form name as usual 

    def form_valid(self): 
     # override the ModelFormMixin definition so you don't save twice 
     return HttpResponseRedirect(self.get_success_url()) 

    def form_invalid(self, form, formset): 
     return self.render_to_response(self.get_context_data(form=form, formset=formset)) 

    def get(self, request, *args, **kwargs): 
     self.object = None 
     form_class = self.get_form_class() 
     form = self.get_form(form_class) 
     formset = SecurityQuestionsFormSet(queryset=SecurityQuestionsInter.objects.none()) 
     return self.render_to_response(self.get_context_data(form=form, formset=formset)) 

    def post(self, request, *args, **kwargs): 
     self.object = None 
     form_class = self.get_form_class() 
     form = self.get_form(form_class) 
     formset = SecurityQuestionsFormSet(request.POST) 
     form_valid = form.is_valid() 
     formset_valid = formset.is_valid() 
     if form_valid and formset_valid: 
      self.object = form.save() 
      security_questions = formset.save(commit=False) 
      for security_question in security_questions: 
       security_question.acct_user = self.object 
       security_question.save() 
      formset.save_m2m() 
      return self.form_valid() 
     else: 
      return self.form_invalid(form, formset) 

: 여기

내가 단지 모델의 formset 사용하여이 작업을 수행 할 방법

내가 할을 꽤 왜 우리가 질문 모음을 필요로하는지 이해하십시오.

queryset은 formset에 대한 개체의 편집 가능한 초기 범위를 정의합니다. 개별 폼의 instance 매개 변수와 유사하게 쿼리 세트 내의 각 폼에 바인딩되는 인스턴스 집합입니다. 그런 다음 쿼리 세트의 크기가 max_num 매개 변수를 초과하지 않는 경우 최대 max_num 또는 지정된 추가 항목 수인 extra 언 바운드 양식이 추가됩니다. 빈 쿼리 세트를 지정한다는 것은 모델 인스턴스를 편집하고 싶지 않다는 것을 의미하며 새로운 데이터를 만들고 싶다는 의미입니다.

기본 쿼리 세트를 사용하는 버전의 제출되지 않은 양식의 HTML을 검사하면 중간 행의 ID를 제공하는 숨겨진 입력이 표시됩니다. 또한 선택한 질문 및 답변이 비 필수 입력에 표시됩니다. 숨겨진 입력.

양식을 기본적으로 언 바운드 (인스턴스를 지정하지 않은 경우)하는 반면, 양식 세트는 기본적으로 전체 테이블에 바인딩되는 반면 (다른 방법을 지정하지 않는 한) 혼동하는 것은 논란의 여지가 있습니다. 코멘트가 보여 주듯이, 그것은 잠시 동안 확실히 나를 버렸다. 그러나 형식 세트는 본질적으로 단 하나의 형식이 아닌 복수 형태로되어 있습니다.

쿼리 세트를 제한하면 인라인 서식 세트에서 수행하는 작업 중 하나입니다.

또는 formset에 대해 acct_user를 설정하기 전까지 formset이 해당 양식을 어떻게 알고 있는지를 나타냅니다. 우리가 인스턴스 매개 변수를 사용하지 않은 이유는 무엇입니까?

실제로 formset은 관련이 있는지 결코 알지 못합니다. 결국 모델 필드를 설정하면 SecurityQuestionsInter 개체가 실행됩니다.

기본적으로 HTML 양식은 POST 데이터의 모든 필드 값 (두 개의 비밀번호와 두 개의 보안 질문 선택 및 사용자 응답)에이 필드와 관련이없는 기타 정보를 전달합니다 문제. 우리가 생성 한 각각의 파이썬 객체 (formformset)는 필드 ID와 formset 접두사를 기반으로 말할 수 있습니다 (기본 값은 여기서 잘 작동합니다. 하나의 페이지에서 여러 형식 세트가 더 복잡해집니다). POST 데이터의 어느 부분이 책임입니까? . form은 암호를 처리하지만 보안 질문에 대해서는 아무것도 모릅니다. formset은 두 가지 보안 질문을 처리하지만 비밀번호 (또는 암시 적으로 사용자)에 대해서는 아무 것도 모릅니다. 내부적으로 formset은 각각 하나의 질문/답변 쌍을 처리하는 두 개의 양식을 작성합니다. 다시 한 번 ID의 번호 매기기를 사용하여 처리하는 POST 데이터의 부분을 알려줍니다.

두 사람을 하나로 묶는 견해입니다. 어떤 형식이든 관계형에 대해 알지 못하지만 그 견해는 그렇지 않습니다.

인라인 formsets은 이러한 관계를 추적하기위한 여러 가지 특수한 동작을 가지고 있으며 더 많은 코드 검토 후에 보안 Q/A 쌍의 유효성을 검사하기 전에 사용자를 저장하지 않고도 여기에서 사용할 수있는 방법이 있다고 생각합니다. 인스턴스에 필터하는 내부 쿼리 세트이지만 실제로 유효성 검사를 위해 해당 쿼리 세트를 평가해야하는 것처럼 보이지는 않습니다. 그냥 대신 당신이 그들을 사용할 수 있고 사용자 형식이 유효하지 않은 경우 커밋되지 않은 사용자 개체 (즉, 반환 값 form.save(commit=False))를 instance 인수 또는 None 인수로 전달할 수 있다고 말하는 것을 피할 수있는 주요 부분은 내가 두 번째 경우에는 100 % 확신 할 수 없습니다. 당신이 명확하게 그 접근 방식이 찾을 경우 테스트 할 가치가있을 수도 있습니다 - 당신이 처음에 있었다으로 인라인의 formset을 설정 인수없이 get에 해당 formset 초기화, 모든 후 form_valid에 최종 저장 동작을 떠나 :

def form_valid(self, form, formset): 
    # commit the uncommitted version set in post 
    self.object.save() 
    form.save_m2m() 
    formset.save() 
    return HttpResponseRedirect(self.get_success_url()) 

def post(self, request, *args, **kwargs): 
    self.object = None 
    form_class = self.get_form_class() 
    form = self.get_form(form_class) 
    if form.is_valid(): 
     self.object = form.save(commit=False) 
    # passing in None as the instance if the user form is not valid 
    formset = SecurityQuestionsInLineFormSet(request.POST, instance=self.object) 
    if form.is_valid() and formset.is_valid(): 
     return self.form_valid(form, formset) 
    else: 
     return self.form_invalid(form, formset) 

양식이 유효하지 않을 때 원하는대로 작동하면 더 나은 버전으로 스스로 이야기했을 수 있습니다. 비 - 인라인 버전이하는 일만하면 처리가 숨겨집니다. 첫 번째로 다양한 generic mixins의 구현과 좀 더 가깝습니다. 비 저장 버전에서도 저장 동작을 form_valid으로 옮길 수는 있지만 말입니다.

+0

그래서 저는 장고를 처음 사용하기 때문에 인라인 formset이 필요한지 확신 할 수 없습니다. 할 일이 옳은 것 같았지만 둘 사이의 차이를 완전히 이해하지 못할 수도 있습니다. 나는 이것을 시험해보고 알려줄 것이다.''Base'와''get'' 함수의 시작 부분에''self.object = None'' 행을''BaseCreateView 이 함수가 상속받은''post''와'get' 함수는 무엇입니까? – BoogeyMarquez

+0

코드를 조금만 확인하면 데이터베이스에 이미 사용자 개체가있을 때 인라인 서식 세트를 사용하는 것이 편리하다고 생각합니다. 그런 다음 초기화 할 때 적절한 보안 질문 등을 자동으로 미리로드합니다. 생성시 일반 모델 집합이 가장 좋을 수 있으며 사용자에게 연결되는 필드를 통과 테이블에 포함하지 않는 것이 가장 좋습니다. 그런 다음 사용자를 만들고 생성 된 테이블에 사용자 필드를 수동으로 설정할 수 있습니다. 그리고, 예,'self.object'가 아마 초기화 될 것입니다. –

+0

피터, 대답은 거의 다 왔어. 최근 답변을 사용하고 있지만 중간 모델이 증가하지 않습니다. 내 모델이 어떻게 설정되었는지 알 수 있습니다. – BoogeyMarquez