小梅の日記帳

覚書き、メモ、等々残していくつもりです。

FormViewの継承関係を見てみる

継承先が見れるようになったので確認してみる。 ProcessFormViewは、CreateViewや、FormViewを継承しているBaseCreateViewを継承しているクラス。 ややこしい。

getが呼び出される時、get_context_data()が動作してそれを返しているのが分かる。

FormViewはBaseFormViewとTemplateResponseMixinを継承。

class FormView(TemplateResponseMixin, BaseFormView):
    """A view for displaying a form and rendering a template response."""

この2つのクラスを見てみる。

class BaseFormView(FormMixin, ProcessFormView):
    """A base view for displaying a form.""" 

ProcessFormViewを見てみると、getが呼び出された時には、get_context_data()が呼び出され、コンテキストを取得した後で、render_to_response関数が走っていることが分かる。 get_context_data()はというと、FormMixinの中にある。

class ProcessFormView(View):                                                                                                                                                                                       
    """Render a form on GET and processes it on POST."""
 Getメソッドが呼び出される。                                                                                                                                                           
    def get(self, request, *args, **kwargs):                                                                                                                                                                       
        """Handle GET requests: instantiate a blank version of the form."""
  ※空のフォームで初期化している。
   render_to_responseはTemplateResponseMixinのrender_to_responseを呼び出している。                                                                                                                                       
        return self.render_to_response(self.get_context_data())                                                                                                                                                    
    
 Postメソッドが呼び出される。                                                                                                                                                                                                               
    def post(self, request, *args, **kwargs):                                                                                                                                                                      
        """                                                                                                                                                                                                        
        Handle POST requests: instantiate a form instance with the passed                                                                                                                                          
        POST variables and then check if it's valid.                                                                                                                                                               
        """
        渡されたPOST変数でフォームを初期化して、それをバリデーションチェックしている。
        
  ※ここでformを取得している。                                                                                                                                                                                        
        form = self.get_form()                                                                                                                                                                                     
        
        ※バリデーションを実施
   if form.is_valid():                                                                                                                                                                                        
            return self.form_valid(form)                                                                                                                                                                           
        else:                                                                                                                                                                                                      
            return self.form_invalid(form)                                                                                                                                                                         
                                                                                                                                                                                                                   
    # PUT is a valid HTTP verb for creating (with a known URL) or editing an                                                                                                                                       
    # object, note that browsers only support POST for now.                                                                                                                                                        
    def put(self, *args, **kwargs):                                                                                                                                                                                
        return self.post(*args, **kwargs)

この中でgetメソッド実行時のget_context_data()が走っている。

class FormMixin(ContextMixin):                                                                                                                                                                                     
    """Provide a way to show and handle a form in a request."""                                                                                                                                                    
    initial = {}                                                                                                                                                                                                   
    form_class = None                                                                                                                                                                                              
    success_url = None                                                                                                                                                                                             
    prefix = None                                                                                                                                                                                                  
                                                                                                                                                                                                                   
    def get_initial(self):                                                                                                                                                                                         
        """Return the initial data to use for forms on this view."""                                                                                                                                               
        return self.initial.copy()                                                                                                                                                                                 
                                                                                                                                                                                                                   
    def get_prefix(self):                                                                                                                                                                                          
        """Return the prefix to use for forms."""                                                                                                                                                                  
        return self.prefix                                                                                                                                                                                         
                                                                                                                                                                                                                   
    def get_form_class(self):                                                                                                                                                                                      
        """Return the form class to use."""                                                                                                                                                                        
        return self.form_class                                                                                                                                                                                     
                                                                                                                                                                                                                   
    def get_form(self, form_class=None):                                                                                                                                                                           
        """Return an instance of the form to be used in this view."""                                                                                                                                              
        if form_class is None:                                                                                                                                                                                     
            form_class = self.get_form_class()                                                                                                                                                                     
        return form_class(**self.get_form_kwargs())                                                                                                                                                                
                                                                                                                                                                                                                   
    def get_form_kwargs(self):                                                                                                                                                                                     
        """Return the keyword arguments for instantiating the form."""                                                                                                                                             
        kwargs = {                                                                                                                                                                                                 
            'initial': self.get_initial(),                                                                                                                                                                         
            'prefix': self.get_prefix(),                                                                                                                                                                           
        }                                                                                                                                                                                                          
                                                                                                                                                                                                                   
        if self.request.method in ('POST', 'PUT'):                                                                                                                                                                 
            kwargs.update({                                                                                                                                                                                        
                'data': self.request.POST,                                                                                                                                                                         
                'files': self.request.FILES,                                                                                                                                                                       
            })                                                                                                                                                                                                     
        return kwargs                                                                                                                                                                                              
                                                                                                                                                                                                                   
    def get_success_url(self):                                                                                                                                                                                     
        """Return the URL to redirect to after processing a valid form."""                                                                                                                                         
        if not self.success_url:                                                                                                                                                                                   
            raise ImproperlyConfigured("No URL to redirect to. Provide a success_url.")                                                                                                                            
        return str(self.success_url)  # success_url may be lazy

    def form_valid(self, form):                                                                                                                                                                                    
        """If the form is valid, redirect to the supplied URL."""                                                                                                                                                  
        return HttpResponseRedirect(self.get_success_url())                                                                                                                                                        
                                                                                                                                                                                                                   
    def form_invalid(self, form):
        この中で指定したformに値を入れてrender_to_responseで返している。                                                                                                                                                                                 
        """If the form is invalid, render the invalid form."""                                                                                                                                                     
        return self.render_to_response(self.get_context_data(form=form))                                                                                                                                           
                                                                                                                                                                                                                   
    def get_context_data(self, **kwargs):                                                                                                                                                                          
        """Insert the form into the context dict."""
  ※フォームを辞書型のコンテキストの中に挿入している。
                                                                                                                                                                 
        if 'form' not in kwargs:                                                                                                                                                                                   
            kwargs['form'] = self.get_form()
  ※引数の値を格納している。
  ※superクラスではextra_contextという変数へ格納しているだけ。                                                                                                                                                                       
        return super().get_context_data(**kwargs)
