coderboy
coderboy

Reputation: 769

how to make the page redirects to the same page after the event occured

I am trying to make a upvote and downvote functionality on my website. however there is a particular behaviour that i don't like which is that whenever a user clicks the button, he should not be redirect to another page but should remain on the same page.

What happens after clicking the upvote button is that it goes to the url http://localhost:8001/upvote/2/ which i don't want. I want it to remain on the same page which is http://localhost:8001/view-supplier/

models.py

class User(AbstractBaseUser, PermissionsMixin):
    email = models.EmailField(max_length=254, unique=True)

    # CUSTOM USER FIELDS
    firstname = models.CharField(max_length=30)
    lastname = models.CharField(max_length=30)
    upvotes = models.IntegerField(default=0)
    downvotes = models.IntegerField(default=0)
    objects = UserManager()

    def get_absolute_url(self):
        return "/users/%i/" % (self.pk)
        
    def get_email(self):
        return self.email

views.py

def Viewsupplier(request):
    title = "All Suppliers"
    suppliers = User.objects.filter(user_type__is_supplier=True)

    context = {"suppliers":suppliers, "title":title}

    return render(request, 'core/view-suppliers.html', context)

@login_required
def upvote(request, pk):
    supplier_vote = get_object_or_404(User, id=pk)
    supplier_vote.upvotes += 1
    supplier_vote.save()
    upvote_count = supplier_vote.upvotes
    context = {"supplier_vote":supplier_vote, "upvote_count":upvote_count}
    return render(request, "core/view-suppliers.html", context)

@login_required
def downvote(request, pk):
    supplier_vote = get_object_or_404(User, id=pk)
    supplier_vote.downvotes -= 1
    supplier_vote.save()
    downvote_count = supplier_vote.downvotes
    context = {"supplier_vote":supplier_vote, "downvote_count":downvote_count}
    return render(request, "core/view-suppliers.html", context)

urls.py

from django.urls import path
from . import views

urlpatterns = [
    path('upvote/<int:pk>/', views.upvote, name='upvote'),
    path('downvote/<int:pk>/', views.downvote, name='downvote'),
]

view-supplier.html

<table class="table table-borderless table-data3">
    <thead>
        <tr>
            <th>No</th>
            <th>Country</th>
            <th>Votes</th>
        </tr>
    </thead>
    <tbody>
        {% for supplier in suppliers %}
        <tr>
            <td>{{forloop.counter}}</td>
            <td>{{supplier.country}}</td>
            <td>
                <div class="table-data-feature">
                    <a href="{% url 'upvote' supplier.id %}" class="m-r-10">
                        <button class="item" data-toggle="tooltip" data-placement="top" title="Like">
                        <i class="zmdi zmdi-thumb-up"></i>{{upvote_count}}</button>
                    </a>
                    <a href="{% url 'downvote' supplier.id %}">
                        <button class="item" data-toggle="tooltip" data-placement="top" title="Dislike">
                        <i class="zmdi zmdi-thumb-down"></i>{{downvote_count}}</button>
                    </a>
                </div>
            </td>
        </tr>
        {% empty %}
            <tr><td class="text-center p-5" colspan="7"><h4>No supplier available</h4></td></tr>
        {% endfor %}
    </tbody>
</table>

Upvotes: 0

Views: 70

Answers (3)

EarlyCoder
EarlyCoder

Reputation: 1313

You need to implement an API (application programming interface) to send the upvote and downvote asynchronously. Django REST framework is the way to go to create your very own API. You can watch hours of video tutorials on that subject on YouTube. The docs for Django REST framework is really great and easy to read as well. Django is a server-side web-framework which means that it can only help you if you submit to the server. You can definitely reload the same page:

return HttpResponseRedirect(reverse('<app_name>:<url_name>'))

However, there will be an interruption. So, the recommended way to handle this type of behavior is through asynchronous call using JavaScript's APIs such as the Fetch API to the REST framework.

If, for probably misplaced fear of learning asynchronous coding, you decide to send data to your server the old-fashion way, you can always use your upvote and downvote to submit user data and update the counts. Then, in your view_supplier view, you need to get the updated view count and pass it to the context. So, your upvote view changes the upvote counts and trigger the Viewsupplier view. Then, inside the ViewSupplier view, you get the counts and add it to the context

