Shan
Shan

Reputation: 23

Django form JSON

Please tell me where the problem is: I need to process a JSON request, what should I access and what should I return? and this is the essence of the problem, because the answer comes to me on the server, that there is a problem with the token.

contact.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>

forms.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"

views.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,
                '', ['[email protected]'],
                headers = {'Reply-To': contact_email }
            )
            email.send()
            return HttpResponse('')

in urls.py:

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

in server console:

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

in browser console:

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

Please do not recommend options using jQuery, its presence is excluded in this project

Upvotes: 0

Views: 63

Answers (1)

Sachin Singh
Sachin Singh

Reputation: 607

In your script take the csrf token value using the below line

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

and when you sending data to server use one more parameter

headers: {'X-CSRFToken': token}

It will resolve your csrf error and make sure in form you have defined {% csrf_token %}.

Upvotes: 1

Related Questions