A {% csrf_token %} was used in a template, but the context did not provide the value

I am following this code to create a formset (subform/nested form): example-inline-formsets |

django inline formeset with class based views and crispy forms

I don’t get any errors on the form or in my code. But when I try to save the form nothing saves and I remain on the same page. However in VS Code terminal I get the following message.

"C:\Users\Dane Miller\Dropbox\3. Personal\Software Development\1. Projects\1. Completed Projects\Django\HSSE_Mgt_System\HSSE_Solution\myvenv\lib\site-packages\django\template\defaulttags.py:65: UserWarning: A {% csrf_token %} was used in a template, but the context did not provide the value. This is usually caused by not using RequestContext. "A {% csrf_token %} was used in a template, but the context "

Can someone point me in the right direction. I have uploaded my code as reference:

models

class BBSO_Records(models.Model):

    COMPANY_OR_CONTRACTOR = (
        ('company', 'Company'),
        ('contractor', 'Contractor'),
       )

    severityLevel = (
        ('1', 'Level 1'),
        ('2', 'Level 2'),
        ('3', 'Level 3'),
       )
    
    severity_level = models.CharField(max_length=6, default= 3 , choices=severityLevel)
    date_recorded  = models.DateTimeField()
    observer_name_ID = models.ForeignKey(get_user_model(), on_delete=models.CASCADE, verbose_name="Observer Name")  # i need to double check how I would be handling this. 
    observer_department_ID =  models.ForeignKey(Observer_Department, on_delete=models.CASCADE, verbose_name="Observer Department")
    site_location_ID = models.ForeignKey(Site_Locations, on_delete=models.CASCADE, verbose_name='Location of Observation')
    location_details = models.CharField(max_length=50, help_text='e.g. In the kitchen on the 4th floor.', blank=True)
    company_or_contractor = models.CharField(max_length=10, choices=COMPANY_OR_CONTRACTOR)
   
    number_of_persons_observed = models.IntegerField(default=1, validators=[MinValueValidator(0),
                                       MaxValueValidator(25)],verbose_name='# of Persons Observed')  #  https://stackoverflow.com/questions/849142/how-to-limit-the-maximum-value-of-a-numeric-field-in-a-django-model
    time_spent = models.IntegerField(verbose_name="Time Spent Observing (mins)")
    PTW = models.CharField(max_length=10, verbose_name="Permit To Work Number", blank=True)
    JSA = models.CharField(max_length=10,verbose_name="Job Safety Analysis Number", blank=True)
    details_of_observation  = models.TextField()
    date_created = models.DateTimeField(auto_now_add=True, editable=True)  # setting editable equal=False wouldnot make this contorl show on the form
    date_updated = models.DateTimeField(auto_now=True, editable=True)
    
    def __str__(self) :
        return self.details_of_observation

    def get_absolute_url(self):
        return reverse ('bbso_records_detail', args=[str(self.id)])
 

    class Meta:
        ordering = ["-date_created"]
        verbose_name_plural = "BBSO_Records" 
       

class BBSO_Record_Actions(models.Model):    
    bbso_record_ID = models.ForeignKey(BBSO_Records, on_delete=models.CASCADE, verbose_name="BBSO Record", related_name='relatednameBBSO_Records')
    classification_code_ID = models.ForeignKey(Classification_Code, on_delete=models.CASCADE)
    recommended_action = models.TextField(verbose_name='Recommended Action') # models.CharField(max_length=300)
    # closed_action = models.TextField(max_length=300, blank=True, help_text='Enter if the closed actions are different from the Recommended Actions')
    assigned_to = models.ForeignKey(get_user_model(), on_delete=models.CASCADE, verbose_name='Assigned To')
    date_closed = models.DateField(blank=True)
    date_created = models.DateTimeField(auto_now_add=True, editable=True) # editable=True causes the field not to show on a form.
    
    def __str__(self):
        return self.recommended_action

    class Meta:
        ordering = ["-date_created"]
        verbose_name_plural = "BBSO_Record_Actions"

forms

# REFERENCES
# https://stackoverflow.com/questions/6536373/how-can-i-set-the-size-of-rows-columns-in-textfield-in-django-models
# https://dev.to/zxenia/django-inline-formsets-with-class-based-views-and-crispy-forms-14o6/comments

