3

I have a mini project with Django. I have just a model with a counter total :

class Reponse(models.Model):
    total = models.IntegerField()

I have this view:

def questions(request):
    _reponse = get_object_or_404(Reponse, id= 1)
    return render(request, 'vautmieux/test.html', {'reponse': _reponse})

And my HTML test display the variable total:

<p id="block1">
    {{reponse.total}}
</p>

My question is :

I would like when I click on a button in the HTML, the variable total increases by 1. How can I do that ? With a form POST or GET ? May be there is a better method ?

A button like this :

<p id="block1">
    {{reponse.total}}
</p>
<button type="button">
    Click for increase total by 1
</button>
5
  • 2
    Look into AJAX. Unless you're okay with the page refreshing every time the button is clicked, you're going to need to write some frontend JavaScript to make things work the way you describe Commented Jul 21, 2019 at 20:41
  • 1
    It's not totally clear what you want. Do you want the click to increase the total displayed on the same page, straight away? If so, then that's easy enough with just Javascript. If you want it to also change the value in the database so that, the next time anyone loads the page, it displays the new total, then you need to submit a POST request to the server, which your Django back end can handle and then display the updated page. Even better, as @senox13 says, do it with Ajax so that the page never has to reload. Commented Jul 21, 2019 at 20:42
  • It's exactly that what I want. I want change the value in the database, and display the new value, without refresh the page ! I will try with AJAX. Do you have any other tips for me ? :) Commented Jul 21, 2019 at 20:47
  • @RobinZigmond How I use a POST request with my Django back end ? Should I use a new view ? Commented Jul 21, 2019 at 20:51
  • yes, if you're using Ajax you need to set up a new endpoint to process it. It doesn't need to return HTML, and generally shouldn't, in this case you probably want to respond with a simple JSON string showing the new total. Commented Jul 21, 2019 at 20:56

2 Answers 2

3

You can do that way

from django.db.models import F
def questions(request)
     _reponse = Reponse.objects.update(total=F('total') + 1)

      return render(request, 'vautmieux/test.html', {'reponse': _reponse})

If you want to add a button to increase the counter so you need to create two separate views one to render the html page and the other to increase the integerfield So you views.py will look like this

from django.db.models import F
from django.views.decorators.csrf import csrf_exempt
def questions(request)      
      return render(request, 'vautmieux/test.html', {'reponse': _reponse})
@csrf_exempt
def IncreaseCounter(request):
    _reponse = Reponse.objects.update(total=F('total') + 1)
    return HttpResponse('the counter has been increased')

and in your url you will have :

path('question_page/', views.questions, name='question-html'),
path('increase_counter/', views.IncreaseCounter, name='Increase-Counter')

And last you need just to add a button to target the second view :

<button onclick="window.location.href='/increase_counter/';"> + 1 </button>

And the ideal way is to use ajax so your page will not refresh every time you click the button, to do so you have to change the onclick function of the button and to add the following script :

<button onclick="increase_counter()"> + 1 </button>

<script type="text/javascript">
             $.ajax({
             url: '/increase_counter/',
             method : 'POST',
             success: function(response) {

              alert('counter increased')
              }
              }); 
</script>

But if you want to use ajax you have to add a csrf_exempt decorator on your view.

In order to update a specific object in your model you need to pass the pk as a variable in your url like so :

path('increase_counter/<int:pk>/', views.IncreaseCounter, name='Increase-Counter')

in your button you will loop change the button to be like this :

<button onclick="window.location.href='/increase_counter/{{ response.pk }}/';"> + 1 </button>

for aajax is the same method you add the pk into the url. And in your view you will add this :

def IncreaseCounter(request, pk):
    _reponse = Reponse.objects.filter(pk=pk).update(total=F('total') + 1)
    return HttpResponse('the counter has been increased')
Sign up to request clarification or add additional context in comments.

6 Comments

Thanks, but this increases total each times the page test.html is called. I would like just when I click on a button. I update my question.
Thank you very much Farhani, I have a last question : I have a lot of instance of my class Reponse. When you wirte ` Reponse.objects.update(total=F('total') + 1)`. Is it the good instance of the object Reponse ?
with this view it will update the last created instancen if you want to update a specefic instance you need to, queryset the Response for the desired one and then update it, if you want to do this you need to pass the pk of the instance in the url, let me know if you want to do something like this, and if the answer satisfy your question don't forget to accept it
Yes, I would like a specifik instance ! The instance on my html {{reponse.total}}, I would like increase this reponse, when i refresh the page the reponse change. Yes sure I'm gonna accept your answer ! :)
In your model Response you will have more than one object ?
|
0

In my opinion, this is a much easier straightforward method. This isn't exact code for your problem, but more of a general flow on what the heck all this stuff is and how to use it. So apologies on the wordiness of this post. I am posting for my case because I think will be useful to you as you expand your app to needing to control totals for a particular object. So, in my case, I was needing a button to easily increase or decrease a part quantity for an inventory system, like nuts and bolts. This is what I needed to control inventory while on a part-specific page:

  1. A button with a reverse pattern name that links to increase_inventory view.

    <a href="{% url 'webapp:increase-inventory' part.pk %}" ><button class="btn btn-primary">Add 1</button></a>

Notice the "parts.pk", I'm going to talk about it in sec. Also, now and later notice the differences between _ and -. When you see -, it's a pattern name.

  1. In your urls.py, place a similar code like this in your file.

     urlpatterns = [
     path('increase_inventory_level/<pk>', views.increase_inventory, name='increase-inventory'), ]
    

Notice a few things here too, "inventory-level" is the pattern name which is the linking variable between your html page and urls.py. "increase_inventory_level/<pk" is the URL link for a specific object. Say in your parts list you have: a nut, a bolt, and an o-ring. Each one of these objects is going to have a different PK. Each one of these items has it's own detail page which is going to have its own url, which will look something like this partdetail/<pk. (Close those brackets for pk, I can't in this post or it will disappear)

The last thing to notice is the "views.increase_inventory". This links your app to the specific view that you need.

def increase_inventory(request, *args, **kwargs):
    pk = kwargs.get('pk')
    part = get_object_or_404(Part, pk=pk)
    part.inventory_level = part.inventory_level + 1
    part.save()

    context = {'part': part}

    return render(
        request,
        'webapp/part_detail.html',
        context=context
    )

Now we're cooking. The view grabs the object associated with the PK value then edits the inventory attribute of the part object, saves it, and then renders the html page with the new part information.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.