Reputation: 365
In my project, users have a manytomanyfield of users they are following. When they look at the list of users who are following them, I want to show a Follow/Unfollow link depending on if they have that person in their following list. For example, if B is following A, and A is following B, then there should be an Unfollow link next to B's name when A views their following list.
unfortunately, it always says "(Follow)" and never gives me the "(Remove)" link even if I'm logged in as a user that's already following that user.
My userprofile model:
class UserProfile(models.Model):
user = models.OneToOneField(User, related_name='user_object')
visible = models.BooleanField(default=True)
bio = models.TextField(null=True, blank=True)
avatar = models.FileField(upload_to=get_upload_file_name, null=True, blank=True)
following = models.ManyToManyField(User, related_name='following_list')
and the code I am trying to use in my template:
{% for f in followers %}
<a href="/accounts/profile/{{f.user.id}}/">{{f.user.username}}</a>
{% if thisuser.user_object.following.all == f.user %}
<a href="/accounts/profile/{{f.user.id}}/unfollow/">(Remove)</a>
{% else %}
<a href="/accounts/profile/{{f.user.id}}/follow/">(Follow)</a>
{% endif %}
{% endfor %}
In my views, I am sending:
def followers(request, user_id=1):
thisuser = request.user
userlookup = User.objects.get(id=user_id)
following = thisuser
followers = UserProfile.objects.filter(following=thisuser)
args = {'following': following, 'thisuser': thisuser, 'userlookup': userlookup, 'followers': followers}
args.update(csrf(request))
return render_to_response('followers.html', args)
Upvotes: 1
Views: 1019
Reputation: 174622
Decorate your objects in your view to make life in your template easier:
from django.shortcuts import render
def followers(request, user_id=1):
user = User.objects.get(pk=user_id)
followers = UserProfile.objects.filter(following=request.user)
args = {}
args['following'] = request.user
args['userlookup'] = User.objects.get(pk=user_id)
args['followers'] = []
for f in followers:
user_status = (f, request.user.user_object.following_list.filter(pk=f.pk).exists())
args['followers'].append(user_status)
return render(request, 'followers.html', args)
The key part is this:
(f, request.user.user_object.following_list.filter(pk=f.pk).exists())
This is a 2-tuple, the first item is the user profile object, and the second item is either True or False if this user is being followed. The exists()
queryset method returns True if the query would have returned results. I use this to flag each user object.
I then collect this "decorated" lists of user profile objects in a list, which is sent as the context variable followers to the template.
You should avoid doing complex logic in the templates, and whenever possible use the views to send extra information about your objects. This not only enhances the performance of your application (templates are not optimal for heavy processing and the most difficult part to debug); but also keeps your templates free from any logic - beyond what is required to display things.
Now, in your template:
{% for f,following in followers %}
<a href="/accounts/profile/{{f.user.id}}/">{{f.user.username}}</a>
{% if following %}
<a href="/accounts/profile/{{f.user.id}}/unfollow/">(Remove)</a>
{% else %}
<a href="/accounts/profile/{{f.user.id}}/follow/">(Follow)</a>
{% endif %}
{% endfor %}
You don't need to pass request.user
to the template, instead make sure the request context processor is enabled in your settings:
import django.conf.global_settings as DEFAULT_SETTINGS
TEMPLATE_CONTEXT_PROCESSORS += DEFAULT_SETTINGS.TEMPLATE_CONTEXT_PROCESSORS+(
'django.core.context_processors.request',
)
Upvotes: 1