46 votes

Mettre un django formulaire de connexion sur chaque page

Je voudrais que le formulaire de connexion (AuthenticationForm de django.contrib.auth) apparaissent sur chaque page de mon site que si l'utilisateur n'est pas connecté. Lorsque l'utilisateur se connecte, il est redirigé vers la même page. Si il y a une erreur, l'erreur sera affiché sur la même page avec le formulaire.

Je suppose que vous auriez besoin d'un contexte de processeur pour fournir le formulaire pour chaque modèle. Mais, alors que vous auriez également besoin de chaque vue de gérer la forme validée? Est-ce à dire que vous devez créer quelques middleware? Je suis un peu perdu.

Est-il un moyen de faire cela?

34voto

asciitaxi Points 734

Ok, j'ai finalement trouvé un moyen de le faire, même si je suis sûr qu'il y a de meilleurs moyens. J'ai créé un nouveau middleware classe appelée LoginFormMiddleware. Dans le process_request méthode, la poignée de la forme plus ou moins la façon dont l'auth login point de vue 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

Maintenant, si vous avez le contexte de la demande processeur installé, vous pouvez accéder au formulaire avec:

{{ request.login_form }}

Notez qu'un champ caché 'is_top_login_form" a été ajouté au formulaire afin que je puisse le distinguer des autres posté formes sur la page. Aussi, l'action du formulaire est "." au lieu de l'auth login vue.

25voto

twampss Points 417

À l'aide de django.contrib.auth, vous pouvez mettre le code du formulaire dans le modèle de base comme suit:

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

Tout ce que vous devez faire est de modifier la valeur suivante de sorte qu'au lieu de:

<input type="hidden" name="next" value="" />

Il sera désormais:

<input type="hidden" name="next" value="{{ request.get_full_path }}" />

Pour accéder à l'objet de demande, assurez-vous d'inclure

'django.core.context_processors.request'

dans votre modèle de contexte processeurs. De cette façon, vous n'avez pas à écrire un contexte de processeurs pour les connexions depuis que vous utilisez le Django intégré dans les vues.

6voto

John Debs Points 2266

Le plus simple est probablement de mettre le formulaire à la main, un modèle de base comme suit:

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

et puis il suffit d'écrire une vue accroché à une URL nommé "connexion" à la poignée de la forme comme vous le feriez normalement (à l'aide d'un objet de formulaire qui correspond à la forme ci-dessus). Avoir le point de vue de rediriger request.META['HTTP_REFERER'] pour l'afficher sur la même page que celui qui l'a soumise.

Cette approche évite le middleware ou de la nécessité de créer un formulaire disponible pour chaque modèle dans le contexte.

Mise à jour: Il y a quelques problèmes avec cette démarche, le besoin de réfléchir sur elle un peu plus. Je l'espère, au moins, vous reçoit à aller dans la bonne direction.

2voto

user2159075 Points 21

Basé sur la réponse de asciitaxi, j'utilise ces Middleware Classes de connexion et de déconnexion:

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'

Ce qui dans mon template de 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 %}

Remarques:

  • La demande.method = " GET " lignes sont nécessaires pour les sites avec d'autres formes. Semble un peu mais akward, mais il fonctionne très bien.
  • Puisque c'est affiché sur chaque page, je n'ai pas besoin de la déconnexion cas particulier, pas plus, parce que je n'ai tout simplement pas besoin d'un autre page de déconnexion
  • J'ai besoin d'une certaine distinction de ma connexion/déconnexion forme AVANT de vérifier si la validité de son (et donc appel AuthenticationForm Classe. Sinon, il y aura des erreurs quand il s'agit de pages avec plus de formes. Donc, j'utilise la valeur du Bouton Soumettre pour choisir les cas pertinents

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X