# Updating model after click event with JavaScript

**URL:** <https://forum.djangoproject.com/t/updating-model-after-click-event-with-javascript/6795>\
**Category:** Using Django\
**Created:** [February 26, 2021, 6:18pm UTC](https://forum.djangoproject.com/t/updating-model-after-click-event-with-javascript/6795 "2021-02-26T18:18:30Z")\
**Posts on this page:** 10\
**Page:** 1

<div class="post-metadata">

**Author:** ![jackaitken](https://sea2.discourse-cdn.com/flex026/user_avatar/forum.djangoproject.com/jackaitken/32/3656_2.png) [@jackaitken](https://forum.djangoproject.com/u/jackaitken)\
**Post date:** [February 26, 2021, 6:18pm UTC](https://forum.djangoproject.com/t/updating-model-after-click-event-with-javascript/6795/1 "2021-02-26T18:18:30Z")

</div>

Hello,

I have a to do app that I’m working on and I have 3 models, a custom user model, a list model, and an item model. The item model represents list items that can be on a specific list. The item has a foreign key relationship to a list and a list is mapped to a specific user.

In my item model I have a field for “completed”, which defaults to False, but I would like this to be updated to True if a user clicks a checkbox. I would like to do this in JavaScript, but I’m unsure about how to properly update a model with JS. As a note, I haven’t serialized my models, but if this would make it easier than just updating a model directly, then I would certainly look into that.

Here is my JS code that I’ve written, and you can see from the photo I’ve added at the bottom, I’m getting a response in the console, which is great, but the url route is not what I was expecting from my fetch request in my JS code.

```
// function to mark list item as completed.
document.addEventListener('DOMContentLoaded', function() {
    let checkboxes = document.querySelectorAll('#completed')
    checkboxes.forEach(checkbox => {
        checkbox.onclick = function() {
            const pk = checkbox.dataset.id
            fetch(`/${pk}/item`, {
                method: 'PUT',
                body: JSON.stringify({
                    completed: (completed ? false : true)
                })
            })
        }
    });
});

```

**Here is my urls.py file. (I’ve excluded the imports, but i’ve imported my views)**

```
urlpatterns = [
    path('signup/', SignUpView.as_view(), name='signup'),
    path('<int:pk>/todolists/', ToDoListView.as_view(), name='todolists'),
    path('list_new/', ToDoListCreateView.as_view(), name='list_new'),
    path('<int:pk>/item_new/', item_new_view, name='item_new'),
    path('<int:pk>/delete/', ToDoListDeleteView.as_view(), name='list_delete'),
    path('<int:pk>/item', mark_item_as_completed_view, name='item_completed')
]

```

**Here is the specific view that is going to handle the fetch. I’ve worked on this bit the least:**

```
def mark_item_as_completed_view(request, pk):
    if request.method == "PUT":
        return JsonResponse({
            "success: completed"
        })

```

 ![Screen Shot 2021-02-26 at 1.04.26 PM](https://us1.discourse-cdn.com/flex026/uploads/djangoproject/original/2X/3/3eb69ea6d7e045a7cf6f14559f6aaf6d6782536c.png)

---

<div class="post-metadata">

**Author:** ![conor](https://sea2.discourse-cdn.com/flex026/user_avatar/forum.djangoproject.com/conor/32/3736_2.png) [@conor](https://forum.djangoproject.com/u/conor)\
**Post date:** [February 26, 2021, 6:52pm UTC](https://forum.djangoproject.com/t/updating-model-after-click-event-with-javascript/6795/2 "2021-02-26T18:52:29Z")

</div>

G’day g’day,

Is the `urls.py` file in your post your app specific URLs or your project’s URLs? Is it possible for you two share both the project level and app level URLs? I ask this because the URL in your console debugger is quite long and the URL for what I assume is your app level URL should be `<integer>/item` whereas your URL appears to also include the URL for the `ToDoListCreateView`.

Am I right in guessing the your project level URLs has something along the lines of:

```python
path("lists/", include("your_app_name.urls")),

```

From looking at the console debugger output and your `urls.py`, I’m guessing that the `fetch()` function in your JS is prepending to many paths to the URL of your request.

One thing I can suggest doing is to hardcode your URL into your JS as a test or use a tool like Postman to test your endpoints.

And almost forgot to ask, are you using Django by itself or are you also using Django Rest Framework. If the former, you’ll have to include the [CSRF cookie](https://docs.djangoproject.com/en/3.1/ref/csrf/)

---

<div class="post-metadata">

**Author:** ![jackaitken](https://sea2.discourse-cdn.com/flex026/user_avatar/forum.djangoproject.com/jackaitken/32/3656_2.png) [@jackaitken](https://forum.djangoproject.com/u/jackaitken)\
**Post date:** [February 26, 2021, 7:03pm UTC](https://forum.djangoproject.com/t/updating-model-after-click-event-with-javascript/6795/3 "2021-02-26T19:03:04Z")

</div>

Hello Conor,

Your assumption is correct, I have a project level `urls.py` file and then what I shared in my first post is my app level `urls.py` file. Also I’m not using DRF, just traditional Django. Here are the project level urls again without my imports:

```
urlpatterns = [
    path('admin/', admin.site.urls),
    path('lists/', include('lists.urls')),
    path('lists/', include('django.contrib.auth.urls')),
    path('', TemplateView.as_view(template_name='home.html'),
        name='home')
]

```

I’ve tried previously to hardcode the route into the fetch request as well, but that hasn’t been successful. Perhaps the interaction between my project level urls and app level urls is the cause?

---

<div class="post-metadata">

**Author:** ![jackaitken](https://sea2.discourse-cdn.com/flex026/user_avatar/forum.djangoproject.com/jackaitken/32/3656_2.png) [@jackaitken](https://forum.djangoproject.com/u/jackaitken)\
**Post date:** [February 26, 2021, 7:14pm UTC](https://forum.djangoproject.com/t/updating-model-after-click-event-with-javascript/6795/4 "2021-02-26T19:14:32Z")

</div>

I tried the hardcoding again just to double check. Given the pk 31 for a specific item, when the checkbox is clicked it still prepends `lists/23/todolists/lists/` so the full path would be: `lists/23/todolists/lists/31/item`.

Here’s the hardcoded JS:

```
// function to mark list item as completed.
document.addEventListener('DOMContentLoaded', function() {
    let checkboxes = document.querySelectorAll('#completed')
    checkboxes.forEach(checkbox => {
        checkbox.onclick = function() {
            const pk = checkbox.dataset.id
            fetch("/31/item", {
                method: 'PUT',
                body: JSON.stringify({
                    completed: (completed ? false : true)
                })
            })
        }
    });
});
```

---

<div class="post-metadata">

**Author:** ![conor](https://sea2.discourse-cdn.com/flex026/user_avatar/forum.djangoproject.com/conor/32/3736_2.png) [@conor](https://forum.djangoproject.com/u/conor)\
**Post date:** [February 26, 2021, 7:17pm UTC](https://forum.djangoproject.com/t/updating-model-after-click-event-with-javascript/6795/5 "2021-02-26T19:17:59Z")

</div>

I was more thinking of hardcoding the entire URL, for example, http:localhost:8000/lists/31/item

Please see my questions about your URLs and DRF.

---

<div class="post-metadata">

**Author:** ![jackaitken](https://sea2.discourse-cdn.com/flex026/user_avatar/forum.djangoproject.com/jackaitken/32/3656_2.png) [@jackaitken](https://forum.djangoproject.com/u/jackaitken)\
**Post date:** [February 26, 2021, 7:20pm UTC](https://forum.djangoproject.com/t/updating-model-after-click-event-with-javascript/6795/6 "2021-02-26T19:20:11Z")

</div>

Sorry, my latest response might have overshadowed my first. I answered the DRF and urls question above, but I’ve copied and pasted it below:

Hello Conor,

Your assumption is correct, I have a project level `urls.py` file and then what I shared in my first post is my app level `urls.py` file. Also I’m not using DRF, just traditional Django. Here are the project level urls again without my imports:

```auto
urlpatterns = [
    path('admin/', admin.site.urls),
    path('lists/', include('lists.urls')),
    path('lists/', include('django.contrib.auth.urls')),
    path('', TemplateView.as_view(template_name='home.html'),
        name='home')
]

```

I’ve tried previously to hardcode the route into the fetch request as well, but that hasn’t been successful. Perhaps the interaction between my project level urls and app level urls is the cause?

Thanks,  
Jack

---

<div class="post-metadata">

**Author:** ![conor](https://sea2.discourse-cdn.com/flex026/user_avatar/forum.djangoproject.com/conor/32/3736_2.png) [@conor](https://forum.djangoproject.com/u/conor)\
**Post date:** [February 26, 2021, 7:38pm UTC](https://forum.djangoproject.com/t/updating-model-after-click-event-with-javascript/6795/7 "2021-02-26T19:38:36Z")

</div>

Mea culpa, I missed your first reply.

I’m guessing you’re developing this on your own, local machine? Can you navigate to the URL in your web browser? I know it’s not a PUT request, but this will help you determine if the URL is reachable. If so, then I’m leaning towards there being an issue with `fetch()`method in your JS. I’m not much a JS wizard, so I might be missing something obvious, but if you’re feeding `"/31/item"` into `fetch()` and getting an incorrect URL as a result, then I’d be inclined the look there.

If you want to test this programatically with python, the you can use requests to fire off a put request:

```python
import requests # pip install requests

url = "http:localhost:8000/lists/31/item"
data = {"completed": True}
response = requests.put(url, json=data)
print(response.content) # this will print the raw bytes response. Handy for debugging when things go wrong
print(response.json()) # will print the JSON response if there is one

```

If a simple test program like the one above works, then I’d say `fetch()` if the culprit.

Also, if there is more than one attribute to the list model, and not just `complete`, you can consider using `PATCH` instead of `PUT`. PUT recreates the object whereas PATCH can modify just one or more attributes of a model.

---

<div class="post-metadata">

**Author:** ![jackaitken](https://sea2.discourse-cdn.com/flex026/user_avatar/forum.djangoproject.com/jackaitken/32/3656_2.png) [@jackaitken](https://forum.djangoproject.com/u/jackaitken)\
**Post date:** [February 26, 2021, 8:11pm UTC](https://forum.djangoproject.com/t/updating-model-after-click-event-with-javascript/6795/8 "2021-02-26T20:11:10Z")

</div>

I’ve made some progress here now. I’ve been using Chrome, but noticed that changes I was making in my fetch request were not being reflected in the console. I switched to Safari and noticed a difference immediately. I changed my fetch request to `/lists/${pk}/item` and noticed that this fixed the route it was looking for and it dropped that long prepended route. Chrome however is still showing me that long route I was seeing, maybe I need to clear cache and cookies?

One other issue was that my fetch request originally was `/${pk}/item`, so adding `lists` to the beginning of my request fixed some issues. I’ve also added a `csrf_exempt` decorator on top of the view for the time being.

So for right now it’s getting the right route and view, now I just need to figure out how to actually change my model from False to True, because that’s still not working.

Thank you for your help.

---

<div class="post-metadata">

**Author:** ![conor](https://sea2.discourse-cdn.com/flex026/user_avatar/forum.djangoproject.com/conor/32/3736_2.png) [@conor](https://forum.djangoproject.com/u/conor)\
**Post date:** [February 26, 2021, 8:31pm UTC](https://forum.djangoproject.com/t/updating-model-after-click-event-with-javascript/6795/9 "2021-02-26T20:31:28Z")

</div>

Good to hear. This is just going from the top of my head (I’m about to nod off for the night), so definitely sanity check this, but something along these lines would be the steps to be required to receive some JSON and modify a model instance. **Note** If working with Django and a frontend, Django Rest Framework is your very, very best friend - it is mine.

```python
from django.shortcuts import get_object_or_404
from lists.models import List

def mark_item_as_completed_view(self, request):
    if request.method == "PUT":
        # get the ID KWARG
        list_id = request.kwargs.get("pk", None)
        if list_id is not None:
            try:
                list_obj = get_object_or_404(List, pk=list_id)
                completed = request.POST.get("completed", None)
                # good idea to do some more error checking here, but its getting late
                list_object.update(completed=completed)
                return JsonResponse({
                    "success": completed,
                    "list_id": list_obj.id
                })
            except List.DoesNotExist:
                # handle the exception
                pass
        return JsonResponse({"error": "something went wrong"}, status=401)

```

Hope this helps. Good luck!

---

<div class="post-metadata">

**Author:** ![jackaitken](https://sea2.discourse-cdn.com/flex026/user_avatar/forum.djangoproject.com/jackaitken/32/3656_2.png) [@jackaitken](https://forum.djangoproject.com/u/jackaitken)\
**Post date:** [February 26, 2021, 8:40pm UTC](https://forum.djangoproject.com/t/updating-model-after-click-event-with-javascript/6795/10 "2021-02-26T20:40:33Z")

</div>

Thank you, Conor! I really appreciate your time and help.
