Подтвердить что ты не робот

Ввод формы входа в систему django на каждой странице

Я хочу, чтобы форма входа (AuthenticationForm из django.contrib.auth) появлялась на каждой странице моего сайта, если пользователь не вошел в систему. Когда пользователь входит в систему, они будут перенаправлены на ту же страницу. Если произошла ошибка, ошибка будет показана на той же странице с формой.

Я предполагаю, что вам нужен процессор контекста, чтобы предоставить форму каждому шаблону. Но, тогда вам также понадобится каждое представление для обработки опубликованной формы? Означает ли это, что вам нужно создать некоторое промежуточное ПО? Я немного потерян.

Есть ли принятый способ сделать это?

4b9b3361

Ответ 1

Хорошо, я в конце концов нашел способ сделать это, хотя я уверен, что есть лучшие способы. Я создал новый класс промежуточного программного обеспечения, называемый LoginFormMiddleware. В методе process_request обрабатывайте форму более или менее так, как это делает вид входа в auth:

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

Теперь, если у вас установлен обработчик контекста запроса, вы можете получить доступ к форме с помощью:

{{ request.login_form }}

Обратите внимание, что в форму добавлено скрытое поле 'is_top_login_form', чтобы я мог отличить его от других опубликованных форм на странице. Кроме того, действие формы "." вместо входа в auth login.

Ответ 2

Используя django.contrib.auth, вы можете поместить код формы в базовый шаблон следующим образом:

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

Все, что вам нужно сделать, это изменить следующее значение, а вместо:

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

Теперь это будет:

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

Чтобы получить доступ к объекту запроса, убедитесь, что вы включили

'django.core.context_processors.request'

в ваших шаблонных контекстных процессорах. Таким образом, вам не нужно писать какие-либо процессоры контекста для входа в систему, поскольку вы используете встроенные представления Django.

Ответ 3

Самый простой способ - это, вероятно, разместить форму вручную в базовом шаблоне, например:

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

а затем просто напишите представление, подключенное к URL-адресу с именем "login", чтобы обрабатывать форму, как обычно (с использованием объекта формы, который соответствует приведенной выше форме). Перейдите на страницу request.META['HTTP_REFERER'], чтобы отобразить ее на той же странице, что и страница.

Этот подход позволяет избежать промежуточного программного обеспечения или необходимости создавать форму для каждого отдельного шаблона через контекст.

Обновление. Есть некоторые проблемы с этим подходом; нужно подумать об этом немного больше. Надеюсь, он по крайней мере заставит вас идти в правильном направлении.

Ответ 4

Основываясь на ответе asciitaxi, я использую эти классы Middleware для входа и выхода из системы:

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'

Это в моем базовом шаблоне:

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

Примечания:

  • Строки request.method = 'GET' необходимы для сайтов с другими формами. Кажется немного, но неловко, но он отлично работает.
  • Так как это отображается на каждой странице, мне больше не нужен особый случай выхода из системы, потому что мне просто не нужна отдельная страница выхода
  • Мне нужно какое-то различие в моей форме входа/выхода из системы, прежде чем проверять, действительно ли она действительна (вызывая, таким образом, класс AuthenticationForm. В противном случае будут возникать ошибки, когда речь заходит о страницах с большим количеством форм. Поэтому я использую значение кнопки Submit для выбора соответствующих случаев.