django admin redirect after a successful login - django

I am using Django=1.6.1.
Currently in my project, the admin system takes me to admin dashboard after a successful admin login (i.e: localhost:8000/admin/). From here I can visit most of my apps like users, categories, groups etc..
90% of the time I want to visit the users admin page (i.e localhost:8000/admin/my_project/users/). thus I am trying to find a way to redirect the admin login to admin users page rather than the dashboard. How can I do this?

I do not know if this is the right way to tackle this issue but this is how I have solved my problem.
I created a subclass of AdminSite called CustomAdminSite and overwritten the login() to accept a redirect url using the REDIRECT_FIELD_NAME(i.e using the 'next' hidden field option).
class CustomAdminSite(AdminSite):
#never_cache
def login(self, request, extra_context=None):
"""
Displays the login form for the given HttpRequest.
"""
from django.contrib.auth.views import login
context = {
'title': _('Log in'),
'app_path': request.get_full_path(),
REDIRECT_FIELD_NAME: settings.ADMIN_LOGIN_REDIRECT_URL,
}
context.update(extra_context or {})
defaults = {
'extra_context': context,
'current_app': self.name,
'authentication_form': self.login_form or AdminAuthenticationForm,
'template_name': self.login_template or 'admin/login.html',
}
return login(request, **defaults)
site = CustomAdminSite()
in urls.py
admin.site.login = path.to.custom.site.login
in settings.py
ADMIN_LOGIN_REDIRECT_URL = '/admin/my_project/users/'
P.S: please let me know if there is a better way to do this :)

Currently on Django (and since version 1.8) you can reverse your admin urls to redirect to any admin page.
For example:
The url you want to redirect to: /admin/my_project/users/
The reference: href="{% url 'admin:app_list' 'app_name' %}
The implementation: href="{% url 'admin:app_list' 'users' %}
Assuming you only have one model MyUser inside your users app, you can go directly into the admin list view of that model.
Reference: href="{% url 'admin:app_label_model_name_changelist' %}
Implementation: href="{% url 'admin:users_myuser_changelist' %}

You can do it by overriding the 'admin:index' url (the url named 'index' within admin namespace).

Related

How can i render a specific Django admin page from a view?

I know that can reverse to admin pages from a template by doing this:
{% url 'admin:index' %}
or
{% url 'admin:app_model_add' %}
But how can i render an admin page using the render function in my view?
When i do
render(request, template_name='admin/index.html')
I get a blank looking admin page with the message "You do not have permission to view or edit anything"
Furthermore, I am not sure what the syntax would be to render a specific admin template, i.e. the equivalent of using this reverse in a template:
admin:app_model_add
is not something like this in a view:
render(request, template_name='admin/app_model_add.html')
In fact i shouldn't to try to render an admin page, i should redirect to it.
so in my view I should be using:
redirect(to=reverse('admin:index'))
or
redirect(to=reverse('admin:app_model_add'))

django-registration: how do I check whether the user is logged in before displaying a page

I followed this page to set up a django registration site. It's pretty awesome, and registration and authentication are nicely wrapped.
But, it doesn't show me, how do I check if a user is logged in, who this user is, before displaying a webpage? and how do I direct the user to a new page after logged in?
Thanks!
In a view, you can use if request.user.is_authenticated(): and the variable for the current user is request.user
In a template, you can use {% if user.is_authenticated %} and the variable for the current user is user
For redirecting a user after logging in, you can set up LOGIN_REDIRECT_URL variable in settings.py
In .py documents
You can either use this inside every view
if not request.user.is_authenticated:
#do something
or this just before every view
#login_required
Remember that this one requires importing from django.contrib.auth.decorators import login_required
and you may also want to write LOGIN_URL = "/loginurl/" in your settings.py to get non-logged users redirected to an specific URL instead of the default one accounts/login)
In .html documents
{% if not user.is_authenticated %}
Login is required
{% endif %}
Redirecting after logging in
You can either modify LOGIN_REDIRECT_URL in settings.py
or redirect("/indexpage") after the user has been logged in.
This last one requires importing from django.shortcuts import redirect
You can also use a login required decorator before your view :
#login_required()
It redirects a user to the login page if a non logged in user tries to access your view
You will find more on this page :
https://docs.djangoproject.com/en/dev/topics/auth/default/#topic-authorization

Redirect to admin for login

