Django link to a specific users profile page - python

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)

Related

Django blog app won't display edit posts page

Currently working through the Python Crash Course Django section I've got everything but the edit posts page working. I added the edit post link under each post but this error now displays when you try to view the homepage:
Reverse for 'edit_post' with no arguments not found. 1 pattern(s) tried: ['edit_post/(?P<post_id>[0-9]+)/$']
Here is the code I've been using.
from django.db import models
# Create your models here.
class BlogPost(models.Model):
"""A topic the user is learning about"""
title = models.CharField(max_length=200)
body = models.TextField()
date_added = models.DateTimeField(auto_now_add=True)
def __str__(self):
"""A place for the user to create a blog post"""
return self.title
Views
from django.shortcuts import render, redirect
from .models import BlogPost
from .forms import BlogForm
# Create your views here.
def index(request):
"""The home page for Blog"""
return render(request, 'blogs/index.html')
def blogposts(request):
"""Show all blogposts"""
blogposts = BlogPost.objects.order_by('date_added')
context = {'blogposts': blogposts}
return render(request, 'blogs/blogposts.html', context)
def new_post(request):
"""Add a new post"""
if request.method != 'POST':
# No data submitted, create a blank form
form = BlogForm()
else:
# POST data submitted; process data
form = BlogForm(data=request.POST)
if form.is_valid():
form.save()
return redirect('blogs:blogposts')
# Display a blank or invalid form
context = {'form': form}
return render(request, 'blogs/new_post.html', context)
def edit_post(request, post_id):
current_entry = BlogPost.objects.get(id=post_id)
if request.method != 'POST':
# Initial request; pre-fill form with current entry
form = BlogForm(instance=current_entry)
else:
form = BlogForm(instance=current_entry, data=request.POST)
if form.is_valid():
form.save()
return redirect('blogs:index')
context = {'post':post, 'form':form}
return render(request, 'blogs/edit_post.html', context)
URLs
"""Defines URL patterns for blogs"""
from django.urls import path
from . import views
app_name = 'blogs'
urlpatterns = [
# Home page
path('', views.index, name='index'),
# Page that shows all topics
path('blogposts/', views.blogposts, name='blogposts'),
# Page that displays a single post
path('new_post/', views.new_post, name='new_post'),
# Page for editing a post
path('edit_post/<int:post_id>/', views.edit_post, name='edit_post'),
]
blogposts.html
{% extends "blogs/base.html" %}
{% block content %}
<p>Blog Posts</p>
<ul>
{% for blogpost in blogposts %}
<h1>{{ blogpost }}</h1>
<p>{{ blogpost.body }}</p>
Edit post
{% empty %}
<li>No blogs have been posted yet</li>
{% endfor %}
</ul>
Create a new post
{% endblock content %}
edit_post.html
{% extends "blogs/base.html" %}
{% block content %}
<p>Edit post:</p>
<form action="{% url 'blogs:edit_post' post.id %}" method='post'>
{% csrf_token %}
{{ form.as_p }}
<button name="submit">Save Changes</button>
</form>
{$ endblock content %}
You need to pass the id of the blog post you want to edit.
So in your blogposts.html try:
"{% url 'blogs:edit_post' blogpost.pk %}"

Add a friend system on django

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.

how can i access a context of function view with a separate page in base page?

i created newsletters app with below code after that i have a URL : subscribe that perfectly work and save my email after that i want to add this ability in base page for example a user don't go to subscribe page and subscribed i want directly have access in base template and subscribe .
i want to know this because i want add login form to base page and have this problem with that .
this my code and this is my template
tnx for help.
views.py
from django.shortcuts import render
def Subscribe(request):
form = SiqnupNewslettersForm(request.POST or None)
if form.is_valid():
instance = form.save(commit=False)
if SignupNewsletters.objects.filter(email=instance.email).exists():
print("this email already taken ")
else :
instance.save()
context = {
'form':form
}
template_name = "subscribe.html"
return render(request,template_name,context)
def Unsubcribe(request):
form = SiqnupNewslettersForm(request.POST or None)
if form.is_valid():
instance = form.save(commit=False)
if SignupNewsletters.objects.filter(email= instance.email).exists():
SiqnupNewslettersForm.objects.filter(email = instance).delete()
else:
print("your email is not here")
context = {
'form' : form
}
template_name = "unsubscribe.html"
return render(request,template_name,context)
subscribe.html
{% block content %}
<div class="container">
<div class="row">
<form method="POST" action="">
{% csrf_token %}
<div class="form-group">
{{ form }}
</div>
<input type='submit' class="btn btn-primary"
value="submit">
</form>
</div>
</div>
{% endblock %}
urls.py
urlpatterns = [
path('subscribe/',views.Subscribe,name="subscribe"),
path('unsubscribe/',views.Unsubcribe,name= "unsubscribe"),
]
and finally what i have to do for add newsletter form in base page ?
base.html

