User should be redirected to the Login page after registration and after logout. In both cases there must be a message displayed indicating relevant messages.
Using the django.contrib.auth.views.login how do I send these {{ info }} messages.
A possible option would be to copy the auth.views to new registration module and include all essential stuff. But that doesn't seem DRY enough.
What is the best approach.
Update: Question elaboration:
For normal cases when you want to indicate to some user the response of an action you can use
request.user.message_set.create()
This creates a message that is displayed in one of the templates and automatically deletes.
However this message system only works for logged in users who continue to have same session id. In the case of registration, the user is not authenticated and in the case of logout since the session changes, this system cannot be used.
Add to that, the built in login and logout functions from django.contrib.auth.views return a 'HttpResponseRedirect' which make it impossible to add another variable to the template.
I tried setting things on the request object itself
request.info='Registered'
and check this in a different view
try:
info = request.info:
del request.info
except:
info = ''
#later
render_to_response('app/file',{'info':info})
Even this didn't work.
Clearly I can define a registered.html and add this static message there, but I was being lazy to write another template and trying to implement it DRY.
I realized that the cases were different for "registered" message and "logged out" message. And the DRY approach I used, I shall write as an answer.
If the messages are static you can use your own templates for those views:
(r'^accounts/login/$', 'django.contrib.auth.views.login', {'template_name': 'myapp/login.html'}
From the docs.
I think the best solution to this problem is to use a "flash"-type session-based messaging system. There are several floating around: django-flash seems really nice, I use django-session-messages which is very simple. Hopefully by the time we get to Django 1.2 this'll be baked-in.
You have Request Context Processors to add this kind of information to the context of every template that gets rendered.
This is the "zero impact" way to do this kind of thing. You don't update any view functions, so it meets some definitions of DRY.
See http://docs.djangoproject.com/en/dev/ref/templates/api/#id1
First, write your own login.html template.
Second, write your own context function to provide any additional information that must be inserted into the template.
Third, update settings to addy your context processor to the TEMPLATE_CONTEXT_PROCESSORS setting.
Related
"Accessing request.POST inside middleware before the view runs or in process_view() will prevent any view running after the middleware from being able to modify the upload handlers for the request, and should normally be avoided."
This is from the django documentation. First of all, if I just read the POST, without changing that, how does it even know and how does it prevent the view from doing it's business and second, how is a CsrfViewMiddleware different in that sense?
The warning comes from this ticket and this.
Django currently parses the POST data lazily, but middlware might try to access POST on a request and trigger parsing, even though the function itself never touches POST.
That would put high load on the machine if the POST data is rather large ...
It means that the view will be unable to set any custom upload handlers, perform custom parsing of the request body, or enforce permission checks prior to file uploads being accepted.
And the difference about CsrfViewMiddleware is stated clearly right below the said warning in the docs:
The CsrfViewMiddleware ... provides the csrf_exempt() and
csrf_protect() decorators which allow views to explicitly control at what point the CSRF validation should
occur.
I need to have certain users fill out a specific form on login. Django should redirect the user to the form, whenever a certain condition is True for that user.
I used a custom middleware to do it, but I am curious if there is a better approach.
Any ideas?
Another option is to change LOGIN_REDIRECT_URL to a view that does the check and redirects if required. However, users can then navigate away from the form by typing in another url.
If you absolutely require users to fill out the form, then using middleware is the way to do it.
The middleware is the way to go for this problem, it's the only method that's truly reliable and configurable.
The built-in actions that come with the Django admin generally display a helpful message after they execute at the top, e.g. saying that a new object was added or what have you.
The docs show how to do it with simple actions that can be represented as methods of the custom ModelAdmin. However, with custom actions that need intermediate pages (covered further down on that same page), I am encouraged to pass the user onto another view. That's great, but it means that I no longer have access to the custom ModelAdmin instance in order to call its message_user() method... Or at least I'm not sure how to get it.
Can you tell me how to get a hold of the current ModelAdmin instance or, if there's a better way, how else to display one of those helpful little messages when I'm done in the other view?
To mimic the ModelAdmin.message_user method you only need to do the following:
from django.contrib import messages
messages.info(request, message)
Adding a message is documented here https://docs.djangoproject.com/en/dev/ref/contrib/messages/#adding-a-message and the way ModelAdmin uses it can be seen here: https://code.djangoproject.com/browser/django/trunk/django/contrib/admin/options.py#L691
Construct a LogEntry and write a custom templatetag to render messages on your intermediat page, for instance:
LogEntry.objects.log_action(
user_id=request.user.id,
content_type_id=ContentType.objects.get_for_model(yourmodel).pk,
object_id=case.id,
object_repr=force_unicode(yourmodel),
action_flag=ADDITION if created else CHANGE)
read more: Django docs (Message Framework)
I want to show various messages to registered users only once in my django application. I found django-announcements which seemed to do what I want - but I found in testing it marks messages as read by using a session variable, which disappears if the user logs out. This means a message is shown again to a user if they dismiss it when logged in, log out, and then log in again.
I wondered if anyone know of an application that I might be able to use here without re-inventing the wheel.
Have a look at django-notification. It is used by pinax, there it seems to work like what you are searching for. At least it saves the status in the db.
edit
Response to the comment
from the docs:
notification.send([to_user], "friends_invite", {"from_user": from_user})
so this should work:
notification.send(Users.objects.all(), "friends_invite", {"from_user": from_user})
and if a queryset isnt right:
notification.send([u for u in Users.objects.all()], "friends_invite", {"from_user": from_user})
Have you looked at the Messages Framework in Django 1.3? In Django <=1.2 it was a simple model so you could do:
for user in User.objects.all():
user.message_set.create(message="some text")
and this would be rendered in the template, and dismissed as soon as the next page is loaded (it's what Django admin uses). It has changed a bit in 1.3, but it might be handy, but not 'dismissable' in the way that maybe you want.
The Django framework easily handles redirecting when a user fails to log in properly. However, this redirection goes to a separate login page. I can set the template to be the same as the page I logged in on, but none of my other objects exist in the new page.
For example, I have a front page that shows a bunch of news articles. On the sidebar is a login form. When the user logs in, but fails to authenticate, I would like it to return to the front page and preserve all the news articles that show. As of current, none of the news articles show up.
How can I fix this problem? Any help is appreciated.
Edit: Remember that I have dynamic content that is being displayed, and I would like it to still display! Futhermore, the main page is not the only place a user can log in. The sidebar never changes, so the user can potentially log in from any page on the site, and all of the content on that page exactly as it was still needs to be displayed upon failure to log in.
Do you want to redirect to the referring page on failed login?
... authentication code above
if user.is_authenticated():
#show success view
else:
return HttpResponseRedirect(request.META.get('HTTP_REFERER', reverse('index'))
you might want to check that referring page url is set correctly, otherwise set it to default url (assuming that your default url is named "index").
Use an <IFRAME> in the sidebar to
call the login view -- all postbacks
will happen within the iframe, so
your page stays intact. If the
visitor logs in successfully, you
can use javascript to redirect the
parent page to some other URL
Use AJAX to post the login form --
acheives the same effect as (1), but
it means your visitors will need to
have javascript-enabled browsers
I personally prefer to have the login on a separate page. If you're only worried about your visitors losing their current page (and not say, bound by a fussy client), you can have the login show up in a lightbox. I've used all three approaches in the past, and I'd be happy to post some code samples if you're interested.
This is because redirecting to a view misses the original context you use to render the page in the first place.
You are missing just a simple logic here. You are trying to render the same template again, but with no news_article list.
I suppose (in the first place), you are rendering the template which shows you Articles as well as login form, by sending two things 1. Login Form, and 2. Articles List.
But secondly, when user fails to authenticate, you are not passing the same things again. Pass those variables again as context (you can also add error message if your form is not handling error messages).
if user.is_authenticated():
#show success view
else:
return render_to_response('same_template.html', {
'error_msg': 'Username or password you provided was incorrect',
'news_articles': NewsArticles.objects.all()[:3],
'login_form': LoginForm(request.POST);
})
Edit: The reality is that, a context is used to render a template, and it's the complete responsibility of that template, what it wants to pass in further navigation. And as I see, if you are not passing something further, you are not getting it further.
If you want some automated context, develop your own context processor, something like the auth-context-processor, which automatically adds like 'user', always available to the template.
And by the way, you are going to miss that kind of context anyway, even if login is authenticated. So if that particular context is really important, either try sending the primary keys of articles along with the login form submit, or store that in global (ugliest thing ever) or just reconsider and separate the flow (good thing, I feel).