# in your template
<a href="{% url 'upvote' supplier.id %}" class="m-r-10">
   <button class="item" data-toggle="tooltip" data-placement="top" title="Like">
   <i class="zmdi zmdi-thumb-up"></i>{{upvote_count}}</button>
</a>

# in your view
def Viewsupplier(request):
    title = "All Suppliers"
    suppliers = User.objects.filter(user_type__is_supplier=True)

    # Get the updated count:
    suppliers_votes_count = {}
    for supplier in suppliers:
        upvote_count    = supplier.upvotes
        downvote_count  = supplier.upvotes

        supplier_count = {supplier: {'upvote': upvote_count, 'downvote': downvote_count } }
    
    suppliers_votes_count.update(supplier_count)

    context = {"suppliers":suppliers, "title":title, "suppliers_votes_count": suppliers_votes_count }

    return render(request, 'core/view-suppliers.html', context)

@login_required
def upvote(request, pk):
    supplier_vote = get_object_or_404(User, id=pk)
    supplier_vote.upvotes += 1
    supplier_vote.save()
    upvote_count = supplier_vote.upvotes
    context = {"supplier_vote":supplier_vote, "upvote_count":upvote_count}
    return HttpResponseRedirect(reverse('core:view_supplier'))

Upvotes: 2

Anthony
Anthony

Reputation: 959

Here's how I would achieve this:

first I'd have simple forms handling the upvotes/downvotes:

<form method="POST" action="{% url 'view-supplier' %}"> //upvote form
  {% csrf_token %}
  <input type="hidden" name="upvote-button">
  <button type="submit" style="width:100%">Upvote Button</button>
</form>

<form method="POST" action="{% url 'view-supplier' %}"> // downvote form
  {% csrf_token %}
  <input type="hidden" name="downvote-button">
  <button type="submit" style="width:100%">Downvote Button</button>
</form>

Then I'd have the view set up like:

def supplierView(request):
   supplier_vote = get_object_or_404(User, id=pk)

   if 'upvote-button' in request.POST:
         supplier_vote.upvotes += 1
         supplier_vote.save()
         upvote_count = supplier_vote.upvotes

   elif 'downvote-button' in request.POST:
         supplier_vote.downvotes -= 1
         supplier_vote.save()
         downvote_count = supplier_vote.downvotes
   
   else:
         downvote_count = supplier_vote.downvotes
         upvote_count = supplier_vote.upvotes

   context = {
    'upvote_count': upvote_count,
    'downvote_count': upvote_count,
   }

   return render(request, 'main/view-suppliers.html', context)

This way when someone clicks the upvote button, they're redirected to the same view, which then handles adding the upvotes and updates the context.

If view-supplier is a detail view, you'll also have to pass in the PK to the view.

Upvotes: 1

Ram
Ram

Reputation: 4789

This can be easily achieved by using AJAX.

Rather than providing the supplier_id as part of URL, it would be better to send the supplier_id in AJAX to your Django Upvote view. You could do like this.

HTML:

<button id="{{ supplier_id }}" class="item upvote" data-toggle="tooltip" data-placement="top" title="Like">
<i class="zmdi zmdi-thumb-up"></i>{{upvote_count}}
</button>

Extract the supplier_id from the button on click event using Javascript.

JavaScript:

$('.upvote').on('click', function () {
var supp_id = $(this).attr('id');
  $ajax({
    type: 'POST',
    url: '/upvote/',
    data: {
       supplier_id: supplier_id,
    },
   success: function (data) {
   if (data.status == 'success') {
       /* Your upvote logic like updating the color of button or showing Unlike etc.,*/
    }
  }
 });
});

Change your url pattern in Django urls.py to

urlpatterns = [path('upvote/', views.upvote, name='upvote'),

Views.py

def upvote(request):
    if request.method == 'POST':
        supplier_id = request.POST['supplier_id']
        # Your DB update logic goes here....
        return JsonResponse({'status': 'success'})
    else:
        return JsonResponse({'status': 'Error'})

Similarly you could do the same for downvote.

Upvotes: 1

Related Questions