Allow user to edit profile information and submit it causing page to redirect to profile page.

In django I am attempting to allow that user to edit his/her profile information, press submit, and have the the change reflect in his/her profile page.
This is the code :
In the views.py document in my application
User is allowed to view the profile page
def view_profile(request):
var = { 'user' : request.user }
return render(request, 'accounts/profile.html', var)
User is allowed to edit the profile page
def edit_profile(request):
if request.method == 'POST':
form = UserChangeForm(request.POST, instance=request.user)
if form.is_valid():
form.save()
return redirect('account/profile')
else:
form = UserChangeForm(instance=request.user)
var = {'form' : form }
return render(request, 'accounts/edit_profile.html', var)
This is the urls.py document
Import modules
from django.conf.urls import url
from . import views
Defined the urls
urlpatterns = [
url(r'^profile/$', views.view_profile, name = 'view_profile'),
url(r'^profile/edit/$', views.edit_profile, name = 'edit_profile')
]
This is the edit_profile
{% extends 'base.html' %}
{% block head %}
<title>{{ user }}</title>
{% endblock %}
{% block body %}
<div class = "container">
<form method = "post">
{% csrf_token %}
{{ form.as_p }}
<button class = "btn btn-default" type="submit">Submit</button>
</form>
</div>
{% endblock %}
When I edit user model on the edit_profile.html page and submit, it redirects
from :
http://127.0.0.1:8000/account/profile/edit/
To :
http://127.0.0.1:8000/account/profile/edit/account/profile
This latter urls is not accurate, it should redirect
To :
http://127.0.0.1:8000/account/profile
This is how that page looks
When you redirect you should include a leading slash to make it an absolute url:
return redirect('/account/profile')
You can avoid hardcoding the url by using the URL pattern name instead. The redirect shortcut will reverse the url for you:
return redirect('view_profile')

How to implement forget password functionality using Django and Python

I need one help. I need to implement the forget password functionality using Django. I am using the Django signup and login page. My code is below:
login.html:
{% extends 'base.html' %}
{% block content %}
<h2>Log in</h2>
{% if form.errors %}
<p style="color: red">Your username and password didn't match. Please try again.</p>
{% endif %}
<form method="post">
{% csrf_token %}
{% for field in form %}
<p>
{{ field.label_tag }}<br>
{{ field }}<br>
{% for error in field.errors %}
<p style="color: red">{{ error }}</p>
{% endfor %}
{% if field.help_text %}
<p><small style="color: grey">{{ field.help_text }}</small></p>
{% endif %}
</p>
{% endfor %}
<button type="submit">Log in</button>
New to My Site? Sign up
</form>
{% endblock %}
views.py:
class Signup(View):
""" this class is used for user signup """
def get(self, request):
""" this function used to get the sign up form """
form = UserCreationForm()
return render(request, 'plant/signup.html', {'form': form})
def post(self, request):
""" this function used for post the sign up data """
form = UserCreationForm(request.POST)
if form.is_valid():
form.save()
return redirect('login')
class AuthLogin(View):
""" Its for login """
def get(self, request):
""" this function used to get the login form """
form = AuthenticationForm()
return render(request, 'plant/login.html', {'form': form})
def post(self, request):
""" this function used for post the login data """
form = AuthenticationForm(None, request.POST or None)
if form.is_valid():
login(request, form.get_user())
return redirect('/')
urls.py:
urlpatterns = [
url(r'^$', TemplateView.as_view(template_name="plant/index.html")),
url(r'^logout/$', auth_views.logout,
{'next_page': 'login'}, name='logout'),
url(r'^login/$', core_views.AuthLogin.as_view(), name='login'),
url(r'^signup/$', core_views.Signup.as_view(), name='signup'),
]
In login page I should have the forget password link. When user will click on it, the reset password page will open and another one condition is after trying 3 wrong attempt the forget password button will be invisible for 1 hour.
Do not create this functionality yourself but use the built-in Django auth views. https://docs.djangoproject.com/en/1.11/topics/auth/default/#built-in-auth-views
The only thing you need to do is add the contrib auth urls to your project:
urlpatterns = [
url('^', include('django.contrib.auth.urls')),
]
This gives you all views like login, logout, password reset etc.
If you want to customise the templates, copy the templates form /path/to/site-packages/django/contrib/admin/templates/registration/ to your app project/app/templates/registration/ and make any customisations
there.
If your app is listed before 'django.contrib.auth' in INSTALLED_APPS (it should always be like that) your custom templates will be picked first.

Categories

Resources