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.