Poner un formulario de inicio de sesión de django en cada página

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?

    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í:

     
    {% csrf_token %}

    Todo lo que necesita hacer es modificar el siguiente valor, así que en lugar de:

      

    Ahora será:

      

    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.

    La forma más fácil es, probablemente, poner el formulario manualmente en una plantilla base como esta:

     {% if user.is_authenticated %} 
    {% csrf_token %}
    {% 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.

    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 %} 
    {% csrf_token %}

    {{ request.login_form.non_field_errors }} {% for field in request.login_form %} {{ field.errors }} {{ field.label_tag}}: {{ field }} {% endfor %}

    {% else %}
    {% csrf_token %}

    Logged in as {{ request.user.username }}.

    {% 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