使用ajax和基于类的视图处理bootstrap模式中的表单提交

时间:2017-04-25 08:14:24

标签: javascript ajax django

我使用django时很新,我已经在这个问题上陷入困境好几天了。 我有一个form.Form在我的模板上的bootstrap模式只有1个字段(email_field),基本上我需要通过ajax提交该表单,检查该电子邮件地址是否已在数据库中注册,然后发送邀请到该电子邮件和关闭模态。如果未注册电子邮件,则显示表单错误而不关闭模式。我尝试了不同的示例,但可以找到解决方案,因为示例不处理错误或表单不在模态中或不使用基于类的视图

我的代码存在两个问题:

  1. 如果表单有效或无效,我不知道在我的视图中返回什么,以及如何处理我的js代码中的错误以在模态上显示它们。(返回表单以呈现错误或JSON响应?)。
  2. 在第一次成功提交后,表单不能再次使用。(提交按钮的大小会更改,如果单击它会返回错误:CSRF令牌丢失或不正确)
  3. Form.py

    class CollaboratorForm(forms.Form):
    email_address = forms.EmailField(required=True,widget=forms.TextInput(attrs={'class': 'form-control focus-text-box', 'type': 'email',
         'placeholder': 'Enter email'}))
    
    def clean_email_address(self):
        email = self.cleaned_data['email_address']
        if not User.objects.filter(email=email):
            raise forms.ValidationError('This user is not registered')
        return email
    
    def sendEmail(self, datas):
        message = "Hello, " + datas['user_name']+" "+ datas['email_from'] + " invited you to collaborate in an existing project. Follow this link if you are interested " + datas['invitation_link']
        msg = EmailMessage('Invitation from ' + datas['user_name'],
                       message, to=[datas['email_to']])      
        msg.send()
    

    Template.html(project_detail.html)

    <script src="{% static '/experiments/js/invite_collaborator.js' %}"></script>
    
    <div class="bootstrap-modal modal fade in" id="collaboratorModal" style="display: none;">
        <div class="modal-body">
        <form  action="{% url 'experiments:invite-collaborator' project_id=project.id %}" method="post" id=collaborator-form >
          {% csrf_token %}
    
        <div class="form-group">
        {% if collaborator_form.errors %}
            <ol>
            {% for error in collaborator_form.errors %}
                <li><strong>{{ error|escape }}</strong></li>
            {% endfor %}
            </ol>
        {% endif %}
    
        <label class="control-label">Invite someone by email</label>
        <div class="input-group mt10">
        {{ collaborator_form }}
        <span class="input-group-btn">
        <input name="collaborator-commit" onClick="invite({{project.id}});" class="btn btn-primary" data-disable-with="Send Invitation" id="invite-button" type="submit">
        </span>
        </div>
        </div>
        </form>
        </div>
        </div>
    

    Url.py

    urlpatterns = [
        url(r'^(?P<project_id>[0-9]+)/invite_collaborator$', views.InviteCollaborator.as_view(), name='invite-collaborator'),
    ]
    

    View.py

    class ProjectDetail(DetailView):
        model = Project
        template_name = 'experiments/project_detail.html'
        pk_url_kwarg = 'project_id'
    
    
        def get_context_data(self, **kwargs):
            context = super(ProjectDetail, self).get_context_data()
            project = get_object_or_404(Project,pk=self.kwargs["project_id"])
            context["project"] = project
            context["collaborator_form"] = CollaboratorForm()
            return context
    
    class InviteCollaborator(FormView):
        form_class = CollaboratorForm
        template_name = 'experiments/project_detail.html'
    
        def post(self, request, *args, **kwargs):
                collaborator_form = CollaboratorForm(data=request.POST)
                project_id = request.POST['project_id']
                current_project = Project.objects.get(id=project_id)
                datas={}
                if collaborator_form.is_valid():
                    cleaned_data = collaborator_form.cleaned_data
                    email_address = cleaned_data.get('email_address')
                    user = User.objects.get(pk=request.user.id)
                    invitation_link = "http://exp.innovationhackinglab.com/projects/"+ str(current_project.id) + "/join/" + current_project.invitation_key
                    datas['user_name'] = user.first_name + ' ' + user.last_name
                    datas['email_from'] = user.email
                    datas['email_to'] = email_address
                    datas['invitation_link'] = invitation_link
                    collaborator_form.sendEmail(datas)
                    data = simplejson.dumps("Success")
                    return HttpResponse(data, content_type='application/json')
                else:
                    return super(InviteCollaborator, self).form_invalid(collaborator_form)
    

    invite_collaborator.js

    function invite(project_id) {
        $('#collaborator-form').submit(function(e) {
            e.preventDefault();
            $.ajax({
                data: $(this).serialize()+'&'+$.param({ 'project_id': project_id }),
                type: $(this).attr('method'),
                url: $(this).attr('action'),
                });
        $('#collaboratorModal').modal('toggle');
        $('#collaboratorModal').on('hidden.bs.modal', function () {
            $(this).find("input,textarea,select").val('').end();
                });
            });
        };
    

    我读过有关使用成功的信息:&amp;错误:在js文件上,但如果没有适当的&#34;返回&#34;则不知道如何使用它。在视图中

2 个答案:

答案 0 :(得分:0)

