I have been trying to implement a follow/unfollow system on django in which a user can follow other users and the user can also be followed, in the user's profile there is a following count which displays how many people the user is following and a follower count which is supposed to display how many followers the user has just like in instagram. Everything is working good except for the follower count which doesn't counting the followers. for doing this follower count, I used signals but it doesnt work. How can I fix this problem?
models.py
class Profile(models.Model):
user = models.OneToOneField(User, on_delete=models.CASCADE)
profile_pic = models.ImageField(upload_to='profile_pics', null=True, blank=True, default='default.png')
bio = models.CharField(max_length=400, default=1, null=True)
connection = models.CharField(max_length = 100, blank=True)
follower = models.IntegerField(default=0)
following = models.IntegerField(default=0)
def __str__(self):
return f'{self.user.username} Profile'
class Following(models.Model):
user = models.OneToOneField(User, on_delete=models.CASCADE)
followed = models.ManyToManyField(User, related_name="followed")
follower = models.ManyToManyField(User, related_name="follower")
#classmethod
def follow(cls, user, another_account):
obj, create = cls.objects.get_or_create(user = user)
obj.followed.add(another_account)
print("followed")
#classmethod
def unfollow(cls, user, another_account):
obj, create = cls.objects.get_or_create(user = user)
obj.followed.remove(another_account)
print("unfollowed")
def __str__(self):
return f'{self.user.username} Profile'
views.py
def profile(request, username=None):
profile, created = Profile.objects.get_or_create(user=request.user)
if username:
post_owner = get_object_or_404(User, username=username)
profile_bio = Profile.objects.filter(user_id=post_owner)
user_posts = Post.objects.filter(user_id=post_owner)
user = User.objects.get(username=username)
is_following = Following.objects.filter(user=request.user, followed=user)
following_obj = Following.objects.get(user=user)
follower = following_obj.follower.count()
following = following_obj.followed.count()
else:
post_owner = request.user
user_posts = Post.objects.filter(user=request.user)
profile_bio = Profile.objetcs.filter(user=request.user)
args1 = {
'post_owner': post_owner,
'user_posts': user_posts,
'follower': follower,
'following': following,
'connection': is_following,
'profile_bio': profile_bio,
}
return render(request, 'profile.html', args1)
def follow(request, username):
main_user = request.user
to_follow = User.objects.get(username=username)
following = Following.objects.filter(user = main_user, followed = to_follow)
is_following = True if following else False
if is_following:
Following.unfollow(main_user, to_follow)
is_following = False
else:
Following.follow(main_user, to_follow)
is_following = True
resp = {
'following': is_following,
}
response = json.dumps(resp)
return HttpResponse(response, content_type="application/json")
signals.py
#receiver(m2m_changed, sender = Following.followed.through) # which list is changed
def add_follower(sender, instance, action, reverse, pk_set, **kwargs):
followed_users = [] # list of users main (logged ) user have followed
logged_user = User.objects.get(username = instance) # user who followed other users
for i in pk_set:
user = User.objects.get(pk = i)
following_obj = Following.objects.get(user = user)
followed_users.append(following_obj)
if action == "pre_add":
for i in followed_users:
i.follower.add(logged_user)
i.save()
if action == "pre_remove":
for i in followed_users:
i.follower.remove(logged_user)
i.save()
profile.html
{% if connection and not request.user == post_owner %}
<a type="button" class="button-caballo" id="follow" role="button" href="{% url 'follow' post_owner.username %}">Unfollow</a>
{% elif not connection and not request.user == post_owner %}
<a type="button" class="button-caballo" id="follow" role="button" href="{% url 'follow' post_owner.username %}">Follow</a>
{% endif %}
<div class="header-item">
{{follower}}
</div>
<div class="header-item">
{{following}}
</div>
why creating another field for the followers? you can get the followers count and users from the same Following table without any need for followers field.
your following model should only contain user, followed
you can get the followers by using
following.objects.filter(followed=request.user)
Related
I am working on an Auction website using Django. I am trying to display data of the Last_bid field which is connected to Bid table with a foreign key. I tried many ways but nothing worked out.
The models.py file is:
from django.contrib.auth.models import AbstractUser
from django.db import models
from django.db.models.base import Model
from django.db.models.deletion import CASCADE
from django.db.models.fields import CharField
from django.utils import timezone
class User(AbstractUser):
pass
class Category(models.Model):
category = models.CharField(max_length=64)
def __str__(self):
return f'{self.category}'
class AuctionListing(models.Model):
item_name = models.CharField(max_length=100)
item_image = models.ImageField(upload_to="products", null=True, blank=True)
detail = models.TextField()
price = models.IntegerField()
last_bid = models.ForeignKey('Bid', on_delete=models.CASCADE, blank=True, null=True, related_name='lst')
user = models.ForeignKey(User, on_delete=models.CASCADE, related_name='publisher_listing', null=True, blank=True)
watchers = models.ManyToManyField(User, blank=True, related_name='watched_list')
pub_date = models.DateTimeField(auto_now=True, null=True)
deadline = models.DateTimeField(null=True)
list_category = models.ForeignKey(Category, on_delete=models.CASCADE, null=True, related_name='sortion')
closed = models.BooleanField(default=False)
def __str__(self):
return f'{self.item_name} - {self.price}'
class Bid(models.Model):
bid = models.IntegerField()
user = models.ForeignKey(User, on_delete=CASCADE)
auction = models.ForeignKey(AuctionListing, on_delete=CASCADE)
bid_date = models.DateTimeField(auto_now=True)
def __str__(self):
return f'{self.bid}-{self.auction}'
class Comment(models.Model):
user = models.ForeignKey(User, on_delete=CASCADE)
com = models.TextField()
pub_date = models.DateField()
com_item = models.ForeignKey(AuctionListing, on_delete=models.CASCADE, related_name='get_comment')
def __str__(self):
return f'{self.user} - {self.pub_date}'
Views.py:
from django.contrib.auth import authenticate, login, logout
# from django.contrib.auth.decorators import login_required
from django.db import IntegrityError, reset_queries
from django.http import HttpResponse, HttpResponseRedirect
from django.shortcuts import redirect, render
from django.urls import reverse
from django.forms import ModelForm
from .models import *
def index(request):
active_list = AuctionListing.objects.all().order_by('id').reverse()
return render(request, "auctions/index.html", {'active_list': active_list })
def login_view(request):
if request.method == "POST":
# Attempt to sign user in
username = request.POST["username"]
password = request.POST["password"]
user = authenticate(request, username=username, password=password)
# Check if authentication successful
if user is not None:
login(request, user)
return HttpResponseRedirect(reverse("index"))
else:
return render(request, "auctions/login.html", {
"message": "Invalid username and/or password."
})
else:
return render(request, "auctions/login.html")
def logout_view(request):
logout(request)
return HttpResponseRedirect(reverse("index"))
def register(request):
if request.method == "POST":
username = request.POST["username"]
email = request.POST["email"]
# Ensure password matches confirmation
password = request.POST["password"]
confirmation = request.POST["confirmation"]
if password != confirmation:
return render(request, "auctions/register.html", {
"message": "Passwords must match."
})
# Attempt to create new user
try:
user = User.objects.create_user(username, email, password)
user.save()
except IntegrityError:
return render(request, "auctions/register.html", {
"message": "Username already taken."
})
login(request, user)
return HttpResponseRedirect(reverse("index"))
else:
return render(request, "auctions/register.html")
class CreateForm(ModelForm):
class Meta:
model = AuctionListing
fields = ['item_name', 'item_image', 'detail', 'price', 'deadline', 'list_category']
def create_listing(request):
user = request.user
if user.id is None:
return redirect('login')
if request.method == 'GET':
context = {
'form': CreateForm()
}
return render(request, 'auctions/create_listing.html', context)
else:
if request.method == 'POST':
form = CreateForm(request.POST or None, request.FILES or None)
if form.is_valid():
item_name = form.cleaned_data['item_name']
item_image = form.cleaned_data['item_image']
detail = form.cleaned_data['detail']
price = form.cleaned_data['price']
deadline = form.cleaned_data['deadline']
list_category = form.cleaned_data['list_category']
listing_created = AuctionListing.objects.create(
item_name = item_name,
item_image = item_image,
detail = detail,
price = price,
deadline = deadline,
list_category = list_category,
user = request.user,
)
listing_created.save()
return redirect('index')
def listing(request, pk):
user = request.user
list = AuctionListing.objects.get(id=pk)
if request.method == 'POST':
bid = request.POST.get('placebid')
user = request.user
form = Bid(bid=bid, user=user, auction=list)
form.save()
return render(request, 'auctions/listing.html', {'list': list})
The index.html is:
{% extends "auctions/layout.html" %}
{% block body %}
<h2>Active Listings</h2>
{% for each in active_list %}
<div class="back">
<div class="imag">
<img src="{{ each.item_image.url }}" alt="">
</div>
<div class="detail">
<h1>{{ each.item_name }}</h1>
<h6>Published by: <span>{{ each.user }}</span></h6>
{% if each.last_bid %}
<p>Current Bid: <span>{{ each.last_bid.bid }} </span></p>
{% else %}
<p>Current Bid: <span>{{ each.price }} </span></p>
{% endif %}
<p>Published date: <span>{{ each.pub_date }}</span></p>
<p>DeadLine: <span>{{ each.deadline }}</span></p>
<div class="bid-detail">
<p>Initial Price: {{ each.price }}</p>
<p>Watchers: 10</p>
</div>
</div>
</div>
{% endfor %}
{% endblock %}
I want to display the last_bid in index.html but I was not able to. Please help me with this problem. I will be thankful to you.
I have been working on a follow system like in instagram in which a user can follow and unfollow other users, also a profile has to display the number of followers the selected user has and the number of people that user is following. Everything is working fine except for the followers count which is not displaying any number rather than 0 which is the default even tho the user has one or more followers. How can a count function be added to this django project?
models.py
class Profile(models.Model):
user = models.OneToOneField(User, on_delete=models.CASCADE)
profile_pic = models.ImageField(upload_to='profile_pics', null=True, blank=True, default='default.png')
bio = models.CharField(max_length=400, default=1, null=True)
connection = models.CharField(max_length = 100, blank=True)
follower = models.IntegerField(default=0)
following = models.IntegerField(default=0)
def __str__(self):
return f'{self.user.username} Profile'
class Following(models.Model):
user = models.OneToOneField(User, on_delete=models.CASCADE)
followed = models.ManyToManyField(User, related_name="followed")
follower = models.ManyToManyField(User, related_name="follower")
#classmethod
def follow(cls, user, another_account):
obj, create = cls.objects.get_or_create(user = user)
obj.followed.add(another_account)
print("followed")
#classmethod
def unfollow(cls, user, another_account):
obj, create = cls.objects.get_or_create(user = user)
obj.followed.remove(another_account)
print("unfollowed")
def __str__(self):
return f'{self.user.username} Profile'
views.py
def profile(request, username=None):
profile, created = Profile.objects.get_or_create(user=request.user)
user = User.objects.filter(username=username)
if user:
post_owner = get_object_or_404(User, username=username)
profile_bio = Profile.objects.filter(user_id=post_owner)
user_posts = Post.objects.filter(user_id=post_owner)
user = user[0]
is_following = Following.objects.filter(user=request.user, followed=user)
following_obj = Following.objects.get(user=user)
follower = following_obj.follower.count()
following = following_obj.followed.count()
else:
post_owner = request.user
user_posts = Post.objects.filter(user=request.user)
profile_bio = Profile.objetcs.filter(user=request.user)
args1 = {
'user_obj':user,
'post_owner': post_owner,
'user_posts': user_posts,
'follower': follower,
'following': following,
'connection': is_following,
'profile_bio': profile_bio,
}
return render(request, 'profile.html', args1)
def follow(request, username):
main_user = request.user
to_follow = User.objects.get(username=username)
following = Following.objects.filter(user = main_user, followed = to_follow)
is_following = True if following else False
if is_following:
Following.unfollow(main_user, to_follow)
is_following = False
else:
Following.follow(main_user, to_follow)
is_following = True
resp = {
'following': is_following,
}
response = json.dumps(resp)
return HttpResponse(response, content_type="application/json")
profile.html
<div class="header-item">
{{ follower }}
</div>
<div class="header-item">
{{ following }}
</div>
{% if connection %}
<a type="button" class="button-caballo" id="follow" role="button" href="{% url 'follow' user_obj.username %}">Unfollow</a>
{% elif not connection %}
<a type="button" class="button-caballo" id="follow" role="button" href="{% url 'follow' user_obj.username %}">Follow</a>
{% endif %}
You have to change follow function like this :
def follow(request, username):
main_user = request.user
to_follow = User.objects.get(username=username)
following = Following.objects.filter(user = main_user, followed = to_follow).first()
if following is not None:
Following.unfollow(main_user, to_follow)
is_following = False
main_user.following -= 1
to_follow.follower -= 1
else:
Following.follow(main_user, to_follow)
is_following = True
main_user.following += 1
to_follow.follower += 1
main_user.save()
to_follow.save()
resp = {
'following': is_following,
}
response = json.dumps(resp)
return HttpResponse(response, content_type="application/json")
I have been trying make users follow other users from thier posts like in instagrams explore page. Currently a user can just follow and unfollow other users from their profile but I will like to have that follow/unfollow on their posts too. I tried to make this happen but in the process I got a NameError name 'username' is not defined, How can I fix this error in order to make this work?
models.py (mates model is where the follow/unfollow should go)
class Mates(models.Model):
user = models.OneToOneField(User, on_delete=models.CASCADE, related_name='usermates', unique=True)
req_bio = models.CharField(max_length=400)
class Following(models.Model):
user = models.OneToOneField(User, on_delete=models.CASCADE)
followed = models.ManyToManyField(User, related_name="followed")
follower = models.ManyToManyField(User, related_name="follower")
#classmethod
def follow(cls, user, another_account):
obj, create = cls.objects.get_or_create(user = user)
obj.followed.add(another_account)
print("followed")
#classmethod
def unfollow(cls, user, another_account):
obj, create = cls.objects.get_or_create(user = user)
obj.followed.remove(another_account)
print("unfollowed")
def __str__(self):
return f'{self.user.username} Profile'
class Profile(models.Model):
user = models.OneToOneField(User, on_delete=models.CASCADE)
profile_pic = models.ImageField(upload_to='profile_pics', null=True, blank=True, default='default.png')
bio = models.CharField(max_length=400, default=1, null=True)
connection = models.CharField(max_length = 100, blank=True)
follower = models.IntegerField(default=0)
following = models.IntegerField(default=0)
def save(self, *args, **kwargs):
super().save(*args, **kwargs)
img = Image.open(self.profile_pic.path)
if img.height > 300 or img.width > 300:
output_size = (300,300)
img.thumbnail(output_size)
img.save(self.profile_pic.path)
def __str__(self):
return f'{self.user.username} Profile'
views.py
def matesmain(request):
if request.user.has_posts():
contents = Mates.objects.filter(
categories__in=['action', 'sports', 'shooter', 'battle_royale', 'adventure', 'racing']
)
mates_owner = get_object_or_404(User, username=username)
context = {
'contents': contents,
'mates_owner': mates_owner,
}
print("nice3")
return render(request, 'mates.html', context)
else:
return render(request, 'mates-error.html')
def follow(request, username):
main_user = request.user
to_follow = User.objects.get(username=username)
following = Following.objects.filter(user = main_user, followed = to_follow)
is_following = True if following else False
if is_following:
Following.unfollow(main_user, to_follow)
is_following = False
else:
Following.follow(main_user, to_follow)
is_following = True
resp = {
'following': is_following,
}
response = json.dumps(resp)
return HttpResponse(response, content_type="application/json")
html
{% if connection and not request.user == mates_owner %}
<a type="button" class="button-caballo" id="follow" role="button" href="{% url 'follow' mates_owner.username %}">Unfollow</a>
{% elif not connection and not request.user == mates_owner %}
<a type="button" class="button-caballo" id="follow" role="button" href="{% url 'follow' mates_owner.username %}">Follow</a>
{% endif %}
urls.py
urlpatterns = [
path('follow/<str:username>', views.follow, name='follow')
path('mates-main', views.matesmain, name='mates-main'),
]
traceback
Traceback (most recent call last):
File "C:\Users\USER\Envs\startup\lib\site-packages\django\core\handlers\exception.py", line 34, in inner
response = get_response(request)
File "C:\Users\USER\Envs\startup\lib\site-packages\django\core\handlers\base.py", line 115, in _get_response
response = self.process_exception_by_middleware(e, request)
File "C:\Users\USER\Envs\startup\lib\site-packages\django\core\handlers\base.py", line 113, in _get_response
response = wrapped_callback(request, *callback_args, **callback_kwargs)
File "C:\Users\USER\startup\gstartup\startup_home\views.py", line 126, in matesmain
mates_owner = get_object_or_404(User, username=username)
NameError: name 'username' is not defined
[16/Jul/2020 08:53:25] "GET /mates-main HTTP/1.1" 500 70246
I am trying to add a follow sistem to my django project my when running my code, I am getting a The QuerySet value for an exact lookup must be limited to one result using slicing. error, It is saying that the wrong part is on this line of code of the views.py file following_obj = Following.objects.get(user=user).
views.py
def profile(request, username=None):
profile, created = Profile.objects.get_or_create(user=request.user)
if username:
post_owner = get_object_or_404(User, username=username)
user_posts = Profile.objects.filter(user_id=post_owner)
user = User.objects.filter(username=username)
is_following = Following.objects.filter(user=request.user, followed=user)
following_obj = Following.objects.get(user=user)
follower, following = following_obj.follower.count(), following_obj.followed.count()
else:
post_owner = request.user
user_posts = Profile.objects.filter(user=request.user)
args1 = {
'post_owner': post_owner,
'user_posts': user_posts,
'connection': is_following,
'follower': follower,
'following': following,
}
return render(request, 'profile.html', args1)
def follow(request, username):
main_user = request.user
to_follow = User.objects.get(username=username)
following = Following.objects.filter(user = main_user, followed = to_follow)
is_following = True if following else False
if is_following:
Following.unfollow(main_user, to_follow)
is_following = False
else:
Following.follow(main_user, to_follow)
is_following = True
resp = {
'following': is_following,
}
response = json.dumps(resp)
return HttpResponse(response, content_type="application/json")
models.py
class Profile(models.Model):
user = models.ForeignKey(User, on_delete=models.CASCADE)
profile_pic = models.ImageField(upload_to='profile_pics', null=True, blank=True, default='default.png')
bio = models.CharField(max_length=400, default=1, null=True)
follower = models.IntegerField(default=0)
following = models.IntegerField(default=0)
def __str__(self):
return f'{self.user.username} Profile'
class Following(models.Model):
user = models.OneToOneField(User, on_delete=models.CASCADE)
followed = models.ManyToManyField(User, related_name="followed")
follower = models.ManyToManyField(User, related_name="follower")
#classmethod
def follow(cls, user, another_account):
obj, created = cls.objects.get(user = user)
obj.followed.add(another_account)
print("followed")
#classmethod
def unfollow(cls, user, another_account):
obj, create = cls.objects.get(user = user)
obj.followed.remove(another_account)
print("unfollowed")
def __str__(self):
return f'{self.user.username} Profile'
profile.html
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.5.1/jquery.min.js"></script>
{% if connection and not request.user == post_owner %}
<a type="button" class="btn btn-outline-primary" id="follow" role="button" href="{% url 'follow' post_owner.username %}">Unfollow</a>
{% elif not connection and not request.user == post_owner %}
<a type="button" class="btn btn-outline-primary" id="follow" role="button" href="{% url 'follow' post_owner.username %}">Follow</a>
{% endif %}
<p>Follower : {{follower}} Following : {{following}}</p>
<script type="text/javascript">
$("#follow").click(function(e){
e.preventDefault();
var href = this.href;
$.ajax({
url : href,
success : function(response){
if(response["following"]){
$("#follow").html("Unfollow");
}
else{
$("#follow").html("Follow");
}
}
})
})
</script>
The line:
user = User.objects.filter(username=username)
returns a collection of User objects, you should retrieve a single one with .get(…) [Django-doc]:
user = User.objects.get(username=username)
Django version 2.2
I have models in django
class Class_teacher(models.Model):
first_name = models.CharField(max_length=200)
last_name = models.CharField(max_length=200)
empid = models.CharField(max_length=10)
standard = models.IntegerField()
division = models.CharField(max_length=1)
subject = models.CharField(max_length=200)
email = models.EmailField(max_length=30)
def __str__(self):
return self.first_name + ' -- ' + str(self.school)
class Student(models.Model):
first_name = models.CharField(max_length=200)
last_name = models.CharField(max_length=200)
classteacher = models.ForeignKey('Class_teacher', on_delete=models.CASCADE, )
reg_id = models.CharField(max_length=15)
parent_first_name = models.CharField(max_length=200)
parent_second_name = models.CharField(max_length=200)
email = models.EmailField(max_length=100)
def __str__(self):
return self.first_name + ' ' + self.last_name
views for adding student
class StudentCreate(LoginRequiredMixin, CreateView):
login_url = '/signin/'
model = Student
fields = ['first_name', 'last_name', 'parent_first_name','parent_second_name', 'email', 'reg_id']
success_url = '/dashboard/'
The webapp has login feature as below ,
def signin(request):
if request.method == 'POST':
username = request.POST.get('username')
password = request.POST.get('password')
user = authenticate(username=username, password=password)
if user:
if user.is_active:
login(request, user)
return HttpResponseRedirect('../dashboard/')
else:
return HttpResponse("Your account was inactive.")
else:
return HttpResponse("Invalid login details given")
else:
return render(request, 'webapp/login.html')
def dashboard(request):
email = request.user.email
if Class_teacher.objects.filter(email__iexact=email).count() == 1:
students = Student.objects.values('classteacher')
context = { 'students' : students}
return render(request, 'webapp/dashboard.html',context)
dashboard.html template
{% if students %}
<ol>
{% for student in students %}
<li>{{student.first_name}} {{student.last_name}}</li>
{% endfor %}
</ol>
{% else %}
<h3>No Students Added</h3>
{% endif %}
{% endblock %}
I used students = Student.objects.values('classteacher') but it doesnot provide with students names , just display an ordered list numbers .
I have two requirements
I have a modelform where the logged in teacher can add students , while I am adding students using the first mentioned view above it is triggering an error 'NOT NULL constraint failed: webapp.classteacher_id' , and when I change the add views to below it works well
class StudentCreate(LoginRequiredMixin, CreateView):
login_url = '/signin/'
model = Student
fields = ['first_name', 'last_name', 'parent_first_name','parent_second_name', 'email', 'reg_id' , 'classteacher']
success_url = '/dashboard/'
What i Want with the studentadd view is students should be added under the respective logged in teacher without providing the teacher's value via form
After login , the dashboard have to display students of the respective logged in teacher
You have filtered your students incorrectly.
Try this:
def dashboard(request):
email = request.user.email
class_teacher = Class_teacher.objects.get(email=email)
students = Student.objects.filter(classteacher=class_teacher)
return render(request, 'webapp/dashboard.html', {'students': students})