Home > Software design >  CSRF token missing or incorrect - using auto-complete light in Django
CSRF token missing or incorrect - using auto-complete light in Django

Time:12-11

Running into CSRF_Token missing or incorrect in my Django-app, don't really understand what the issue is as I've included the {% csrf_token %} in any possible form being rendered by my template. I suspect it may have to do with the ajax requests that are done within the form to retrieve area-names and more, maybe someone can tell me what the issue is. I'm using autocomplete-light for retrieving some data from my DB, don't know if that can play a part in this. I've tried searching around online but haven't found a solution that seems to apply to my problem.

Views.py

Class BreedAutocomplete(autocomplete.Select2QuerySetView):

    def get_queryset(self):

        if not self.request.user.is_authenticated:
            return DogBreeds.objects.none()

        qs = DogBreeds.objects.all()

        if self.q:
            qs = qs.filter(name__istartswith=self.q)

        return qs


class AdListTakeMyDog(generic.ListView):
    model = Advertisement
    context_object_name = 'ads'
    template_name = 'core/advertisement_list_take.html'

    def get_queryset(self):
        queryset = Advertisement.objects.filter(is_offering_own_dog=True)
        return queryset


class AdListGetMeADog(generic.ListView):
    model = Advertisement
    context_object_name = 'ads'
    template_name = 'core/advertisement_list_get.html'

    def get_queryset(self):
        queryset = Advertisement.objects.filter(is_offering_own_dog=False)
        return queryset


class NewAdTakeMyDog(CreateView):
    model = Advertisement
    form_class = NewAdTakeMyDogForm
    success_url = reverse_lazy('view_ads_take_my_dog')
    template_name = 'core/advertisement_form_take.html'

    def form_valid(self, form):
        form.instance.author = self.request.user
        form.instance.is_offering_own_dog = True
        return super().form_valid(form)


class NewAdGetMeADog(CreateView):
    model = Advertisement
    form_class = NewAdGetMeADogForm
    success_url = reverse_lazy('ad_changelist')
    template_name = 'core/advertisement_form_get.html'

    def form_valid(self, form):
        form.instance.author = self.request.user
        form.instance.is_offering_own_dog = False
        return super().form_valid(form)

advertisement_create - TEMPLATE

{% extends '_base.html' %}

{% load static %}

{% block content %}
  <body onl oad="hide_area_field()">
    

  {% block form_title %}
  <h2>Ny annons</h2>
  {% endblock form_title %}

      
  {% if form.is_multipart %}
    <form method="post" enctype="multipart/form-data" id="adForm" data-municipalities-url="{% url 'ajax_load_municipalities' %}" data-areas-url="{% url 'ajax_load_areas' %}" novalidate>
    {% csrf_token %}  

  {% else %}
    <form method="post" id="adForm" data-municipalities-url="{% url 'ajax_load_municipalities' %}" data-areas-url="{% url 'ajax_load_areas' %}" novalidate>
    {% csrf_token %}  
    
    {% endif %}
      

    <table>  
      {{ form.as_p }}
    </table>

    <button type="submit">Publicera annons</button>

  {{ form.media }}

  </form>

</body>
{% endblock content %}

{% block footer %}

  {% comment %} Imports for managing Django Autocomplete Light in form {% endcomment %}
  <script type="text/javascript" src="{% static 'admin/js/vendor/jquery/jquery.js' %}"></script>
  <link rel="stylesheet" type="text/css" href="{% static 'autocomplete_light/select2.css' %}" />
  <script type="text/javascript" src="{% static 'autocomplete_light/jquery.init.js' %}"></script>
  <script type="text/javascript" src="{% static 'autocomplete_light/autocomplete.init.js' %}"></script>
  <script type="text/javascript" src="{% static 'autocomplete_light/select2.js' %}"></script>
  <link rel="stylesheet" type="text/css" href="{% static 'autocomplete_light/vendor/select2/dist/css/select2.css' %}" />
  <script type="text/javascript" src="{% static 'autocomplete_light/vendor/select2/dist/js/select2.full.js' %}"></script>
  <script type="text/javascript" src="{% static 'autocomplete_light/forward.js' %}"></script>
  <script type="text/javascript" src="{% static 'admin/js/vendor/jquery/jquery.js' %}"></script>




  {% comment %} Functions for handling area selectors {% endcomment %}
  <script>
      function hide_area_field() {
        const area_selector = document.getElementById('id_area');
        area_selector.style.display = 'none';
      }

      /* Get URL for requesting list of municipalities & Areas */
      const baseURI = window.location.origin
      const municipality_url = document.getElementById('adForm')['attributes']['data-municipalities-url']['value']
      const area_url = document.getElementById('adForm')['attributes']['data-areas-url']['value']


      /* Get relevant objects from DOM */
      const province_selector = document.getElementById('id_province');
      const municipality_selector = document.getElementById('id_municipality');
      const area_selector = document.getElementById('id_area');

      /* Update municipalities when Province have been chosen */
      province_selector.addEventListener('change', (event) => {
        
        var xhr = new XMLHttpRequest();

        xhr.onload = function () {
          if (xhr.readyState === xhr.DONE) {
              if (xhr.status === 200) {
                  municipality_selector.innerHTML = xhr.response
              }
          }
        };

        xhr.open('GET',  baseURI   municipality_url, true);
        xhr.setRequestHeader('province', province_selector.value)
        xhr.send();

      });


      /* Update Areas when Municipiality have been chosen */
      municipality_selector.addEventListener('change', (event) => {
      
      var xhr = new XMLHttpRequest();

      xhr.onload = function () {
        if (xhr.readyState === xhr.DONE) {
            if (xhr.status === 200) {
                if (xhr.response.length > 58) {
                  area_selector.style.display = ''
                  area_selector.innerHTML = xhr.response
                } else {
                  area_selector.style.display = 'none'
                }
            }
        }
      };

      xhr.open('GET',  baseURI   area_url, true);
      xhr.setRequestHeader('municipality', municipality_selector.value)
      xhr.send();

    });
  </script>

{% endblock footer %}

forms.py

class NewAdTakeMyDogForm(forms.ModelForm):

    breed = forms.ModelChoiceField(
        queryset=DogBreeds.objects.all(),
        widget=autocomplete.ModelSelect2(url='breed-autocomplete')
    )

    class Meta:
        model = Advertisement
        fields = ('province', 'municipality', 'area', 'title', 'description', 'days_per_week', 'size_offered', 'breed', 'image1', 'image2', 'image3')

    def __init__(self, *args, **kwargs):
        super(NewAdTakeMyDogForm, self).__init__(*args, **kwargs)
        self.fields['municipality'].queryset = Municipality.objects.none()
        self.fields['area'].queryset = Area.objects.none()
        self.fields['area'].required = False

        if 'province' in self.data:
            try:
                # Set municipality queryset
                province_id = int(self.data.get('province'))
                self.fields['municipality'].queryset = Municipality.objects.filter(province_id=province_id).order_by('name')
            
                # Set area queryset
                municipality_id = int(self.data.get('municipality'))
                self.fields['area'].queryset = Area.objects.filter(municipality_id=municipality_id).order_by('name')
                

            except (ValueError, TypeError):
                pass # invalid input from the client; ignore and fallback to empty Municipality/Area queryset
            

CodePudding user response:

Your AJAX request doesn't contain the CSRF token. So Django's cross site request forgery protection kicks in.

Django documentation explains in detail how to acquire the CSRF token when you send an AJAX POST request and how to include it in the headers of your request.

CodePudding user response:

The error was that I was looking at the wrong template, I have multiple template with inheritance, and had got them mixed up, so I though I was presenting a CSRF token in the form, but it was done in a template that wasn't used. Lesson learned - have one BASE template which you start from and only use blocks for essential code that changes between the base-template.

  • Related