class TemplateResponseMixin:                                                                                                                                                                                       
    """A mixin that can be used to render a template."""                                                                                                                                                           
    template_name = None                                                                                                                                                                                           
    template_engine = None                                                                                                                                                                                         
    response_class = TemplateResponse                                                                                                                                                                              
    content_type = None                                                                                                                                                                                            
    
                                                                                                                                                                                                                   
    def render_to_response(self, context, **response_kwargs):                                                                                                                                                      
        """                                                                                                                                                                                                        
        Return a response, using the `response_class` for this view, with a template rendered with the given context.                                                                                                                                                                                                                                                                  
        Pass response_kwargs to the constructor of the response class.                                                                                                                                             
        """                                                                                                                                                                                                        
        response_kwargs.setdefault('content_type', self.content_type)                                                                                                                                              
        return self.response_class(                                                                                                                                                                                
            request=self.request,                                                                                                                                                                                  
            template=self.get_template_names(),                                                                                                                                                                    
            context=context,                                                                                                                                                                                       
            using=self.template_engine,                                                                                                                                                                            
            **response_kwargs                                                                                                                                                                                      
        )                                                                                                                                                                                                          
                                                                                                                                                                                                                   
    def get_template_names(self):                                                                                                                                                                                  
        """                                                                                                                                                                                                        
        Return a list of template names to be used for the request. Must return                                                                                                                                    
        a list. May not be called if render_to_response() is overridden.                                                                                                                                           
        """                                                                                                                                                                                                        
        if self.template_name is None:                                                                                                                                                                             
            raise ImproperlyConfigured(                                                                                                                                                                            
                "TemplateResponseMixin requires either a definition of "                                                                                                                                           
                "'template_name' or an implementation of 'get_template_names()'")                                                                                                                                  
        else:                                                                                                                                                                                                      
            return [self.template_name] 
class ProcessFormView(View):
    """Render a form on GET and processes it on POST."""
    def get(self, request, *args, **kwargs):
        """Handle GET requests: instantiate a blank version of the form."""
        return self.render_to_response(self.get_context_data())

    def post(self, request, *args, **kwargs):
        """
        Handle POST requests: instantiate a form instance with the passed
        POST variables and then check if it's valid.
        """
        form = self.get_form()
        if form.is_valid():
            return self.form_valid(form)
        else:
            return self.form_invalid(form)

    # PUT is a valid HTTP verb for creating (with a known URL) or editing an
    # object, note that browsers only support POST for now.
    def put(self, *args, **kwargs):
        return self.post(*args, **kwargs) 

取り敢えず、render関連の関数とバリデーション関連の関数は別クラスになっていることが分かる。 POSTメソッドでは、バリデーションが通ったら、フォームの値をコンテキストへ詰めてrenderしているということがわかる。