2

I'm a beginner trying to figure how to use both Django and Fetch api.

I was trying to follow this question Django - taking values from POST request, JavaScript fetch API

To figure out how to POST a form to a Django view, and access the data from the view. I'm not sure if my header has an issue.

my html form

            <form class="basicform">
               <label for="nametextbox">Change First Name</label>
               <input type="text" name="nametextbox">
            </form>`

My fetch POST request

function postForm(id, form){
            var formData = new FormData (form);
            let response = fetch("{% url 'fetch-ppl' '12345' %}".replace('12345',id), {
                method: 'POST',
                body: formData,
                headers: { 'Accept': 'application/json, text/plain, */*',
                    'Content-Type': 'application/json',
                    "X-CSRFToken": getCookie("csrftoken") },
            })
            .then(response => response.json())
            .then(data=>{
                console.log(data);
            })
        return 'Post Done';
        }

My POST view, that I'm trying to send the form data to

def post_form_rest(request, pk):
    ppl = PersonalData.objects.get(id=pk)
    serializer = PersonalDataSerializer(ppl,many=False)
    if (request.method == 'POST'):
        print("It's a Post Request")
        print(request.POST);
        print("Contents of Body")
        print(request.body);
        data = ["post request done"]
        return JsonResponse(data, safe=False)
    print("it wasn't a post request")
    return JsonResponse(serializer.data)

My problem is when I send my POST request, the django view doesn't detect any POST data at all, it just skips to the end where it gives me a json response of the initial model object. (I don't get any print statements that "it's a post request")

I'm having trouble accessing the formdata that I'm trying to send. The request.POST is empty and so is request.body

2023-08-25 20:52:14 It's a Post Request
2023-08-25 20:52:14 
2023-08-25 20:52:14 <QueryDict: {}>
2023-08-25 20:52:14 
2023-08-25 20:52:14 Contents of Body
2023-08-25 20:52:14 
2023-08-25 20:52:14 b'------WebKitFormBoundary3j9PtnVhAWSkfB14--\r\n'
2023-08-25 20:52:14 

If I visit the url, does spit out the JSON.

For reference I set up a demo, but it'll probably be deleted evetually:

Form: https://alisatlee.pythonanywhere.com/ You can check the console.log, just type gibberish in any of the boxes and hit enter.

I want to post a request to here: https://alisatlee.pythonanywhere.com/fetch-ppl/1/

arsarc
  • 443
  • 1
  • 9
  • 22
  • 1
    `if (request.POST):` might be the issue. I believe it should be better with `if request.method == 'POST':` and the reason why might be found here: https://www.django-antipatterns.com/antipattern/checking-request-method-with-if-request-post.html – raphael Aug 25 '23 at 20:08
  • @raphael Thank you, I added it and the django view is sensing the POST request now, but I'm unable to access the formData i submitted to it. checking request.body and request.post are both empty – arsarc Aug 25 '23 at 20:24
  • I'm getting a 403 forbidden error now. The `getCookie` might be ok, but django may not be setting the cookie unless you include `{% csrf_token %}` within your form in the HTML. Check out https://docs.djangoproject.com/en/4.2/howto/csrf/ – raphael Aug 25 '23 at 20:42
  • I can't recreate the 403 error, are you talking about the fetch-ppl/1/ page? In both cases the website and the response page work for me even when I'm logged out. I added the csrf token inside the form itself, but it didn't seem to send any contents. I can edit the question to add in the print responses, one moment – arsarc Aug 25 '23 at 20:55
  • Something changed. I do NOT get the 403 error anymore. In fact as far as the console it looks like it is working with no errors. I was talking about the https://alisatlee.pythonanywhere.com/ page where I was getting the 403 error. I am getting `post request done` in the console. – raphael Aug 25 '23 at 21:07
  • @raphael you can add the answer and I will accept. I think my second issue is a javascript one but the django one seems ok now. – arsarc Aug 28 '23 at 15:22
  • Done. The last time I tried it, the browser console, at least, was not giving me any errors, in fact it seemed to show the correct values. I'll check again, when I can. – raphael Aug 28 '23 at 16:28

2 Answers2

1

The issue is using if (request.POST):. It should be if request.method == 'POST': and the reason why can be found found https://www.django-antipatterns.com/antipattern/checking-request-method-with-if-request-post.html, where the authors explain the problem as follows:

Because POST requests do not per se carry data. By checking if request.POST, we are checking the truthiness of the request.POST. This is a QueryDict [Django-doc]. A QueryDict has as truthiness False, if the QueryDict is empty. But not all POST requests have "payload". For example it is possible that a confirm box to confirm deleting an object makes a POST request, but without any data as payload. In that case the if request.POST check will fail, but request.method will still be 'POST'.

raphael
  • 2,469
  • 2
  • 7
  • 19
0

Ok after the django problem, my javascript problem was how I was trying to loop through the forms. Instead of using foreach, I used for(let i = 0; i < data.length ; i++) I actually don't understand how to use foreach, but using the for loop with an index was able to solve the problem.

function fetchItems(){
    fetch (`{% url 'listppljson' %}`)
    .then(response => response.json())
    .then(data =>{
        divstuff.innerHTML="";
        j = 0;
        var formData = [];
        for(let i = 0; i < data.length; i++)
        {
            console.log(data[i].f_name);
            var row = `<p>
            <br><form id='form-${data[i].id}' class="basicform">
            {% csrf_token %}
            ${data[i].f_name}
            <br>${data[i].l_name}</br>
            <label for="nametextbox">Change First Name</label>
            <input type="text" name="nametextbox">
            </form></p>`
            divstuff.insertAdjacentHTML("beforeend",row);

            basicfm[i].addEventListener("submit", function (e) {
                e.preventDefault();
                fetch("{% url 'fetch-ppl' '12345' %}".replace('12345',data[i].id), {
                    method: "POST",
                    headers: {
                        "X-CSRFToken": getCookie("csrftoken")
                    },
                    body: new FormData(basicfm[i]),
                })
                .then(response => response.json())
                .then(data => {
                    console.log(data);
                })
                .catch(error => {
                    console.error("Error:", error);
                });
            })

        }
    })
}
arsarc
  • 443
  • 1
  • 9
  • 22