class BBSO_RecordsForm(forms.ModelForm):

    class Meta:
        model = BBSO_Records
        fields = '__all__'
        widgets = { 'date_recorded': DateTimePickerInput(options={"showClose": True,"showClear": True,"showTodayButton": True,}), }  # https://pypi.org/project/django-bootstrap-datepicker-plus/ 
        # exclude = ['date_created', 'date_updated']

    def __init__(self, *args, **kwargs):
        super(BBSO_RecordsForm, self).__init__(*args, **kwargs)
        self.helper = FormHelper()
        self.helper.form_tag = True
        self.helper.form_class = 'form-horizontal'
        self.helper.label_class = 'col-md-3 create-label'
        self.helper.field_class = 'col-md-9'
        self.helper.layout = Layout(
            Div(
                Field('severity_level'),
                Field('date_recorded'),  #   css_class='form-group'
                Field('observer_department_ID'),
                Field('site_location_ID'),
                Field('location_details'),
                Field('company_or_contractor'),
                Field('number_of_persons_observed'),
                Field('PTW'),
                Field('JSA'),
                Field('details_of_observation'),
                TabHolder(
                    Tab('SOS Actions', 
                        Fieldset('Add SOS Actions', Formset('bbso_record_actions')),
                        # Div('field_name_2')
                    ),
                    Tab('Second Tab',
                        # Field('field_name_3', css_class="extra")
                    ),
                ),
                # Fieldset('Add SOS Actions', Formset('bbso_record_actions')),
                HTML("<br>"),
                ButtonHolder(Submit('submit', 'Save')),
            )
        )


