Django CSRF_TOKEN issue with Edge only

半城伤御伤魂 提交于 2021-02-10 15:47:07

问题


I'm trying my django application through different browsers (Chrome, Firefox, IE11 and Edge) and I got an issue with the csrf_token and Edge only.

This issue is in reference with my django form.

My view file :

class ManageDocView(AdminRequiredMixin, View):
    """ Render the Admin Manage documents to update year in the filename"""

    template_name = 'omcl/manage_doc_form.html'
    form_class = ManageDocForm
    success_url = 'omcl/manage_doc_form.html'

    @staticmethod
    def get_title():
        return 'Change Document Title'

    def get(self, request):
        form = self.form_class()
        context = {
            "form": form,
            "title": self.get_title()
        }
        return render(request, self.template_name, context)

    def post(self, request):
        form = self.form_class()
        query_document_updated = None
        query_omcl = None
        query_document = None

        if "submitButton" in request.POST:
            omcl_list = request.POST.get('omcl_list', False)
            query_omcl = Omcl.objects.get(id=omcl_list)
            query_document = Document.objects.filter(omcl=omcl_list)
            form.fields['omcl_list'].initial = query_omcl

        elif "UpdateDocument" in request.POST:
            checkbox_id = request.POST['DocumentChoice']
            checkbox_id_minus_1 = int(checkbox_id) - 1
            query_document_updated = Document.objects.get(id=checkbox_id)

            omclcode = query_document_updated.omcl.code
            src_filename = query_document_updated.src_filename
            filename, file_extension = os.path.splitext(src_filename)
            category = query_document_updated.category

            if category == "ANNUAL":
                category = "ANNUAL_REPORT"

            year = self.request.POST['pts_years']

            # Create the new document title updated by the new year
            new_document_title = f"{year}_{category}_{omclcode}_{checkbox_id_minus_1} - {src_filename}"

            # Create the new document file updated by the new year
            new_document_file = f"omcl_docs/{omclcode}/{year}_{category}_{omclcode}_{checkbox_id_minus_1}{file_extension}"

            # Get file.name in order to rename document file in /media/
            document_path = query_document_updated.file.name

            try:
                actual_document_path = os.path.join(settings.MEDIA_ROOT, document_path)
                new_document_path_temp = f"{settings.MEDIA_ROOT}/{new_document_file}"
                new_document_path = os.rename(actual_document_path, new_document_path_temp)
            except FileNotFoundError:
                messages.error(self.request, _(f"Document {src_filename} doesn't exist on the server"))
                return redirect('manage_doc')
            else:
                # Assign modifications to selected document and save it into the database
                query_document_updated.title = new_document_title
                query_document_updated.file = new_document_file
                query_document_updated.save()
                messages.success(self.request, _(f"The modification has been taken into account"))

        context = {
            'form': form,
            'query_omcl': query_omcl,
            'query_document': query_document,
            'query_document_updated': query_document_updated,
            'title': self.get_title(),
        }
        return render(request, self.template_name, context)

My forms file :

class ManageDocForm(forms.Form):

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

    omcl_list = forms.ModelChoiceField(
        queryset=Omcl.objects.filter(is_obsolete=False),
        label=_('OMCL Choice'),
        widget=ModelSelect2Widget(
            model=Omcl,
            search_fields=['code__icontains', 'name__icontains'],
            attrs={'data-placeholder': "Please select an OMCL"}
        )
    )

    now = datetime.today().year
    year_choices = ((i, str(i)) for i in range(now, now - 30, -1))
    pts_years = forms.ChoiceField(
        label='PTS years',
        choices=year_choices,
        required=True,
        widget=Select2Widget(
            attrs={'data-placeholder': "Please select a new year"}),
    )

My template file with a little part of javascript :

{% block extra_script %}
  <!-- Submit OMCL list with change and not submit button + Previous/Next pagination button -->
  <script>
    $('#select-omcl-form').on('change', function () {
      $(this).submit();
    });
  </script>
{% endblock %}

{% block main %}

  <h2>{{ title }}</h2>

  <div class="row manage-doc">

    <div class="col-md-12">
      <form id="select-omcl-form" name="select-omcl-form" action="" method="POST">
        {% csrf_token %}
        <fieldset>
          <legend><span class="name">{% trans 'Select an OMCL' %}</span></legend>
          {{ form.omcl_list }}
          <input type="hidden" name="submitButton">
        </fieldset>
      </form>
    </div>
  </div>
  <br/>

  <div class="row manage-doc">
    <div class="col-md-12">
      <fieldset>
        <legend><span class="name">{% trans 'Select a document' %}</span></legend>
        <form action="" method="POST">
          {% csrf_token %}
          <div id="table-document">
            <table id="document-table" class="table table-bordered table-striped table-condensed table_model">
              <thead>
              <tr>
                <th id="radio-column"></th>
                <th id="document-title-column">{% trans 'Document title' %}</th>
              </tr>
              </thead>
              <tbody>
              {% for document in query_document|dictsortreversed:'title' %}
                <tr>
                  <td><input type="radio" class="radio-document" id="document-radiobox" name="DocumentChoice"
                             value="{{ document.id }}"></td>
                  <td>{{ document.title }}</td>
                </tr>
              {% endfor %}
              </tbody>
            </table>
          </div>
          <br><br>

          <legend><span class="name">{% trans 'Select a new year' %}</span></legend>

          {{ form.pts_years }}

          <button class="btn btn-default" id="document-button" type="submit"
                  name="UpdateDocument">{% trans "Change year" %}</button>
        </form>
      </fieldset>
      <br>
    </div>
  </div>

{% endblock main %}

A gif presentation :

This is a little gif which explains the process and the issue according to csrf_token only with Edge browser :

Link to my gif

What I tried :

I tried to add CSRF_COOKIE_DOMAIN in my settings.py file but it doesn't work.

Do you have any idea ? It's pretty weird because I don't have any issue with others browsers. Ony with Microsoft Edge. Cookies are allowed in my browser.


回答1:


I found the issue thanks to my collegue. I used redirect but I had to use render because if I redirect, the CSRF_TOKEN is not actualized and it sends a second POST request with the previous token.

So it should be :

except FileNotFoundError:
    messages.error(self.request, _(f"Document {src_filename} doesn't exist on the server"))
    context = {
          'form': form,
          'query_omcl': query_omcl,
          'query_document': query_document,
          'query_document_updated': query_document_updated,
          'title': self.get_title(),
          }
    return render(request, self.template_name, context)

Instead of :

except FileNotFoundError:
    messages.error(self.request, _(f"Document {src_filename} doesn't exist on the server"))
    return redirect('manage_doc')


来源:https://stackoverflow.com/questions/53186554/django-csrf-token-issue-with-edge-only

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!