您需要有两个ajax方法,一个用于获取表单(作为原始html),另一个用于发布表单。您的视图中也会有相应的get和post方法。

get function of your view class:

def get(self, request, *args, **kwargs):

  form = CollaboratorForm()  
  return render(request,'template.html',{'form':form})

def post(self, request, *args, **kwargs):

  form = CollaboratorForm(request.POST)
  if form.is_valid():
     //save form
     //return whatever you want to show on successful form submission
  else:
     //return bound form as html with errors  
     return render(request,'template.html',{'form':form}) 

js functions

有两个单独的ajax函数,一个用于获取(显示表单)一个用于发布(提交表单)

答案 1 :(得分:0)

如果你想在服务器端使用模板,使用FormView和ajax,我建议将模板分成两部分 - 包装器和表单,只通过TemplateView加载包装器,然后用ajax获取表单。这允许您使用ajax发送表单并在包装器中放置响应(如带有错误的表单)。

  1. 更改您的HTML模板 - 将模态正文转到另一个文件,例如:
  2. <强> project_detail.html

    <script src="{% static '/experiments/js/invite_collaborator.js' %}"></script>
    
    <div class="bootstrap-modal modal fade in" id="collaboratorModal" style="display: none;">
        <div class="modal-body" id="collaboratorModalContent">        
        </div>
    </div>
    

    <强> project_detail_content.html

    <form  action="{% url 'experiments:invite-collaborator' project_id=project.id %}" method="post" id=collaborator-form >
              {% csrf_token %}
    
        <div class="form-group">
        {% if collaborator_form.errors %}
            <ol>
            {% for error in collaborator_form.errors %}
                <li><strong>{{ error|escape }}</strong></li>
            {% endfor %}
            </ol>
        {% endif %}
    
        <label class="control-label">Invite someone by email</label>
        <div class="input-group mt10">
            {{ collaborator_form }}
        <span class="input-group-btn">
        <input name="collaborator-commit" onClick="invite({{project.id}});" class="btn btn-primary" data-disable-with="Send Invitation" id="invite-button" type="submit">
        </span>
        </div>
        </div>
    </form>
    
    1. FormView应该处理GET和POST - 第一个将project_detail_content.html中的表单转换为modal,第二个用于发送电子邮件。幸运的是,FormView可以为我们做到这一切! (我不知道从哪里获得project变量)
    2. <强> View.py

      class InviteCollaborator(FormView):
          form_class = CollaboratorForm
          template_name = 'experiments/project_detail_content.html'
      
          def form_valid(self, form):
              # This method is called when valid form data has been POSTed.
              # It should return an HttpResponse.
              project_id = self.request.POST['project_id']
              current_project = Project.objects.get(id=project_id)
              datas={}
              cleaned_data = form.cleaned_data
              email_address = cleaned_data.get('email_address')
              user = User.objects.get(pk=request.user.id)
              invitation_link = "http://exp.innovationhackinglab.com/projects/"+ str(current_project.id) + "/join/" + current_project.invitation_key
              datas['user_name'] = user.first_name + ' ' + user.last_name
              datas['email_from'] = user.email
              datas['email_to'] = email_address
              datas['invitation_link'] = invitation_link
              form.sendEmail(datas)
              data = simplejson.dumps("Success")
              return HttpResponse(data, content_type='application/json')
      

      请注意几件事 - 我们使用FormView,因此对于GET请求,它将返回 project_detail_content.html 的内容与 CollaboratorForm ,并在POST时,相同的模板包含表单和错误如果表单无效,或者JSON带有Success消息。

      1. project_detail.html发生了什么?我们将使用TemplateView创建包装器:
      2. <强> Url.py

        urlpatterns = [
            url(r'^invite_collaborator$', TemplateView.as_view(template_name="project_detail.html")),
            url(r'^(?P<project_id>[0-9]+)/invite_collaborator/form$', views.InviteCollaborator.as_view(), name='invite-collaborator'),
        ]
        
        1. 最后,JS
        2. <强> invite_collaborator.js

          // In JS you need to make sure you fetch form from /project_id/invite_collaborator/form each time you show modal
          $(document).ready(function(e) {
              $('#collaboratorModalContent').load('invite_collaborator');
          });
          
          // Then, on submit we simply send data and handle response with success and error.
          // With our current View, invalid form will generate successful response with form and error, so we need to check 
          
          function invite(project_id) {
              $('#collaborator-form').submit(function(e) {
                  e.preventDefault();
                  $.ajax({
                      type: $(this).attr('method'),
                      url: $(this).attr('action'),
                      data: $(this).serialize()+'&'+$.param({ 'project_id': project_id }),
                      success: function ( response, status, xhr, dataType ) {
                          if( dataType === 'json' ){
                              //Make sure response is 'Success' and close modal
                              $('#collaboratorModal').modal('toggle');
                              $('#collaboratorModal').on('hidden.bs.modal', function () {
                                  $(this).find("input,textarea,select").val('').end();
                                      });
                                  });
                              };
                          }
                          else {
                              // It's not JSON, it must be HttpResposne with forms and errors, so it goes into modal's body
                              $('#collaboratorModalContent').html(response)
                          }
          
                      }
                  });
          

          我仍然不知道你在哪里以及如何设置project变量,所以也许TemplateView是不好的选择......