问题
I have been trying to add friend system in which the user can add and remove friends (other users), after finishing with the code, I found an error that when the logedin user tries to add a friend from other user's profile, the add friend button redirects to the logedin user profile making it imposible to add a new friend, it can just add himself as a friend. I personally think the error is on the views.py profile view.
views.py (profile shows user's profile and change_friend is the one that adds and removes frinds)
def profile(request, username=None):
friend = Friend.objects.filter(current_user=request.user).first()
friends = []
if friend:
friends = friend.users.all()
if username:
post_owner = get_object_or_404(User, username=username)
user_posts=Post.objects.filter(user_id=post_owner)
else:
post_owner = request.user
user_posts=Post.objects.filter(user=request.user)
args1 = {
'post_owner': post_owner,
'user_posts': user_posts,
'friends': friends,
}
return render(request, 'profile.html', args1)
def change_friends(request, operation, pk):
friend = User.objects.get(pk=pk)
if operation == 'add':
Friend.make_friend(request.user, friend)
elif operation == 'remove':
Friend.lose_friend(request.user, friend)
return redirect('profile')
models.py
class Friend(models.Model):
users = models.ManyToManyField(User, default='users', blank=True, related_name='users')
current_user = models.ForeignKey(User, related_name='owner', on_delete=models.CASCADE, null=True)
@classmethod
def make_friend(cls, current_user, new_friend):
friend, created = cls.objects.get_or_create(
current_user=current_user
)
friend.users.add(new_friend)
@classmethod
def lose_friend(cls, current_user, new_friend):
friend, created = cls.objects.get_or_create(
current_user=current_user
)
friend.users.remove(new_friend)
profile.html
<div class="media">
<div class="media-body">
<h2 class="account-heading">{{ post_owner.username }}</h2>
<p class="text-secondary">{{ post_owner.email }}</p>
{% if not user in friends %}
<a href="{% url 'change_friends' operation='add' pk=user.pk %}">
<button type="button">add Friend</button>
</a>
{% endif %}
</div>
</div>
<div>
<h2>Friends</h2>
{% for friend in friends %}
<p>{{ friend.username }}</p>
<a href="{% url 'change_friends' operation='remove' pk=friend.pk %}">
<button type="button">Remove Friend</button>
</a>
{% endfor %}
</div>
urls.py
urlpatterns = [
path('profile/<str:username>/', views.profile, name='profile_pk'),
url(r'^connect/(?P<operation>.+)/(?P<pk>\d+)/$', views.change_friends, name='change_friends'),
]
回答1:
The problem is that you're passing the request.user
object to the change_friends
view, through the user
object. By default user == request.user
when used in a template.
Just change that line that you have in profile.html with:
<a href="{% url 'change_friends' operation='add' pk=post_owner.pk %}">
<button type="button">add Friend</button>
</a>
Now, I note that you're redirecting the user to the profile
view once they add a new friend, and that's not what you want. That's happening because when you're calling the redirect()
function in your change_friends
view, you are not passing any parameter to the profile
view. You defined the username should be None
by default and then you're saying that if not username
then post_owner
should be request.user
How to change this? Well, just pass the desired username
when calling redirect
as a keyword argument. Something as follows:
return redirect('profile', username=friend.username)
回答2:
In your view, friends address to already added friends, you want to get the users are eligible to add as friend to request.user object. To achieve this,
In your profile view:
def profile(request, username=None):
friend = Friend.objects.filter(current_user=request.user).first()
friends = []
# In case of friend is None, I send all users except request user, to be able to add on html template.
friends_to_add = User.objects.exclude(id=request.user.id)
if friend:
friends = friend.users.all()
# here we have a valid friend (who is the user request has)
# so I don't want to send users to template who are already friend of request user.
friends_to_add = friends_to_add.exclude(id__in=friend.users.values_list("id"))
if username:
post_owner = get_object_or_404(User, username=username)
user_posts=Post.objects.filter(user_id=post_owner)
else:
post_owner = request.user
user_posts=Post.objects.filter(user=request.user)
args1 = {
'post_owner': post_owner,
'user_posts': user_posts,
'friends': friends,
'friends_to_add': friends_to_add,
}
return render(request, 'profile.html', args1)
In your template file, you can use them as:
<div class="media">
<div class="media-body">
<h2 class="account-heading">{{ post_owner.username }}</h2>
<p class="text-secondary">{{ post_owner.email }}</p>
{% for user in friends_to_add %}
<a href="{% url 'change_friends' operation='add' pk=user.pk %}">
<button type="button">add Friend</button>
</a>
{% endfor %}
</div>
</div>
I hope this will make sense to you. You can ask me anything you cannot understand above from comments if you need.
来源:https://stackoverflow.com/questions/61831356/add-a-friend-system-on-django