[PYTHON] Like button implementation in Django + Ajax

1.First of all

This is the first post of Qiita to commemorate.

I'm a person who loves Twitter, but I don't touch Twitter during work. So, I started to make a Twitter-like app for writing thoughts and memos, but it is quite difficult to implement a like button. .. .. If you do it with form, the feeling of Twitter will be weakened with page transitions, so I searched for other methods. At that time, I learned about Ajax and managed to implement it, so I decided to post it.

dislike.png like.png

I have just started studying web frameworks and DBs, so if you have any mistakes, I would appreciate it if you could teach me.

2. Implementation & Description

Please note that this time we will omit the explanation of the part where the data input from the form is saved in the DB.

urls.py


from django.urls import path
from . import views

urlpatterns = [
    path('', views.timeline, name='index'),
    path('like/', views.like, name='like'),
]

Routing settings. Set the page that returns httpresponse.

models.py


from django.db import models
from django.utils import timezone

class PostTweet(models.Model):
    memo = models.TextField(max_length=140)
    published = models.DateTimeField(default=timezone.now)
    star = models.BooleanField(default=False)

In models.py, in addition to the contents of the memo, define a Boolean value that indicates the "like" status.

forms.py


class PostForm(forms.ModelForm):
    class Meta:
        model = PostTweet
        fields = ['memo', 'published', 'star']

forms.py looks like this. There is nothing special to mention, but I will post it for the time being.

views.py


from django.http import HttpResponse
from django.shortcuts import render
from .models import PostTweet
from .forms import PostForm, SearchForm

def index(request):
    posts = PostTweet.objects.all().order_by('-published')
    form = PostForm()
    d = {
        'form': form,
        'posts': posts
    }
    return render(request, 'index.html', d)

def like(request):
    if request.method == 'GET':
        if 'star' in request.GET:
            like = PostTweet.objects.get(id=int(request.GET['star']))
            like.star = not like.star
            like.save()
            return HttpResponse('OK')
    else:
        return HttpResponse("NG")

I'll talk about like () later.

index.html


{% extends 'base.html' %}
{% block body %}
    {% for post in posts %}
        {{ post.memo | linebreaker }}
        <br>
        {% if post.star == False %}
            <input type="checkbox" class="like" id="like_{{ post.id }}" 
                   data_id="{{ post.id }}">
        {% else %}
            <input type="checkbox" class="like" checked="checked" id="like_{{ post.id }}"
                   data_id="{{ post.id }}">
        {% endif %}
        <label for="like_{{ post.id }}" class="like_label">★</label>
    
    <script src="https://code.jquery.com/jquery-3.5.0.js" 
            integrity="sha256-r/AaFHrszJtwpe+tHyNi/XCfMxYpbsRg2Uqn0x3s2zc=" 
            crossorigin="anonymous"></script>
    <script type="text/javascript">
        $('.like').click(function(){
            var id;
            id = $(this).attr("data_id");
            $.ajax(
                {
                    type:"GET",
                    url: "like",
                    data:{
                        star: id
                        }
                })
            });
    </script>
{% endblock %}

I decided to use checkboxes and labels to represent the like button. If the star that represents the like status is True, set the checkbox to checked in advance.

Omitted for base.html.

style.css


.like{
    display: none;
}
.like_label{
    margin-left: 10px;
    cursor: pointer;
    color: #cccccc;
    border: none;  /*Erase the border*/
    outline: none; /*Remove the border that appears when you click*/
    background: transparent; /*Erase the gray background*/
}
input:checked + .like_label{
    color: gold;
}

Appearance update

Turn off the button and show only the label. The default button label color should be gray. If the checkbox is checked, change the color of the button label to gold.

This will change the color each time you press the button.

DB update

Import jQuery. Use Ajax (asynchronous processing of javascript) to return the record id of the pressed button to the like method of views.py. (The id is automatically added when it is added to the DB.) Then, in views.py like (), set the star of the acquired id to not star and update it.

By doing this, the contents of the DB will be updated each time you press the button.

Summary

By using Ajax and checkboxes, I was able to implement a nice like button. Since this app is based on the premise that only you can see it, you can only turn it on and off, but I think you can make a type that counts the number of likes in the same way.

Thank you for reading this far!

Recommended Posts

Like button implementation in Django + Ajax
Implementation of login function in Django
React → Ajax → Django on Linux implementation memo
Ajax in Django (using generic class view)
Asynchronous processing implementation in Django (Celery, Redis)
Models in Django
Forms in Django
RNN implementation in python
ValueObject implementation in Python
Django drop-down menu implementation
SVM implementation in python
[Django] Manage settings like writing in settings.py with a model
Implement an add form button in your Django inline form set
Performance optimization in Django 3.xx
PHP var_dump in Django templates
Handle constants in Django templates
Implement follow functionality in Django
Rename table columns in Django3
(Note) Django in Vagrant environment
Neural network implementation in python
Implementation of quicksort in Python
Show Django ManyToManyField in Template
Implementation of JWT authentication functionality in Django REST Framework using djoser