Putting a django login form on every page

后端 未结 4 920
执念已碎
执念已碎 2020-11-27 11:35

I\'d like the login form (AuthenticationForm from django.contrib.auth) to appear on every page in my site if the user is not logged in. When the user logs in, they will be r

相关标签:
4条回答
  • 2020-11-27 11:48

    Ok, I eventually found a way of doing this, although I'm sure there are better ways. I created a new middleware class called LoginFormMiddleware. In the process_request method, handle the form more or less the way the auth login view does:

    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
    

    Now if you have the request context processor installed, you can access the form with:

    {{ request.login_form }}
    

    Note that a hidden field 'is_top_login_form' was added to the form so I could distinguish it from other posted forms on the page. Also, the form action is "." instead of the auth login view.

    0 讨论(0)
  • 2020-11-27 11:53

    Using django.contrib.auth, you can put the form code in the base template like so:

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

    All you need to do is modify the next value so instead of:

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

    It will now be:

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

    To access the request object, make sure you include

    'django.core.context_processors.request'
    

    in your template context processors. This way you don't have to write any context processors for logins since you are using the Django built-in views.

    0 讨论(0)
  • 2020-11-27 12:03

    Based on the answer of asciitaxi, i use these Middleware Classes to to login and logout:

    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'
    

    An this in my base template:

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

    Remarks:

    • The request.method = 'GET' lines are needed for sites with other forms. Seems a little but akward, but it works fine.
    • Since this is displayed on every page, i don't need the the logout special case any more, because i simply don't need a separate logout page
    • I need some distinction of my login/logout form BEFORE checking if its valid (thus calling the AuthenticationForm Class. Otherwise, there will be errors when it comes to pages with more forms. Therfore, i use the value of the Submit Button to pick out the relevant cases
    0 讨论(0)
  • 2020-11-27 12:07

    The easiest way is probably to put the form in manually in a base template like so:

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

    and then just write a view hooked up to a URL named "login" to handle the form as you would normally (using a form object that matches the above form). Have the view redirect to request.META['HTTP_REFERER'] to show it on the same page as the one that submitted.

    This approach avoids middleware or the need to make a form available to every single template through the context.

    Update: There are some problems with this approach; need to think on it a little more. Hopefully it at least gets you going in the right direction.

    0 讨论(0)
提交回复
热议问题