I have a view defined for a url 'site/main/'. I would like to be able to have (unauthenticated) users redirected to the default '/admin/' page for login, then redirected to the '/main/' page after successful login. I followed the django documentation, but I must be missing something as I am unable to get this to work.
My view looks like:
def main(request):
if not request.user.is_authenticated():
return HttpResponseRedirect('admin/?next=%s' % request.path)
else:
I get an error:
Page not found (404)
Request Method: GET
Request URL:http://sitename:8080/main/admin/?next=/main/
Any help is greatly appreciated !
You're missing an initial / in the URL: /admin/?next=...
However this still won't work, as the admin URL doesn't know anything about the next parameter. That's only for the actual login views. With your code, the user will be logged into the admin but will not be redirected back to your page.
You should build a login template and wire it up to the built-in login views. Then instead of checking is_authenticated in the view, you should just use the login_required decorator.
#login_required
def main(request):
...
Your request.path shouldn't be /main/. Try it without the first.
If you want to redirect to admin for login for specific view, and then to redirect back to the view url after successful login you only need to do two things:
Add LOGIN_URL to settings.py inside your django project module:
...
LOGIN_URL = '/admin/login/'
Add #login_required as decorator to your view function inside views.py:
from django.contrib.auth.decorators import login_required
...
#login_required
def main(request):
Once you set LOGIN_URL = '/admin/login/' you can use #login_required on whatever view in entire django project and it will redirect to admin for login and after successful login will redirect back to the view url.
Also now you don't need to use is_authenticated any more inside of a view as Daniel Roseman already said.
The good thing is that now you also don't need to build a login template and wire it up to the built-in login views.
What is also good with this approach is the you have flexibility to easily add or remove this kind of authentication to whatever view you want.
urls.py:
url('^', include('django.contrib.auth.urls')),
registration/login.html:
<h3>Login foo</h3>
<form method="post" action="">
{% csrf_token %}
{{form.as_p}}
<input type="submit" value="Login">
</form>
views.py
def only_for_users(request):
if not request.user.is_authenticated():
return HttpResponseRedirect('/login/?next=%s' % request.path)
// fetch some really interesting data
env=(django.get_version(),settings.BASE_DIR,sys.version)
envMod=collections.OrderedDict(sorted(sys.modules.items()))
return render(request,'env.html',{'env':env, 'envMod':envMod})
It works for Django 1.6 and uses the built-in login (look at the urls.py) and template. So you do not need to build a view function.
Info on urls

Django: Redirect to current article after comment post

I am trying to use comments application in my project.
I tried to use code ({% render_comment_form for event %}), shown in the documentation here:
Django comments
And the question is how to make the form redirect to the same page, after the submission.
Also the big question is:
Currently if we have any error found in the for, then we're redirected to preview template.
Is that possible to avoid this behaviour and display errors over the same form (on the same page)?
I will show you how I resolved it in my blog, so you could do something similar. My comments are for Entry model in entries application.
First add new method for your Entry (like) object.
def get_absolute_url(self):
return "/%i/%i/%i/entry/%i/%s/" % (self.date.year, self.date.month, self.date.day, self.id, self.slug)
It generates url for entry objects. URL example: /2009/12/12/entry/1/lorem-ipsum/
To urls.py add 1 line:
(r'^comments/posted/$', 'smenteks_blog.entries.views.comment_posted'),
So now you should have at least 2 lines for comments in your urls.py file.
(r'^comments/posted/$', 'smenteks_blog.entries.views.comment_posted'),
(r'^comments/', include('django.contrib.comments.urls')),
For entries (like) application in views.py file add function:
from django.contrib.comments import Comment #A
...
def comment_posted(request):
if request.GET['c']:
comment_id = request.GET['c'] #B
comment = Comment.objects.get( pk=comment_id )
entry = Entry.objects.get(id=comment.object_pk) #C
if entry:
return HttpResponseRedirect( entry.get_absolute_url() ) #D
return HttpResponseRedirect( "/" )
A) Import on top of file to have
access for comment object,
B) Get
comment_id form REQUEST,
C) Fetch
entry object,
D) Use
get_absolute_url method to make
proper redirect.
Now:
Post button in comment form on entry site redirects user on the same (entry) site.
Post button on preview site redirects user on the proper (entry) site.
Preview button in comment form on entry site and on preview site redirects user on preview site
Thankyou page is not more in use (That page was quite annoying in my opinion).
Next thing good to do is to override preview.html template:
Go to django framework dir, under linux it could by /usr/share/pyshared/.
Get original preview.html template from DJANGO_DIR/contrib/comments/templates/comments/preview.html
Copy it to templates direcotry in your project PROJECT_DIR/templates/comments/entries_preview.html
From now on, it shoud override default template, You can change extends in this way: {% extends "your_pagelayout.html" %} to have your layout and all css files working.
Take a look at "Django-1.4/django/contrib/comments/templates/comments/" folder and you will see in the "form.html" file, there is the line
{% if next %}<div><input type="hidden" name="next" value="{{ next }}" /></div>{% endif %}
Therefore, in the Article-Detail view, you can include the "next" attribute in the context data, and then the comment framework will do the rest
class ArticleDetailView(DetailView):
model = Article
context_object_name = 'article'
def get_context_data(self, **kwargs):
context = super(ArticleDetailView, self).get_context_data(**kwargs)
context['next'] = reverse('blogs.views.article_detail_view',
kwargs={'pk':self.kwargs['pk'], 'slug': self.kwargs['slug']})
return context
Simplify Django’s Free Comments Redirection
Update: Now have the option to redirect as part of the comment form: see https://django-contrib-comments.readthedocs.io/en/latest/quickstart.html#redirecting-after-the-comment-post
This is a really simple redirect to implement. It redirects you back to the page where the comment was made.
When a comment is posted, the url comments/posted/ calls the view comment_posted which then redirects back to the referer page.
Be sure to replace [app_name] with your application name.
views.py
from urlparse import urlsplit
def comment_posted( request ):
referer = request.META.get('HTTP_REFERER', None)
if referer is None:
pass
try:
redirect_to = urlsplit(referer, 'http', False)[2]
except IndexError:
pass
return HttpResponseRedirect(redirect_to)
urls.py
( r'^comments/posted/$', '[app_name].views.comment_posted' ),

