This was one of the most fun features to implement. I came across a couple Youtube videos on how other's pulled this off. Namely, I stole from one of my favorite Youtubers, John Elder (Also known as Codemy.com). He had a good approach, but my beef with his implementation was that he tied it to the user model...meaning that you needed to be logged in to like posts. I wanted an anonymous like button. Did a little more searching and came across Youtuber, codepiep, who made a video about an anonymous like button. I liked his approach too, but I thought his code was quite verbose...plus his Django site was a lot different than mine in that he didn't have the same Post model I was using.

I implemented likes and views in a way that combined both of their approaches. The way it works is that every time someone visits one of my posts, I grab the IP address and throw it into an IP_Person table. That way, it is 'semi-anonymous' in that I don't know who is viewing and liking my posts (Probably a bunch of bots)...but I can have persistent 'likes' because IP addresses are relatively consistent. Someone cannot keep liking the post over and over to drive the number upward.

Obtsining the client IP is actually pretty straightforward

def get_client_ip(request):
    x_forward_for = request.META.get("HTTP_X_FORWARD_FOR")
    if x_forward_for:
        ip = x_forward_for.split(",")[0]
    else:
        ip = request.META.get("REMOTE_ADDR")
    return ip

There's a OnetoMany relationship between my IP_Person table and the post_views and post_likes tables. A user will only get one record in the IP_Person table, but they could like or view many posts.

class Post(models.Model):
    title = models.CharField(max_length=100)
    slug = models.SlugField(unique=True, blank=True, null=True)
    content = RichTextUploadingField(blank=True, null=True)
    date_posted = models.DateTimeField(default=timezone.now)
    author = models.ForeignKey(User, on_delete=models.CASCADE)
    category = models.CharField(max_length=100, default='uncategorized')
    -> likes = models.ManyToManyField(IpPerson, related_name="post_likes", blank=True)
    -> views = models.ManyToManyField(IpPerson, related_name="post_views", blank=True)

Quite happy with how it all turned it!

Comments

Back to Home
John Solly Profile Picture
John Solly Profile Picture

John Solly

Hi, I'm John, a Software Engineer with a decade of experience building, deploying, and maintaining cloud-native geospatial solutions. I currently serve as a senior software engineer at New Light Technologies (NLT), where I work on a variety of infrastructure and application development projects.

Throughout my career, I've built applications on platforms like Esri and Mapbox while also leveraging open-source GIS technologies such as OpenLayers, GeoServer, and GDAL. This blog is where I share useful articles with the GeoDev community. Check out my portfolio to see my latest work!