class BBSO_Record_ActionsForm(ModelForm):

    class Meta:
        model = BBSO_Record_Actions
        fields = '__all__'
        # exclude = ()
        widgets = { 'recommended_action': Textarea(attrs={'rows':2, 'cols':25}), 
                    'date_closed': DatePickerInput(options={"showClose": True,"showClear": True,"showTodayButton": True,}),
        }

    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)

        formtag_prefix = re.sub('-[0-9]+
```, '', kwargs.get('prefix', ''))

        self.helper = FormHelper()
        self.helper.form_tag = False
        self.helper.layout = Layout(
            #  styling the formset
            #  https://github.com/sibtc/advanced-crispy-forms-examples/blob/master/mysite/core/forms.py
                
                # HTML("<hr size='8' color='4DDA2A'>"),
                Row(
                    Column('classification_code_ID',css_class='form-group col-md-2 mb-0'),
                    Column('recommended_action',css_class='form-group col-md-5 mb-0' ),
                    Column('assigned_to', css_class='form-group col-md-2 mb-0'),             
                    Column('date_closed', css_class='form-group col-md-2 mb-0'),
                    Column('DELETE'),  # because of the dynmic inline formset
                      css_class='formset_row-{}'.format(formtag_prefix)
                    #   wrapper_class='form-row'
                      ),
              
            )
        
        # self.helper.template = 'bootstrap/table_inline_formset.html'

BBSO_Record_ActionsFormset = inlineformset_factory(BBSO_Records, 
                                      BBSO_Record_Actions,                                    
                                      fields = ['classification_code_ID',
                                                'recommended_action',
                                                'assigned_to',
                                                'date_closed' ],
                                      form = BBSO_Record_ActionsForm,
                                      extra = 2,

views

class BBSO_RecordsDetailView(DetailView):
    model = BBSO_Records
    template_name = 'sos/bbso_records/bbso_record_detail.html'
    fields = ('date_recorded', 'observer_department_ID', 'site_location_ID', 
            'location_details', 'company_or_contractor','number_of_persons_observed', 'time_spent', 
            'PTW', 'JSA', 'details_of_observation')

    def get_context_data(self, **kwargs):
        context = super(BBSO_RecordsDetailView, self).get_context_data(**kwargs)
        return context


class BBSORecord_NestedForm_CreateView(CreateView):  # main form and nested form for BBSO Records
    model  = BBSO_Records
    template_name = 'sos/bbso_records/bbso_record_create.html' # 'sos/bbso_records/bbso_record_nested_new.html'
    form_class = BBSO_RecordsForm
    # fields = ('date_recorded','time_of_observation', 'observer_department_ID', 'site_location_ID', 
    #         'location_details', 'company_or_contractor','number_of_persons_observed', 'time_spent', 
    #         'PTW', 'JSA', 'details_of_observation')
    # exclude = ('observer_name_ID')
    # success_url =  None #  reverse_lazy('home')

    def get_context_data(self, **kwargs):
        data = super(BBSORecord_NestedForm_CreateView, self).get_context_data(**kwargs)
        if self.request.POST:
            data['bbso_record_actions'] = BBSO_Record_ActionsFormset(self.request.POST)
        else:
            data['bbso_record_actions'] = BBSO_Record_ActionsFormset()
        return data

    def form_valid(self, form):
        context = self.get_context_data()
        bbso_record_actions = context['bbso_record_actions']
        with transaction.atomic():
            form.instance.observer_name_ID = self.request.user  # add the logged on user to the record. 
            self.object = form.save()

            if bbso_record_actions.is_valid():
               bbso_record_actions.instance = self.object               
               bbso_record_actions.save()

        return super(BBSORecord_NestedForm_CreateView, self).form_valid(form)

    def get_success_url(self):
        # return reverse_lazy('bbso_records_detail', kwargs={'pk': self.object.pk})
        return reverse_lazy('bbso_records_detail', kwargs={'pk': self.object.pk})

template

{% extends "base.html" %}
{% load crispy_forms_tags %}
{% load static %}

{% block extrahead %}   {# Extra Resources Start #}
{{ form.media }}        {# Form required JS and CSS #}
{% endblock %}          {# Extra Resources End #}

{% block content %}


<div class="container">
    <div class="card">
        <div class="card-header">
            SOS Data Entry Form 
        </div>
        <div class="card-body">
             {% crispy form %}
         </div>
    </div>
</div>

{% endblock content %}

base template

<!DOCTYPE html>
{% load static %}
<html>

<head>

    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">

    <title>{% block title %}INSPINIA | Main view {% endblock title %}</title>

   {% load bootstrap4 %}       {# imports bootstrap3 #}
   {% bootstrap_css %}         {# Embeds Bootstrap CSS #}
   {% bootstrap_javascript jquery='full' %}  {# Embeds Bootstrap JS #}
   {% block extrahead %}       {# Embeds Extra Resources #}
   {% endblock %}              {# Ends Extra Resources #}


   
</head>
<body>   
    <p><a href="{% url 'bbso_records_nested_new' %}">New Nested SOS </a></p>
   
                          {% block content %}

                        {% endblock content %}
                       
</body>
</html>

custom layout object

from crispy_forms.layout import LayoutObject, TEMPLATE_PACK
from django.shortcuts import render
from django.template.loader import render_to_string


###### Thanks!
###### https://stackoverflow.com/questions/15157262/django-crispy-forms-nesting-a-formset-within-a-form/22053952#22053952

class Formset(LayoutObject):
    template = "mycollections/formset.html"

    def __init__(self, formset_name_in_context, template=None):
        self.formset_name_in_context = formset_name_in_context
        self.fields = []
        if template:
            self.template = template


    def render(self, form, form_style, context, template_pack=TEMPLATE_PACK):
        formset = context[self.formset_name_in_context]
        return render_to_string(self.template, {'formset': formset})

formset

{% load crispy_forms_tags %}
{% load static %}

<style type="text/css">
    .delete-row {
      align-self: center;
    }
  </style>
 
  {{ formset.management_form|crispy }}

  {% for form in formset.forms %}
  
    {% for hidden in form.hidden_fields %}
      {{ hidden|as_crispy_field }}
    {% endfor %}
    {% crispy form %}
  {% endfor %}


<br>
<script src="//ajax.googleapis.com/ajax/libs/jquery/2.1.3/jquery.min.js"></script>
<script src='{% static "mycollections/libraries/django-dynamic-formset/jquery.formset.js" %}'></script>
<script type="text/javascript">
    $('.formset_row-{{ formset.prefix }}').formset({
        addText: 'Add Row',
        deleteText: 'Delete',
        prefix: '{{ formset.prefix }}',
    });
</script>

The value for csrf_token is supplied from ‘django.middleware.csrf.CsrfViewMiddleware’,
which needs to be included in the middleware portion of your settings.py file. Is that present?

(I don’t see in anything you’ve posted where you’re using {% csrf_token %}. Is the reference to {% csrf_token %} in another file that you haven’t shown here?)

Good day Ken and thanks for responding.

  1. Yes, my middleware has the portion included as you noted
  2. If you look at the code snippet (https://github.com/zxenia/example-inline-formsets/tree/master/mycollections) I am using it does not indicate to use {% csrf_token %}.

I appreciate your thoughts.

Yep, I see where you’re not explicitly using it, however, crispy forms by default, does.

The CSRF docs, point #3 specifically identifies the reason behind this error message.
The crispy docs for the helper class shows that there is an option for disabling the automatic addition of the csrf token when rendering a crispy form. Making a guess here, I’d say you’d want to set this option for any of the nested forms within your page to ensure that the token is only rendered once in the form.

I see in your comments where you’re referencing an extremely old SO post. I suggest you be very cautious when attempting to find answers there. A big problem with SO is that answers quickly become obsolete with active projects being continuously developed. One needs to be very aware of the age of answers and what has changed over time.

I’d double check every line of code that you found on SO with the current docs to verify that you haven’t added something that isn’t currently valid.

Hi Ken,

Thanks so much for your help here as I find your guidance here instructive. What I might have to do is take your suggestion and now use dated code in my implementation. But when I search the internet those were the ones which were showing up.
Can I ask you a question then. What implementation do you use to get a nested form (subform) when creating your apps? I am looking for one where the formset (subform) has a button to dynamically add a new row?

I actually addressed something like this in a previous post, Multiples of one formset, which describes a situation where we have three levels of nested formsets.

Thanks much Ken. I will have a look at it.