Getting Django admin url for an object

Before Django 1.0 there was an easy way to get the admin url of an object, and I had written a small filter that I'd use like this: <a href="{{ object|admin_url }}" .... > ... </a>
Basically I was using the url reverse function with the view name being 'django.contrib.admin.views.main.change_stage'
reverse( 'django.contrib.admin.views.main.change_stage', args=[app_label, model_name, object_id] )
to get the url.
As you might have guessed, I'm trying to update to the latest version of Django, and this is one of the obstacles I came across, that method for getting the admin url doesn't work anymore.
How can I do this in django 1.0? (or 1.1 for that matter, as I'm trying to update to the latest version in the svn).
You can use the URL resolver directly in a template, there's no need to write your own filter. E.g.
{% url 'admin:index' %}
{% url 'admin:polls_choice_add' %}
{% url 'admin:polls_choice_change' choice.id %}
{% url 'admin:polls_choice_changelist' %}
Ref: Documentation
from django.core.urlresolvers import reverse
def url_to_edit_object(obj):
url = reverse('admin:%s_%s_change' % (obj._meta.app_label, obj._meta.model_name), args=[obj.id] )
return u'Edit %s' % (url, obj.__unicode__())
This is similar to hansen_j's solution except that it uses url namespaces, admin: being the admin's default application namespace.
I had a similar issue where I would try to call reverse('admin_index') and was constantly getting django.core.urlresolvers.NoReverseMatch errors.
Turns out I had the old format admin urls in my urls.py file.
I had this in my urlpatterns:
(r'^admin/(.*)', admin.site.root),
which gets the admin screens working but is the deprecated way of doing it. I needed to change it to this:
(r'^admin/', include(admin.site.urls) ),
Once I did that, all the goodness that was promised in the Reversing Admin URLs docs started working.
Essentially the same as Mike Ramirez's answer, but simpler and closer in stylistics to django standard get_absolute_url method:
from django.urls import reverse
def get_admin_url(self):
return reverse('admin:%s_%s_change' % (self._meta.app_label, self._meta.model_name),
args=[self.id])
Using template tag admin_urlname:
There's another way for the later versions (>=1.10), recommend by the Django documentation, using the template tag admin_urlname:
{% load admin_urls %}
Add user
Delete this user
Where opts is something like mymodelinstance._meta or MyModelClass._meta
One gotcha is you can't access underscore attributes directly in Django templates (like {{ myinstance._meta }}) so you have to pass the opts object in from the view as template context.
For pre 1.1 django it is simple (for default admin site instance):
reverse('admin_%s_%s_change' % (app_label, model_name), args=(object_id,))
I solved this by changing the expression to:
reverse( 'django-admin', args=["%s/%s/%s/" % (app_label, model_name, object_id)] )
This requires/assumes that the root url conf has a name for the "admin" url handler, mainly that name is "django-admin",
i.e. in the root url conf:
url(r'^admin/(.*)', admin.site.root, name='django-admin'),
It seems to be working, but I'm not sure of its cleanness.
If you are using 1.0, try making a custom templatetag that looks like this:
def adminpageurl(object, link=None):
if link is None:
link = object
return "%s" % (
instance._meta.app_label,
instance._meta.module_name,
instance.id,
link,
)
then just use {% adminpageurl my_object %} in your template (don't forget to load the templatetag first)
For going to the admin page or admin login page we can use the below link. It works for me -
{% url 'admin:index' %}
This url takes me directly to the admin page.
Here's another option, using models:
Create a base model (or just add the admin_link method to a particular model)
class CommonModel(models.Model):
def admin_link(self):
if self.pk:
return mark_safe(u'<a target="_blank" href="../../../%s/%s/%s/">%s</a>' % (self._meta.app_label,
self._meta.object_name.lower(), self.pk, self))
else:
return mark_safe(u'')
class Meta:
abstract = True
Inherit from that base model
class User(CommonModel):
username = models.CharField(max_length=765)
password = models.CharField(max_length=192)
Use it in a template
{{ user.admin_link }}
Or view
user.admin_link()