I am trying to implement on my website a simple and friendly address system.
What i'm thinking about is when the user logged in, his username will be displayed in the address bar.
www.example.com/username1 (for home page profile)
www.example.com/username1/about/
www.example.com/username1/gallery/
www.example.com/username2 (for home page profile)
www.example.com/username2/about/
www.example.com/username2/gallery/
And additionally if anyone enter the address www.example.com/username1, will be shown the profile of user1.
I already implemented a register/Login system using Django-Allauth
mySite/urls.py
url(r'^accounts/', include('allauth.urls')),
home/urls.py
url(r'^$', views.index),
home/views.py
def index(request):
return render_to_response('home/index.html', context_instance=RequestContext(request))
I tried to follow some examples like Facing problem with user profile url scheme like example.com/username in django
But i dont have this thing working yet. I dont understand what to do :(
Please, give some advise.
Add the following url as the last item of the mySite/urls.py:
urlpatterns = patterns('',
...
url(r'^(?P<username>\w+)/', include('userapp.urls')),
)
Then the username parameter will be passed to the views of your userapp:
userapp/urls.py:
from userapp import views
urlpatterns = patterns('',
url(r'^$', views.profile, name='user_profile'),
url(r'^about/$', views.about, name='user_about'),
url(r'^gallery/$', views.gallery, name='user_gallery'),
)
userapp/views.py:
def profile(request, username):
user = get_object_or_404(User, username=username)
return render(request, 'userapp/profile.html', {'profile_user': user})
def about(request, username):
...
def gallery(request, username):
...
It's almost perfect, but i have a bug. Let me explain. When i login (my login system is: django-allauth) on the http://127.0.0.1:8000/accounts/login/ i return to http://127.0.0.1:8000 with an error 404.
I am not getting the http://127.0.0.1:8000/username/ with the template, when the login botton is clicked.
The instalation of django-allauth require adding to the settings.py
LOGIN_REDIRECT_URL = '/'
How can i redirect to http://127.0.0.1:8000/username/ and show the correct template?
1. Regarding
How can i redirect to
Based on the answer from https://stackoverflow.com/a/20143515/4992248
# settings.py:
ACCOUNT_ADAPTER = 'project.your_app.allauth.AccountAdapter'
# project/your_app/allauth.py:
from allauth.account.adapter import DefaultAccountAdapter
class AccountAdapter(DefaultAccountAdapter):
def get_login_redirect_url(self, request):
return 'request.user.username' # probably also needs to add slash(s)
Would be better to use get_absolute_url, ie return 'request.user.get_absolute_url'. In this case you need to do:
# 1. Add `namespace` to `yoursite/urls.py`
urlpatterns = patterns('',
...
url(r'^(?P<username>\w+)/', include('userapp.urls', namespace='profiles_username')),
)
# 2. Add the code below to the Users class in models.py
def get_absolute_url(self):
# 'user_profile' is from the code shown by catavaran above
return reverse('profiles_username:user_profile', args=[self.username])
2. Regarding
show the correct template
catavaran wrote correct urls which leads to views.profile, so in view.py you need to write:
from django.shortcuts import render
from .models import UserProfile # import model, where username field exists
from .forms import UserProfileForm # import Users form
def profiles(request, username):
user = get_object_or_404(UserProfile, username=username)
return render(request, 'home/profiles.html', {'user_profile_form': user})
In template (i.e. profiles.html) you can show user's data via {{user_profile_form.as_p}}
Related
I am using Django 3.2 and django-allauth 0.44
I have set my LOGIN_REDIRECT_URL in settings.py as follows:
LOGIN_REDIRECT_URL = 'profile-page'
in urls.py, I have the following route defined:
path('accounts/profile/slug:username', AccountProfileView.as_view(), name='profile-page'),
When I log in, (unsurprisingly), I get the following error message:
NoReverseMatch at /accounts/login/
Reverse for 'profile-page' with no arguments not found. 1 pattern(s) tried: ['accounts/profile/(?P[-a-zA-Z0-9_]+)$']
How do I pass (or specify) a parameter of the logged in user's username to the route?
If your view needs to perform redirects which are not very simple, you need to override the get_success_url method, considering that you use django-allauth, you will need to override allauth.account.views.LoginView and also write your own url pattern for it so that your overriden view is used. First override the view:
from django.urls import reverse
from allauth.account.views import LoginView as AllauthLoginView
from allauth.account.utils import get_next_redirect_url
class LoginView(AllauthLoginView):
def form_valid(self, form):
self.user = form.user # Get the forms user
return super().form_valid(form)
def get_success_url(self):
ret = (
get_next_redirect_url(self.request, self.redirect_field_name)
or reverse('profile-page', kwargs={'username': self.user.username})
)
return ret
Next wherever you define the urls for allauth, just add your own url before it:
from path_to.view_above import LoginView # Change this import properly
urlpatterns = [
...
path('accounts/login/', LoginView.as_view(), name="account_login"),
path('accounts/', include('allauth.urls')),
...
]
Another alternative solution using allauth is to use a custom ACCOUNT_ADAPTER and override it's get_login_redirect_url because LoginView will internally call it in case there is no next parameter. To do this, first inherit from allauth.account.adapter.DefaultAccountAdapter:
from django.urls import reverse
from allauth.account.adapter import DefaultAccountAdapter
class MyAccountAdapter(DefaultAccountAdapter):
def get_login_redirect_url(self, request):
return reverse('profile-page', kwargs={'username': request.user.username})
Next in settings.py set ACCOUNT_ADAPTER:
ACCOUNT_ADAPTER = "path.to.MyAccountAdapter"
The LOGIN_REDIRECT_URL should point to the page on which user lands after he successfully logs into your website, unless he was redirected to the login page by trying to visit any of the pages that require the authorization.
If you want to redirect user to a specific page, in this example to his own profile page, you can create an intermediate URL that will redirect the user to his own profile page, when visited. It can be accomplished like so:
Using class-based views:
class CurrentUserProfileRedirectView(LoginRequiredMixin, RedirectView):
def get_redirect_url(self, *args, **kwargs):
return reverse('profile-page', kwargs={'username': request.user.username})
or using function-based views:
#login_required
def current_user_profile(request):
return redirect('profile-page', username=request.user.username)
Next, register this redirect view as a regular view, not requiring any parameters, and set the LOGIN_REDIRECT_URL to this view's name.
I'm still new to Django. I have an admin user and a regular user who is not an admin. When admin login he should be redirected to '/admin_section' & when a regular user login he should be redirected to the '/' front page. Beyond that, it should be possible for an admin to be able to navigate to the '/' front page and see the page as a regular user can see.
I've been trying to search for an answer for this and the only thing I find is that I can use request.user.is_superuser in a view and ask whether the user is a superuser/admin or not. But the problem then becomes that admin will not have the ability to navigate to the front page ever. I have also set the login_redirect_url to "LOGIN_REDIRECT_URL = '/'" which means everytime a user login they will be redirected to the frontpage - but it should not be like that.
Here is my code so far (from the views.py file):
def home(request):
# if the user is not logged-in, show the loginpage
if not request.user.is_authenticated:
return HttpResponseRedirect('login')
# if the user is logged-in, show the frontpage
return render(request, 'mainapp/index.html')
# return the view for the admin section
def admin(request):
# if the user is logged-in & is an admin - show the admin section
if request.user.is_authenticated and request.user.is_superuser:
return render(request, 'mainapp/admin.html')
return redirect('home') # redirects to the home view
forms.py:
from django.contrib.auth.forms import AuthenticationForm
from django import forms
from django.contrib.auth import logout
from django.contrib.auth.mixins import LoginRequiredMixin, AccessMixin
# a class which act as a view - it displays the login-form
class LoginForm(AuthenticationForm, AccessMixin):
username=forms.CharField(widget=forms.TextInput(attrs={'class':'form-control'}))
password=forms.CharField(widget=forms.PasswordInput(attrs={'class':'form-control'}))
urls.py:
path('login/', views_auth.LoginView.as_view(form_class=LoginForm, redirect_authenticated_user=True), name='login'), # login-page
Create your login view inherited from the built-in login view and override the get_success_url method according to your logic.
from django.contrib.auth import views as views_auth
class LoginView(views_auth.LoginView):
form_class = LoginForm
redirect_authenticated_user = True
def get_success_url(self):
# write your logic here
if self.request.user.is_superuser:
return '/admin_section'
return '/'
urls.py
urlpatterns = [
path('login/', LoginView.as_view(), name='login'),
]
Provide the newly created view as the login URL in the settings file.
settings.py
LOGIN_URL = 'login'
I created a very simple example code using Django, but cannot get model value to be displayed on my page:
----------------------------- home/models.py
from django.db import models
class Home(models.Model):
msg = models.CharField(max_length=100)
#classmethod
def create(cls, msg):
home = cls(msg=msg)
# do something with the book
return home
home = Home.create("Hello World!")
------------------------------------home/views.py
from django.views.generic import TemplateView
from project.models import Home
class IndexView(TemplateView):
model = Home
template_name = 'home/index.html'
------------------------------------------ templates/home/index.html
{{ home.msg }}
this is a test page. I am expecting to see this....
------------------------------------------- urls.py
from django.conf.urls.defaults import patterns, include, url
from django.contrib import admin
from django.views.generic import TemplateView
admin.autodiscover()
urlpatterns = patterns('',
# Home pagetentacl.urls
url(r'^$', TemplateView.as_view(template_name='home/index.html')),
# Uncomment the admin/doc line below to enable admin documentation:
# url(r'^admin/doc/', include('django.contrib.admindocs.urls')),
# Uncomment the next line to enable the admin:
url(r'^admin/', include(admin.site.urls)),
)
-------------------------------------- result page on browser:
this is a test page. I am expecting to see this....
I don't want to have DB access for my example. I want my model returns "hello world" string. home.msg on index.html doesn't return anything. What is missing here?
You're not giving the template an instance of Home. You need to create one and pass it to the template as a Context, in the form {'msg': msg}.
EDIT: Adding some code
First of all, you should create your instance of home in your view. I've never used TemplateViews, so I'm going to use a regular view method instead.
def IndexView(request):
home=Home.create("Hello World!")
return render(request, 'index.html', {'home': home},)
As #Daniel rightly points out, you're not giving your template an instance of Home to work with.
If you want to use class-based views, subclass TemplateView and override get_context_data():
class IndexView(TemplateView):
template_name = "home/index.html"
def get_context_data(self, **kwargs):
context = super(HomePageView, self).get_context_data(**kwargs)
context["home"] = Home.create("Hello World!")
return context
And make sure your urls.py is using IndexView.as_view() - your version above is just referencing the generic TemplateView.
The fact that you added a model field to your subclass of TemplateView makes me think you're confusing it with DetailView. See the documentation for the difference.
I am making a blog app where I want to make a view that displays all the blogs of a particular user. For this I need to pass the user instance to my view as
def blogs(request,author=None,slug=None):
# If the author context has been passed then display the blogs of that author
if author:
# Displays a particular blog
if slug:
this_blog = get_object_or_404(Entry, creator = author, slug = slug)
return render_to_response('blog/blog_view.html', {'blog': this_blog,},context_instance=RequestContext(request))
# Displays all the blogs of a particular user
else:
blog_list = Entry.objects.filter(creator = author)
return render_to_response('blog/all_blogs_user.html', {'Blogs': blog_list},context_instance=RequestContext(request))
Although syntactically this is correct but now I do not how to actually pass this user context in my url. Earlier I tried passing just the user id but that does not work. Is there any other alternative to doing this thing. When I am building the url internally or redirecting to this particular view then it is fine, but how would the url look like externally. My urls.py is as
from django.conf.urls.defaults import patterns, include, url
from django.contrib.staticfiles.urls import staticfiles_urlpatterns
from django.views.generic.simple import direct_to_template
urlpatterns = patterns('',
url(r'^$', 'blog.views.blogs', name='all_blogs'),
url(r'^(?P<author>\d+)/(?P<slug>[-\w]+)/$', 'blog.views.blogs', name='view_blog'),
url(r'^(?P<author>\d+)/(?P<slug>[-\w]+)/edit/$', 'blog.views.post_form', name='edit_blog'),
url(r'^new/$', 'blog.views.post_form', name='new_blog'),
url(r'^(?P<author>\d+)/(?P<slug>[-\w]+)/delete/$', 'blog.views.delete_blog', name='delete_blog'),
)
urlpatterns += staticfiles_urlpatterns()
It generally works like this:
urls.py
url(r'/author/(?P<slug>/$', 'author_index'),
views.py
def author_index(request, slug):
author = get_object_or_404(User, username=slug)
return render_to_response('author_index.html', {
'author': author,
}, context_instance=RequestContext(request))
You can simply access the user in the view by request.user. Similarly, you can POST data in the request object as well.
I'm trying to redirect a user to a url containing his username (like http://domain/username/), and trying to figure out how to do this. I'm using django.contrib.auth for my user management, so I've tried using LOGIN_REDIRECT_URL in the settings:
LOGIN_REDIRECT_URL = '/%s/' % request.user.username # <--- fail..
but it only seems to accept fixed strings, rather than something that'll be determined after the user is logged in. How can I still accomplish this?
A solution, is to redirect to a static route like '/userpage/' and have that redirect to the final dynamic page.
But I think the real solution is to make a new view that does what you really want.
from django.contrib.auth import authenticate, login
from django.http import HttpResponseRedirect
def my_view(request):
username = request.POST['username']
password = request.POST['password']
user = authenticate(username=username, password=password)
if user is not None:
if user.is_active:
login(request, user)
HttpResponseRedirect('/%s/'%username)
else:
# Return a 'disabled account' error message
else:
# Return an 'invalid login' error message.
http://docs.djangoproject.com/en/dev/topics/auth/#authentication-in-web-requests
for more information about rewriting the view. This is how the docs say to override this kind of thing.
With the class-based django.contrib.auth.views.LoginView, you can now simply override get_success_url:
urls.py:
url(r'^login$', MyLoginView.as_view(), name='login'),
url(r'^users/(?P<username>[a-zA-Z0-9]+)$', MyAccountView.as_view(), name='my_account'),
views.py
class MyLoginView(LoginView):
def get_success_url(self):
return reverse('my_account', args=[self.request.user.username])
Wrap the auth view in your own custom view and redirect to wherever you want if authentication succeeded.
from django.http import HttpResponseRedirect
from django.contrib import auth
from django.core.urlresolvers import reverse
def login(request):
template_response = auth.views.login(request)
if isinstance(template_response, HttpResponseRedirect) and template_response.url == '/accounts/profile/':
return HttpResponseRedirect(reverse('user', args=(request.user.username,)))
return template_response
Another alternative is to use the query param next to indicate where to redirect to after the login.
sign in
I use django-two-factor-auth login view which provides OTP features for login.
Hence I extend from two_factor's LoginView.
In main urls.py:
from two_factor.urls import urlpatterns as tf_urls
urlpatterns = [
# make sure login is before default two_factor (tf_urls) urls
# coz first url has higher preference
path('account/login/', MyLoginView.as_view(), name='login'),
path('', include(tf_urls)),
]
In views.py:
from two_factor.views.core import LoginView
from two_factor.utils import default_device
class MyLoginView(LoginView):
def get_success_url(self):
if self.is_otp_setup() is True:
return reverse('homepage:homepage')
# otp not setup. redirect to OTP setup page
else:
return reverse('two_factor:setup')
def is_otp_setup(self):
if self.request.user and \
self.request.user.is_authenticated and \
default_device(self.request.user):
return True
else:
return False