【问题标题】:Handle form submission in bootstrap modal with ajax and class based views使用 ajax 和基于类的视图在引导模式中处理表单提交
【发布时间】:2017-04-25 08:14:24
【问题描述】:

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

.

我的代码有 2 个问题:

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

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();
            });
        });
    };

我已经阅读了关于在 js 文件上使用成功:& 错误:但不知道如何在视图中没有适当的“返回”的情况下使用它

【问题讨论】:

  • 您在上下文中究竟在哪里设置project 变量?
  • 刚刚编辑了我的问题,在views.py中添加了ProjectDetail。我在该视图上下文中设置项目。

标签: javascript ajax django


【解决方案1】:

您需要有两种 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 函数一个用于获取(显示表单)一个用于发布(提交表单)

【讨论】:

  • 你能再具体一点吗?我不确定在我看来要返回什么。 return HttpResponse(data, content_type='application/json') else: return super(InviteCollaborator, self).form_invalid(collaborator_form) 这两行可以吗?如果表单无效,我如何在我的模式上呈现错误?我需要在我的 js 中添加更多代码来处理这些错误吗?
【解决方案2】:

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

  1. 更改您的 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" 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 中的表单转换为模态,第二个用于发送电子邮件。幸运的是,FormView 可以为我们做这一切! (我不知道你从哪里得到 project 变量)

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 创建 thw 包装器:

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

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 是个糟糕的选择...

【讨论】:

  • 刚刚编辑了我的问题,项目变量在另一个视图中,即我的“仪表板”,我要试试这个...谢谢。
猜你喜欢
  • 1970-01-01
  • 2017-05-20
  • 1970-01-01
  • 1970-01-01
  • 2022-01-10
  • 1970-01-01
  • 1970-01-01
  • 2021-12-23
  • 1970-01-01
相关资源
最近更新 更多