首页 > 解决方案 > Django 表单 JSON

问题描述

请告诉我问题出在哪里:我需要处理一个 JSON 请求,我应该访问什么,我应该返回什么?这就是问题的本质,因为我在服务器上得到了答案,令牌有问题。

联系人.html:

<form class="feedback__form" id="contact_form" role="form" action="{% url 'contact' %}" method="post">
  {% csrf_token %}
  <div class="feedback__inv-msg feedback__response-msg">
    <span> ERROR</span>
  </div>
  <div class="feedback__form-wrapper">
    <ul class="feedback__field-list">
      <li class="feedback__field-item">
        <div class="feedback__field-title txt txt_font_mp_regular txt_size_18"><span>YOUR NAME</span></div>
        <div class="feedback__field-inp">
          {{ contact_form.contact_name }}
        </div>
      </li>
      <li class="feedback__field-item">
        <div class="feedback__field-title txt txt_font_mp_regular txt_size_18"><span>YOUR MAIL</span></div>
    <div class="feedback__field-inp">
        {{ contact_form.contact_email }}
  </div>
  <li class="feedback__field-item">
    <div class="feedback__field-title txt txt_font_mp_regular txt_size_18"><span>YOUR PHONE</span></div>
<div class="feedback__field-inp">
    {{ contact_form.contact_phone }}
</div>
  <li class="feedback__field-item">
    <div class="feedback__field-title txt txt_font_mp_regular txt_size_18"><span>YOUR PROBLEM</span></div>
    <div class="feedback__field-inp">
      {{ contact_form.content }}
    </div>
  </li>
  <div class="feedback__controls">
    <button class="btn btn_compact feedback__sender" type="submit">SEND</button>
  </div>
  <div class="feedback__response">
  <div class="feedback__positive feedback__response-msg"><span>YOUR MESSAGE WAS SENT</span></div>
  <div class="feedback__negative feedback__response-msg"><span>YOUR MESSAGE WASNT SENT</span></div>
</div>
</form>


 <script type="text/javascript">
  class Form {
    constructor(){
      this.element = document.querySelector(`.feedback`)
      this.init()
      this.isValid = false
      this.values = {}
    }

    addClassesToImps(){
      for(let elem of this.element.querySelectorAll(`input`))
      elem.classList.add(`inp`)
      this.element.querySelector(`input[type="hidden"]`).classList.remove(`inp`)
    }

    getStructure(){
      this.addClassesToImps()
      this.form = this.element.querySelector(`.feedback__form`)
      this.inps = this.element.querySelectorAll(`.inp`)
      this.reqInps = this.element.querySelectorAll(`.inp[required]`)
      this.sender = this.element.querySelector(`.feedback__sender`)
    }

    handleValidityCheck(elem){
      if(!elem.checkValidity()){
        elem.classList.add(`inp_invalid`)
        this.isValid = false
      } else {
        elem.classList.remove(`inp_invalid`)
        elem.classList.add(`inp_valid`)
      }
    }

    handleSenderClick(e){

      e.preventDefault()

      this.isValid = true
      for(let elem of this.reqInps){
        this.handleValidityCheck(elem)
      }
      if(this.isValid){
        this.element.classList.remove(`feedback_inv`)

        this.values.name = this.element.querySelector(`.inp[name="contact_name"]`).value
        this.values.mail = this.element.querySelector(`.inp[name="contact_email"]`).value
        this.values.phone = this.element.querySelector(`.inp[name="contact_phone"]`).value
        this.values.text = this.element.querySelector(`.inp[name="content"]`).value

        async function postData(url = '', data = {}) {
          const response = await fetch(url, {
            method: 'POST', // *GET, POST, PUT, DELETE, etc.
            mode: 'cors', // no-cors, *cors, same-origin
            cache: 'no-cache', // *default, no-cache, reload, force-cache, only-if-cached
            credentials: 'same-origin', // include, *same-origin, omit
            headers: {
              'Content-Type': 'application/json'
              // 'Content-Type': 'application/x-www-form-urlencoded',
            },
            redirect: 'follow', // manual, *follow, error
            referrerPolicy: 'no-referrer', // no-referrer, *no-referrer-when-downgrade, origin, origin-when-cross-origin, same-origin, strict-origin, strict-origin-when-cross-origin, unsafe-url
            body: JSON.stringify(data) // body data type must match "Content-Type" header
          });
          return response.json(); // parses JSON response into native JavaScript objects
        }

        postData(``, this.values)
          .then(data => {
            console.log(data); // JSON data parsed by `response.json()` call
          });

      } else {
        this.element.classList.add(`feedback_inv`)
        return false
      }

    }

    init(){
      this.getStructure()
      console.log(this)
      this.sender.addEventListener(`click`, this.handleSenderClick.bind(this))
      for(let elem of this.inps){
        elem.addEventListener(`focusout`, this.handleValidityCheck.bind(this, elem))
      }

    }
  }

  let feedback = new Form()
</script>

表格.py:

class ContactForm(forms.Form):
    contact_name = forms.CharField(required=True)
    contact_email = forms.EmailField(required=True)
    contact_phone = forms.CharField(required=False)
    content = forms.CharField(
        required=True,
        widget=forms.Textarea(attrs={'id': 'my_field', 'class': 'feedback__textarea inp'})
    )

    # the new bit we're adding
    def __init__(self, *args, **kwargs):
        super(ContactForm, self).__init__(*args, **kwargs)
        self.fields['contact_name'].label = "Name:"
        self.fields['contact_email'].label = "Mail:"
        self.fields['contact_phone'].label = "Phone"
        self.fields['content'].label = "Your problem"

视图.py:

def contact(request):
    form_class = ContactForm

    if request.method == 'POST':
        form = form_class(data=request.POST)

        if form.is_valid():
            contact_name = request.POST.get(
                'contact_name'
            , '')
            contact_phone = request.POST.get(
                'contact_phone'
            , '')
            contact_email = request.POST.get(
                'contact_email'
            , '')
            form_content = request.POST.get('content', '')

            # Email the profile with the
            # contact information
            template = get_template('contact_template.txt')
            context = {
                'contact_name': contact_name,
                'contact_email': contact_email,
                'contact_phone': contact_phone,
                'form_content': form_content,
            }
            content = template.render(context)

            email = EmailMessage(
                "New message from form",
                content,
                '', ['mail@mail.com'],
                headers = {'Reply-To': contact_email }
            )
            email.send()
            return HttpResponse('')

在 urls.py 中:

...
path('contact/', views.contact, name='contact'),
...

在服务器控制台中:

Forbidden (CSRF token missing or incorrect.)
"POST / HTTP/1.1" 403

在浏览器控制台中:

SyntaxError: JSON.parse: unexpected character at line 2 column 1 of the JSON data

请不要推荐使用 jQuery 的选项,它在这个项目中被排除在外

标签: javascriptpythonjsondjango

解决方案


在您的脚本中,使用以下行获取 csrf 令牌值

var token = jQuery("[name=csrfmiddlewaretoken]").val();

当您向服务器发送数据时,请使用另外一个参数

headers: {'X-CSRFToken': token}

它将解决您的 csrf 错误并确保您在表单中定义了 {% csrf_token %}。


推荐阅读