So I have a my user profile view you can see as a logged in user. I wanted to add a second view so other logged in users can visit profile pages as well, but I'm not really sure I'm doing it the right way
urls.py
url(r'^accounts/profile/', main_views.uprofile, name='uprofile'), #the page you see as my profile
url(r'^profile/(?P<pk>\d+)/$', main_views.oprofile, name='oprofile'), # the page i use so other users can view the profile page
url(r'^accounts/update/(?P<pk>\d+)/', User_Profile_views.edit_user, name='edit_user'), #Custom update profile page
main_views.py
#login_required(login_url='/accounts/login/')
def uprofile (request):
context = locals()
template = 'profile.html'
return render (request, template, context)
def oprofile (request, pk):
user = User.objects.get(pk=pk)
context = locals()
template = 'profile.html'
return render (request, template, context)
From product point of view, you would want to keep same url for both uprofile and oprofile. One simple reason being, when I visit my profile and if I want to share it with someone else, I'd just copy-paste the url.
How to do that?
In your view, pass a flag that helps your template to render the right elements. For instance, if the user is same as the profile being visited, pass a flag, say editable, and use it to show edit buttons. And instead of two views, you can have single view.
Also, instead of id, people tend to remember their username/handle. So it's better to have username. However, make sure you have unique username for all users.
urls.py
url(r'^profile/(?P<username>[\w\-]+)/$', main_views.profile, name='profile'),
views.py
def profile (request, username):
# If no such user exists raise 404
try:
user = User.objects.get(username=username)
except:
raise Http404
# Flag that determines if we should show editable elements in template
editable = False
# Handling non authenticated user for obvious reasons
if request.user.is_authenticated() and request.user == user:
editable = True
context = locals()
template = 'profile.html'
return render (request, template, context)
Related
I have a Django custom form classed-based view. Under normal conditions I want it to be accessible to both authenticated and logged out or anonymous visitors. However, under certain conditions I'd like it to alert the user they need to login to submit the form (and redirect them). Example:
class CustomFormView(FormView):
...
def form_valid(self, form):
user = self.request.user
req_id = self.request.GET.get("req_id")
if req_id:
errors = False
if not user.is_authenticated():
messages.error(self.request, "You must be logged in to fill out this form. Please sign in, then visit this link again.")
errors = True
# redirect
try:
...
if errors:
ctx = self.get_context_data()
return self.render_to_response(ctx)
I'm aware of LoginRequiredMixin (docs) as well as a decorator #method_decorator(login_required) but I don't want to apply it at the view level or to the entire form_valid() function, only check login state when if req_id condition is met. Currently the view's not executing my if not user.is_authenticated(): so my attempt isn't correct. Is there a way to accomplish this within form_valid()? thanks
I am not sure if i am titling this correctly, however i have a standard base.html file that includes block content from overridden allauth templates, mainly account/email.html, account/password_change.html, account/password_set.html and socialaccount/connections.html. each of these feed into base.html depending on tab selected. the tabs correspond to the default allauth views, accounts/email, accounts/password/change, accounts/password/set, and accounts/social/connections.
When i load base.html, I am able to grab the user profile information from a custom Profile model
#login_required
def base(request):
email = request.user
profile = Profile.objects.filter(my_user=email)
return render(request, 'base.html', {'profile': profile})
as long as i am on the base.html template view, the username displays in the upper right of the screen, and i have access to all profile information for use in the template. however, when i click onto an allauth default view, that still extends base.html, the username information in the header disappears and profile data is no longer available until i click back on the main base.html view.
Can someone help me with what i am missing on how to maintain the username in the upper right of the screen always in the base.html file (even as views change), as well as access to profile information across the different views?
Just in case this helps anyone else overriding AllAuth Views, was able to solve via:
class MyEmailView(EmailView):
def get_context_data(self, **kwargs):
email = self.request.user
profile_data = Profile.objects.filter(my_user=email)
context = super(MyEmailView, self).get_context_data(**kwargs)
context["profile_data"] = profile_data
print(context["profile_data"])
return context
urls.py
# override of email view to add user profile context data
path("accounts/email/", MyEmailView.as_view(), name="account_email"),
I have successfully made it so the user must log in to view their profile, however, I only want the user to be able to view their profile and no one else.
Previously, they could visitwww.websitename.com/user/admin
as well as www.websitename.com/user/test and it would bring up the data for the profile each time of the logged in user.
The URL to visit is www.websitename.com/user/usernameofcurrentuser
Profile Page View
def profile_page(request, username):
context = RequestContext(request)
if request.user == username:
if request.user.is_authenticated():
user = User.objects.get(username=username)
taskitems = request.user.taskitem_set.all()
return render_to_response('profile.html', {}, context)
else:
return render_to_response('login.html', {}, context)
else:
return render_to_response('login.html', {}, context)
However, even though the user is logged in, it's redirecting them to the sign in page. I know the user is logged in because it prints their name on the login page, yet it's not redirecting them to the profile associated with the username.
You can try this :
def profile_page(request, username):
if request.user.is_authenticated():
if request.user.username == username:
# removed user since already in request.user and available in template as 'user'
# removed taskitems since directly available in template as 'user.taskitem_set.all'
return render(request, 'profile.html')
else:
return HttpResponseRedirect(reverse('profile_page', args=(request.user.username,)))
else:
return render(request, 'login.html')
Remove the username parameter since each user should only view their own profile. You can also use the login_required decorator to remove the extra conditional:
from django.contrib.auth.decorators import login_required
from django.shortcuts import render
#login_required
def profile_page(request):
return render(request, 'profile.html')
Make sure to set LOGIN_URL in your settings.py so unauthenticated users get redirected to the right spot.
I want to create one page with both a login and signup form. Per this answer: https://stackoverflow.com/a/1395866/2532070, the best way is to use a separate <form action="{{url}}" tag for each form, and use two different views to handle the POST data for each form. My problem is that using the same view would allow me to pass the errors back to the forms, but if I use separate views with separate urls, I have to redirect the user back to the original page and add these parameters as part of a query string, which doesn't seem very efficient.
My Urls:
url(r'^$', HomePageView.as_view(), name="home_page"),
url(r'^profile/(?P<pk>\d+)/$', MemberUpdate.as_view(template_name="profile.html"), name="profile_page"),
url(r'^signup/$', SignupUser.as_view(), name="signup_user"),
My views:
class HomePageView(TemplateView):
template_name = "index.html"
login_form = AuthenticationForm()
signup_form = UserCreationForm()
def get_context_data(self, **kwargs):
context = super(HomePageView, self).get_context_data(**kwargs)
context['login_form'] = self.login_form
context['signup_form'] = self.signup_form
context['signup_action'] = reverse("signup_user")
return context
class SignupUser(CreateView):
model = settings.AUTH_USER_MODEL
form_class = MemberForm
template_name = "index.html"
def get_success_url(self):
return reverse("profile_page", args=[self.object.pk])
def form_invalid(self, form):
# here, how do I pass form.errors back to the home_page?
# I know messages framework is possible but this isn't as
# easy to add each error to its respective field as
# form.errors would be.
return HttpResponseRedirect(reverse('home_page'))
...and I would have a third view for the login form's POST data. Is this an acceptable way to manage my forms/views, or am I better off simply writing one overall view that distinguishes between the signup and login form within its post method with an if statment?
I have a Django project that uses profiles for user information. Things are somewhat working except for one aspect... Here are code snippets to describe my problem.
In the template:
<li>Profile</li>
In views.py
class UserProfileView(View):
#method_decorator(login_required)
def get(self, request, user):
profile = get_object_or_404(UserProfile, user=request.user)
return render(request, 'accounts/profile.html', {'profile': profile})
In urls.py
url(r'^accounts/(?P<user>.+)/profile/$',
UserProfileView.as_view(),
name='user_profile_view'
),
I've tried variations for the named group, and this is what I found to work. The problem is, I can use any string in between /accounts/ and /profile/ (obviously) and it works. What I want to accomplish is to have only the current user's username be valid in the URL and otherwise throw a 404.
Do you really need the user parameter in the profile URL? If you only want it work for the current user, then why not simply drop the user parameter:
# urls.py
url(r'^accounts/profile/$',
UserProfileView.as_view(),
name='user_profile_view'
),
# views
class UserProfileView(View):
#method_decorator(login_required)
def get(self, request):
profile = get_object_or_404(UserProfile, user=request.user)
return render(request, 'accounts/profile.html', {'profile': profile})
In the code you posted, the UserProfileView.get method was not using the user parameter anyway.
UPDATE
If you want to keep the user parameter and make it work the way you want, you can change the view like this:
from django.http import Http404
class UserProfileView(View):
#method_decorator(login_required)
def get(self, request, user):
if request.user.username == user:
profile = get_object_or_404(UserProfile, user=request.user)
return render(request, 'accounts/profile.html', {'profile': profile})
else:
raise Http404
Btw, since user in the parameter list of the get method is really just the username as opposed to a user object, it would be better to rename it to username, to avoid confusion.