I am trying to create asocial media type site that allows users to follow other users through a Django model. For some reason, the Follow Button says "Unfollow" when a user is not following the user and says "Follow" when the user is following the other user. Do you know how to display the appropriate message? (I have tried switching the True and False values but that just makes the button say "Follow" permanently.)
views.py
def username(request, user):
#get user
user = get_object_or_404(User.objects, username=user)
posts = Post.objects.filter(user=user).order_by('-date_and_time')
#follow button code
if user == request.user:
followButton = False
else:
followButton = True
follow_or_unfollow = ''
try:
following = get_object_or_404(Follower, Q(
user=user) & Q(followers=request.user))
print(following)
except:
following = False
if following:
follow_or_unfollow = True
else:
follow_or_unfollow = False
if request.method == "POST":
if request.POST.get('follow'):
follower = Follower.objects.create(user=user)
follower.followers.add(request.user)
#Follower.objects.create(user=user, followers.set()=request.user)
follow_or_unfollow = False
elif request.POST.get('unfollow'):
follower = Follower.objects.get(followers=request.user)
follow_or_unfollow = True
follower.remove()
return render(request, "network/username.html",{
"user": user,
"posts": posts,
"follow_or_unfollow": follow_or_unfollow,
"followButton": followButton
})
code in html template
<form action = "{% url 'username' user %}" method = "POST">
{% csrf_token %}
{% if follow_or_unfollow == True %}
<input type="submit" value = "Follow" name = "follow">
{% else %}
<input type="submit" value = "Unfollow" name = "unfollow">
{% endif %}
</form>
models.py
class User(AbstractUser):
pass
class Follower(models.Model):
user = models.ForeignKey(User, on_delete=models.CASCADE, default="")
followers = models.ManyToManyField(User, related_name="followers")
CodePudding user response:
You can do it so much simplier without Follower
model:
models.py
class User(AbstractUser):
following = models.ManyToManyField("self", related_name="followers")
template.html
<form action = "{% url 'username' user %}" method = "POST">
{% csrf_token %}
{% if user not in request.user.following.all %}
<input type="submit" value="Follow" name="follow">
{% else %}
<input type="submit" value="Unfollow" name="unfollow">
{% endif %}
</form>
views.py
def username(request, user):
...
if request.method == "POST":
if "follow" in request.POST:
request.user.following.add(user)
elif "unfollow" in request.POST:
request.user.following.remove(user)
...
CodePudding user response:
you don't need user query, you can work only with post
<form action = "{% url 'username' post.user %}" method = "POST">
{% csrf_token %}
{% if request.user != post.user %}
{% if request.user not in post.user.followers.all %}
<input type="submit" value = "Follow" name = "follow">
{% else %}
<input type="submit" value = "Unfollow" name = "unfollow">
{% endif %}
{% endif %}
</form>
dont forget add request in context
, if you don't have a request.context_processor:
def username(request, user):
...
return render(request, "network/username.html",{"posts": posts, "post": posts.first(), "request": request})
CodePudding user response:
I like @NixonSparrow's answer very much. Along those same lines, I'll throw my answer into the mix.
accounts/views.py
import random
import string
from django.shortcuts import render, get_object_or_404
from accounts.models import Post
from django.contrib.auth import get_user_model
from django.contrib.auth import authenticate, login
def generate_fake_user():
username = ''.join(random.choice(string.ascii_lowercase) for i in range(10))
password = 'abc123'
fake_user = get_user_model().objects.create(
username=username
)
fake_user.set_password(password)
fake_user.save()
return fake_user
def username(request, user):
# get user
owner = get_object_or_404(get_user_model(), username=user)
if not request.user.is_authenticated:
visitor = generate_fake_user()
login(request, visitor)
else:
visitor = request.user
posts = Post.objects.filter(user=owner).order_by('-date_and_time')
if request.method == 'POST' and request.user.is_authenticated:
if 'follow' in request.POST:
owner.followers.add(visitor)
if 'unfollow' in request.POST:
owner.followers.remove(visitor)
context = {
"owner" : owner,
"visitor": visitor,
"posts" : posts,
}
return render(request, "network/username.html", context)
generate_fake_user()
is not necessary in your code. Neither is loging in the user within the view. This was necessary to create a re-usable example without a login page.
accounts/models.py
from django.db import models
from django.contrib.auth.models import AbstractUser
class User(AbstractUser):
followers = models.ManyToManyField('self', related_name="followers")
following = models.ManyToManyField('self', related_name="following")
class Post(models.Model):
user = models.ForeignKey(User, on_delete=models.CASCADE)
title = models.CharField(max_length=100)
date_and_time = models.DateTimeField(auto_now_add=True)
def __str__(self):
return self.title
Obviously, you probably have Post
model somewhere else. Just here for example purposes.
accounts/urls.py
from django.urls import path
from .views import username
urlpatterns = [
path('<str:user>/', username, name='username'),
]
network/username.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<div style="margin-left:auto; margin-right:auto; width:50%;">
{% for post in posts %}
<h1>{{ post.title }}</h1>
<div>
<div>Owner: {{ owner }}</div>
<div>Owner: {{ visitor }}</div>
</div>
<form action="{% url 'username' owner %}" method="POST">
{% csrf_token %}
{% if visitor not in owner.followers.all %}
<input type="submit" value="Follow" name="follow">
{% else %}
<input type="submit" value="Unfollow" name="unfollow">
{% endif %}
</form>
{% endfor %}
</div>
</body>
</html>
Before following:
After following: