tipos - Poner un formulario de inicio de sesión de django en cada página
post django (4)
Basado en la respuesta de asciitaxi, utilizo estas clases de Middleware para iniciar y cerrar sesión:
class LoginFormMiddleware(object):
def process_request(self, request):
from django.contrib.auth.forms import AuthenticationForm
if request.method == ''POST'' and request.POST.has_key(''base-account'') and request.POST[''base-account''] == ''Login'':
form = AuthenticationForm(data=request.POST, prefix="login")
if form.is_valid():
from django.contrib.auth import login
login(request, form.get_user())
request.method = ''GET''
else:
form = AuthenticationForm(request, prefix="login")
request.login_form = form
class LogoutFormMiddleware(object):
def process_request(self, request):
if request.method == ''POST'' and request.POST.has_key(''base-account'') and request.POST[''base-account''] == ''Logout'':
from django.contrib.auth import logout
logout(request)
request.method = ''GET''
Un esto en mi plantilla base:
{% if not request.user.is_authenticated %}
<form action="" method="post">
{% csrf_token %}
<p id="login">
{{ request.login_form.non_field_errors }}
{% for field in request.login_form %}
{{ field.errors }}
{{ field.label_tag}}: {{ field }}
{% endfor %}
<input type="submit" name="base-account" value="Login" />
</p>
</form>
{% else %}
<form action="" method="post">
{% csrf_token %}
<p id="logout">Logged in as <b>{{ request.user.username }}</b>.
<input type="submit" name="base-account" value="Logout" />
</p>
</form>
{% endif %}
Observaciones:
- Las líneas request.method = ''GET'' son necesarias para sitios con otras formas. Parece un poco incómodo, pero funciona bien.
- Como esto se muestra en todas las páginas, ya no necesito el caso especial de cierre de sesión, porque simplemente no necesito una página de cierre de sesión por separado.
- Necesito alguna distinción de mi formulario de inicio de sesión / cierre de sesión ANTES de comprobar si es válido (llamando así a la clase AuthenticationForm. De lo contrario, habrá errores cuando se trate de páginas con más formularios. Por lo tanto, uso el valor del botón Enviar para seleccionar los casos relevantes
Me gustaría que el formulario de inicio de sesión (AuthenticationForm de django.contrib.auth) aparezca en todas las páginas de mi sitio si el usuario no ha iniciado sesión. Cuando el usuario inicie sesión, se las redireccionará a la misma página. Si hay un error, el error se mostrará en la misma página con el formulario.
Supongo que necesitaría un procesador de contexto para proporcionar el formulario a cada plantilla. Pero, ¿entonces también necesitaría todas las vistas para manejar el formulario publicado? ¿Esto significa que necesitas crear algún middleware? Estoy un poco perdido.
¿Hay una forma aceptada de hacer esto?
La forma más fácil es, probablemente, poner el formulario manualmente en una plantilla base como esta:
{% if user.is_authenticated %}
<form action="{% url login %}" method="POST">{% csrf_token %}
<input id="username-field" name="username" type="text" />
<input id="password-field" name="password" type="password" />
<button type="submit">Login</button>
</form>
{% else %}
{# display something else here... #}
{% endif %}
y luego simplemente escriba una vista conectada a una URL llamada "inicio de sesión" para manejar el formulario como lo haría normalmente (utilizando un objeto de formulario que coincida con el formulario anterior). Haga que la vista redirija a request.META[''HTTP_REFERER'']
para mostrarla en la misma página que la que envió.
Este enfoque evita middleware o la necesidad de hacer un formulario disponible para cada plantilla a través del contexto.
Actualización : hay algunos problemas con este enfoque; necesito pensar un poco más. Espero que al menos te lleve en la dirección correcta.
Ok, finalmente encontré la manera de hacerlo, aunque estoy seguro de que hay mejores formas. Creé una nueva clase de middleware llamada LoginFormMiddleware. En el método process_request, maneje el formulario más o menos como lo hace la vista de inicio de sesión de autenticación:
class LoginFormMiddleware(object):
def process_request(self, request):
# if the top login form has been posted
if request.method == ''POST'' and ''is_top_login_form'' in request.POST:
# validate the form
form = AuthenticationForm(data=request.POST)
if form.is_valid():
# log the user in
from django.contrib.auth import login
login(request, form.get_user())
# if this is the logout page, then redirect to /
# so we don''t get logged out just after logging in
if ''/account/logout/'' in request.get_full_path():
return HttpResponseRedirect(''/'')
else:
form = AuthenticationForm(request)
# attach the form to the request so it can be accessed within the templates
request.login_form = form
Ahora, si tiene instalado el procesador de contexto de solicitud, puede acceder al formulario con:
{{ request.login_form }}
Tenga en cuenta que se agregó un campo oculto ''is_top_login_form'' al formulario para poder distinguirlo de otros formularios publicados en la página. Además, la acción de formulario es "." en lugar de la vista de inicio de sesión de autenticación.
Utilizando django.contrib.auth, puede poner el código del formulario en la plantilla base así:
<form method="post" action="{% url auth_login %}">
{% csrf_token %}
<p><label for="id_username">Username:</label> <input id="id_username" type="text" name="username" maxlength="30" /></p>
<p><label for="id_password">Password:</label> <input type="password" name="password" id="id_password" /></p>
<input type="submit" value="Log in" />
<input type="hidden" name="next" value="" />
</form>
Todo lo que necesita hacer es modificar el siguiente valor, así que en lugar de:
<input type="hidden" name="next" value="" />
Ahora será:
<input type="hidden" name="next" value="{{ request.get_full_path }}" />
Para acceder al objeto de solicitud, asegúrese de incluir
''django.core.context_processors.request''
en los procesadores de contexto de tu plantilla. De esta forma, no tiene que escribir ningún procesador de contexto para los inicios de sesión ya que está utilizando las vistas incorporadas de Django.