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'),
]
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)
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.
Related
I have a social media website that will allow a user to view another users profile page by clicking their username from one of their posts that appears in the feed section of my page. I have view_profile view created but need to pass in the desired users username into the view, to only show posts, activity, etc... made by that specific user. How do i pass the username into my view?
view_profile.html
<section id="main_feed_section" class="feed_sections">
{% for post in posts %}
<div class="post_main_container">
<section class="post_title">
<h1> {{ post.user_id.username }}{{ post.title }}</h1>
</section>
<section class="post_main_body">
<p>{{ post.caption }}</p>
</section>
<section class="post_footer">
<p>{{ post.date_posted }}</p>
</section>
</div>
{% endfor %}
</section>
views.py
def view_profile(request):
account = "logan9997" #if a post made by logan9997 was clicked
posts = [post for post in Posts.objects.all()
if post.user_id.username == account]
followers = [follower for follower in Relationships.objects.all()
if follower.acc_followed_id.username == account]
context = {
"title":account,
"posts":posts,
"followers":followers
}
return render(request, "myApp/view_profile.html", context)
urls.py
from django.urls import path
from . import views
urlpatterns = [
path("home/", views.home, name="home"),
path("create_post/", views.create_post, name="create_post"),
path('view_profile/<str:username>', views.view_profile, name="view_profile"),
]
Add a variable to your view:
def view_profile(request, account):
...
And urls:
path('view_profile/<str:account>', ...)
Then you can go to url: localhost:8000/view_profile/logan9997.
You can do it better with User id:
path('view_profile/<int:pk>', ...)
def view_profile(request, pk):
account = User.objects.get(id=pk).username
...
And go for: localhost:8000/view_profile/1
This is very not Django-style:
posts = [post for post in Posts.objects.all()
if post.user_id.username == account]
Use filter() method instead:
posts = Posts.objects.filter(user_id__username=account)
# and
followers = Relationships.objects.filter(acc_followed_id__username=account)
I am trying to avoid duplicate email in my website form . Till now I was able to do this:
1.Whenever I enter duplicate email, it navigate back to homepage and user is not saved{ In my case team is not joined}.
2.In admin page when I try to enter duplicate email , I get my error message of duplicate email address
I want this message in my form too, but it navigates to homepage.
This is my model in models.py:
class Team(models.Model):
username = models.CharField(max_length=100)
email = models.EmailField(max_length=100,unique=True,error_messages={'unique':"Email already exists"})
contact=models.IntegerField(null=False,blank=False,default=1234567890)
def __str__(self):
return self.username
This is my form in forms.py:
class TeamMembers(forms.ModelForm):
username = forms.CharField(required=True,max_length=100)
email = forms.EmailField(required=True,max_length=100,error_messages={'unique':"Email already exists"})
contact=forms.IntegerField(required=True)
class Meta:
model=Team
fields = ['username','email','contact']
This is my function in views.py
def join_team(request):
if request.method == "POST":
form = TeamMembers(request.POST)
if form.is_valid():
form.save()
form = TeamMembers()
messages.success(request,"Joined team")
else:
form = TeamMembers()
return render(request, 'user/join_team.html', {'form' : form })
This is my join_team.html
{% extends 'base.html' %}
{%load crispy_forms_tags%}
{% block content %}
<div class="content-section">
<form method="POST">
{% csrf_token %}
<fieldset class="form-group">
<legend class="border-bottom mb-4">Join our team</legend>
{{form|crispy}}
</fieldset>
<div class="form-group">
<button class="btn btn-outline-info" type="submit">Join</button>
</div>
</form>
</div>
{% endblock content %}
I want to display error message on form page instead of going to homepage.
I am not able to find this question anywhere , so please help me!!
I am making a bank website in which users can make accounts, withdrawal, deposit and see transaction history. I have been working on them for two weeks. The Login and Signup works and it saves the email, username and password but when I input the amount the request works and I get redirected without any errors but the amount(balance) doesn't get saved. I then tried hardcoding the amount and then change it later when a person withdraws or deposits. Still, the same results when I try displaying the current balance on the dashboard it stays blank. I have pasted the code down and I am using Django 3.0 +
Views.py
from django.shortcuts import render, redirect
from django.contrib.auth import logout, authenticate, login
from accounts.forms import SignUpForm
from django.contrib.auth.forms import AuthenticationForm, User
from django.contrib.auth.decorators import login_required
from django.contrib import messages
# Welcome, Login, Signup
def welcome(request):
return render(request, 'accounts/welcome.html')
def signup(request):
if request.method == 'POST':
form = SignUpForm(request.POST)
if form.is_valid():
user = form.save(commit=False)
username = form.cleaned_data.get('username')
password = form.cleaned_data.get('password1')
user.amount = 500
user.save()
u = authenticate(username=username, password=password)
return redirect('login-page')
else:
messages.error(request, 'Invalid input or missing fields. Please try again!')
return redirect('signup-page')
else:
form = SignUpForm()
return render(request, 'accounts/signup.html', {'form': form})
def login_view(request):
if request.method == 'POST':
form = AuthenticationForm(data=request.POST)
if form.is_valid():
username = form.cleaned_data.get('username')
password = form.cleaned_data.get('password')
user = authenticate(username=username, password=password)
if user is not None:
login(request, user)
return redirect('dashboard')
else:
messages.error(request,'Invalid login credentials. Please try agian.')
return redirect('login-page')
else:
messages.error(request,'Invalid login credentials. Please try agian.')
return redirect('login-page')
form = AuthenticationForm()
return render(request, 'accounts/login.html', {'form': form})
# Dashboard, Transfer, Transactions
#login_required(login_url='/login/')
def dashboard(request):
user = User.objects.all()
return render(request, 'accounts/dashboard.html', {'user': user})
Forms.py
from django import forms
from django.contrib import messages
from django.contrib.auth.forms import UserCreationForm, User
class SignUpForm(UserCreationForm):
email = forms.EmailField(max_length=128, help_text='Input valid email')
class Meta:
model = User
fields = ('username', 'email', 'password1', 'password2')
dashboard.html
{% extends 'accounts/base.html' %}
{% load static %}
{% block content %}
<div class="row">
<div class="col-sm-4">
<div class="card">
<div class="card-body">
<h5 class="card-title">Current Balance</h5>
<p class="card-text">{{ request.user.amount }}</p>
</div>
</div>
</div>
<div class="col-sm-4">
<div class="card">
<div class="card-body">
<h5 class="card-title">Total Expenses</h5>
<p class="card-text">Amount goes here.</p>
</div>
</div>
</div>
<div class="col-sm-4">
<div class="card">
<div class="card-body">
<h5 class="card-title">Total Spent</h5>
<p class="card-text">Amount goes here.</p>
</div>
</div>
</div>
<div class="col-sm-4 py-4">
<div class="card">
<div class="card-body extended">
<h5 class="card-title">Credit Card</h5>
<h4 class="card-subtitle" id="cc">**** **** **** 1234</h4>
<div id="med-pad">
<p class="card-text medium">{{ request.user.username }}</p>
<p class="card-text medium">Valid Through: 07/22</p>
</div>
<p id="cvv-pad" class="card-text">CVV: 001</p>
</div>
</div>
</div>
<div class="col-sm-8 py-4">
<div class="card">
<div class="card-body extended">
<h5 class="card-title">Total Spent</h5>
<p class="card-text">Amount goes here.</p>
</div>
</div>
</div>
</div>
{% endblock %}
I tried the models but they messed up the current login and signup form. I am using Django 3.0 and am fairly new so please any help would be appreciated!
So if I understand correctly, you want to set an 'amount' attribute for an user.
If so: the default user model (the user model comes out of the box with Django), does not have an amount field included. You will have to extend the user model and add the field 'amount' to it.
Unfortunately I cannot test the following, however I believe if you create a
models.py with the following:
from django.db import models
from django.contrib.auth.models import User
class BankAccount(models.Model):
user = models.OneToOneField(User, on_delete=models.CASCADE)
amount = models.FloatField()
it should work. Make sure you do your migrations after creating this model.
I'm doing a Django blog website project.
One of my features is when you log in, you can click on the tab Other members to show you a list of other members; like this picture
.
However, as of now, this feature only works when I login as one specific account which is an admin. When I log in as other members (not the admin) or another admin account, the feature is not working; that means when I click the tab Other Members it will display errors like
"Friend matching query does not exist"
I'm really confused and getting stuck on this one. Any ideas how to solve it?
Here is my code:
**list_users.html **
{% extends "blog/base.html" %}
{% block content %}
<div class="container">
<div class="col-sm-6">
<h2>Other People</h2>
{% for user in users %}
<a href="{% url 'view_profile_with_pk' pk=user.pk %}">
<h3>{{ user.username }}</h3>
</a>
{% if not user in friends %}
<a href="{% url 'change_friends' operation='add' pk=user.pk %}">
<button type="button" class="btn btn-success">Add Friend</button>
</a>
{% endif %}
{% endfor %}
</div>
<br>
<div class="col-sm-6">
<h2>Friends</h2>
{% for friend in friends %}
<a href="{% url 'view_profile_with_pk' pk=friend.pk %}">
<h3>{{ friend.username }}</h3>
</a>
<a href="{% url 'change_friends' operation='remove' pk=friend.pk %}">
<button type="button" class="btn btn-default">Remove Friend</button>
</a>
{% endfor %}
</div>
</div>
{% endblock content %}
views.py function listusers
def listusers(request):
posts = Post.objects.all().order_by()
users = User.objects.exclude(id=request.user.id)
friend = Friend.objects.get(current_user=request.user)
friends = friend.users.all()
context = {
'posts': posts, 'users': users, 'friends': friends
}
return render(request, 'blog/list_users.html', context)
model.py class Friend
class Friend(models.Model):
users = models.ManyToManyField(User)
current_user = models.ForeignKey(User, related_name='owner', null=True, on_delete=models.CASCADE)
It's because you are using get operator to get the friend. The problem as the image you provided shows, is in line 25 of your views. in below method:
friend = Friend.objects.get(current_user=request.user)
you are trying to get an item which does not exist. There is no friend that it's current_user is the requested user.
you can fix it like this:
friend = Friend.objects.filter(current_user=request.user).first()
if friend:
friends = friend.users.all()
else:
friends = User.objects.none()
Try to use filter instead of get . get throws exception when there's no matching result.
Have a look at filter
Friend.objects.filter(current_user=request.user).first()
Another approach is to create a Friend instance if a user does not have one. You can use get_or_create for this. For example:
users = User.objects.exclude(id=request.user.id)
friend, created = Friend.objects.get_or_create(current_user=request.user) # or have other necessary fields for Friend field
friends = friend.users.all()
context = {
'posts': posts, 'users': users, 'friends': friends
}
return render(request, 'blog/list_users.html', context)
I am new to django and I am trying to create a review system, whereby each team member reviews all the other members within their team.
Here is my models.py file:
from django.db import models
from django.contrib.auth.models import User
class Team(models.Model):
name = models.CharField(max_length=25)
def __str__(self):
return self.name
class Trait(models.Model):
name = models.CharField(max_length=25)
def __str__(self):
return self.name
class Review(models.Model):
reviewer = models.ForeignKey(User, on_delete=models.CASCADE,
related_name='reviewer_id')
reviewee = models.ForeignKey(User, on_delete=models.CASCADE,
related_name='reviewee_id')
trait = models.ForeignKey(Trait, on_delete=models.CASCADE)
trait_score = models.IntegerField()` return
This is my views.py file:
from django.shortcuts import render, redirect
from review.forms import ReviewForm
from django.http import HttpResponse
from django.contrib.auth.models import User
from accounts.models import UserProfile
def positivity_review(request):
if request.method == 'POST':
form = ReviewForm(request.POST)
if form.is_valid():
form.save()
return redirect('/review/relationships')
else:
form = ReviewForm()
users = UserProfile.objects.filter(review_team=1)
args = {'form': form, 'team_members': users}
return render(request, 'review/positivity.html', args)` return
This is my forms.py file:
from django import forms
from django.forms.widgets import NumberInput
from review.models import Team, Review
class RangeInput(NumberInput):
input_type = 'range'
class ReviewForm(forms.ModelForm):
trait_score = forms.IntegerField(widget=RangeInput, min_value=0,
max_value=100, label='')
class Meta:
model = Review
fields = (
'trait_score',
)` return
This is the HTML file:
{% extends 'base.html' %}
{% block head %}
<title>Review</title>
{% endblock %}
{% block content %}
<br>
<h1>Review</h1>
<h2>Do they foster a postive climate?</h2>
<div class="row">
<div class="col-md-2">
<p>Exhibits a lack of awareness for a positive climate. Resistance to prompting.</p>
</div>
<div class="col-md-2">
<p>Cooperates at times, within structured activities and friendly under prompting.</p>
</div>
<div class="col-md-2">
<p>Cooperates within the team environment without prompting.</p>
</div>
<div class="col-md-2">
<p>Cooperates well with others, enthusiastic and positve. Occationally prompts others to engage positively.</p>
</div>
<div class="col-md-4">
<p>Seeks to continuously and consistently create a positive environment. Acts as a role model for the team through prompting being supportive and encouraging and showing genuine concern for others.</p>
</div>
</div>
<div>
<form method="post">
{% for user in team_members %}
<p>Reviewing: {{ user.first_name }} {{ user.last_name }}</p>
{% csrf_token %}
{{ form.as_p }}
{% endfor %}
<button class="btn btn-primary" type="submit">Next</button>
</form>
</div>
{% endblock %}`
Currently I am passing in the queryset through the views.py into the html file and looping through it to load the relevant number of team members.
Since I am loading a form each time for each individual in the team, how can I make the form submit so that it knows who is being reviewed? For example, submitting the reviewer, trait and score is simple as most of that can be passed directly into the view, however, submitting the reviewee (person being reviewed) is the part im not sure how to handle, as they are loaded within the form using the template tagging. I was wondering if it is possible to submit some kind of data back into the form such as first + last name or thier user id, anything so that when I go to publish the results I have a way of filtering individuals results.
Hopefully the description is sufficient. Thanks in advance!
If I understand your question correctly, this might be the answer.
First, create a simple form (rather than ModelForm) and add this, among other things:
pk = forms.CharField(
widget=forms.TextInput(
attrs={
'type': 'hidden',
}
),
label=''
)
This will hold the pk of the reviewee and won't be visible to reviewer.
Then, in the html file, I think you have to generate a separate form for each user rather than only the input (I'm not sure, try it). You can do this:
{% for user in team_members %}
<form method="post" id="review_form_{{user.pk}}">
<p>Reviewing: {{ user.first_name }} {{ user.last_name }}</p>
{% csrf_token %}
{{ form.as_p }}
<button class="btn btn-primary" type="submit">Next</button>
</form>
<script type="text/javascript">
$('#review_form_{{user.pk}}').children('#id_pk').val("{{user.pk}}");
</script>
{% endfor %}
Remember that when django generates a form, each input will have to get an id and django adds id_ to the beginning of the name of the field you create in fields.py
And lastly, when the reviewer submit a form, you can find your reveiwee in views.py this way:
form = ReviewForm(request.POST)
if form.is_valid():
reviewee_id = request.POST.get('pk')
reviewee = User.objects.get(pk=reviewee_id)