web-dev-qa-db-fra.com

la redirection Django après la connexion ne fonctionne pas

J'ai une page de connexion qui fonctionne bien à l'exception de la redirection vers la page de référence. L'utilisateur reçoit un email avec un lien direct au sein de l'application, ils (dans cet exemple) ne sont pas déjà connectés et sont redirigés vers la page de connexion. Une fois la connexion établie, l’utilisateur est redirigé vers un chemin codé en dur. Voir exemple ci-dessous.

URL dans l'email: http://localhost:8000/issueapp/1628/view/22

URL de la page de connexion: http://localhost:8000/login?next=/issueapp/1628/view/22

Vue de connexion (avec redirection codée en dur):

def login_user(request):    
    state = "Please log in below..."
    username = password = ''

    if request.POST:
        username = request.POST['username']
        password = request.POST['password']

        user = authenticate(username=username, password=password)
        if user is not None:
            if user.is_active:
                login(request, user)
                state = "You're successfully logged in!"
                return HttpResponseRedirect('/issueapp/1628/')
            else:
                state = "Your account is not active, please contact the site admin."
        else:
            state = "Your username and/or password were incorrect."

    return render_to_response(
        'account_login.html',
        {
        'state':state,
        'username': username
        },
        context_instance=RequestContext(request)
    )

Vue de connexion (avec la redirection "suivante"):

def login_user(request):    
    state = "Please log in below..."
    username = password = ''

    if request.POST:
        username = request.POST['username']
        password = request.POST['password']

        user = authenticate(username=username, password=password)
        if user is not None:
            if user.is_active:
                login(request, user)
                state = "You're successfully logged in!"
                return HttpResponseRedirect(request.GET['next'])
            else:
                state = "Your account is not active, please contact the site admin."
        else:
            state = "Your username and/or password were incorrect."

    return render_to_response(
        'account_login.html',
        {
        'state':state,
        'username': username
        },
        context_instance=RequestContext(request)
    )

La vue ci-dessus donne lieu à une exception "Key 'next' not found in <QueryDict: {}>" Le formulaire ne semble pas publier la variable "next", même si elle figure dans l'URL et dans le formulaire. J'ai cherché et cherché partout et je ne peux pas comprendre pourquoi cela ne fonctionne pas. Des idées?

Référence additionnelle:

Modèle de connexion:

{% block content %}

    {{ state }}
    <form action="/login/" method="post" >
                {% csrf_token %}
        {% if next %}
        <input type="hidden" name="next" value="{{ next }}" />
        {% endif %}
        username:
        <input type="text" name="username" value="{{ username }}" /><br />
        password:
        <input type="password" name="password" value="" /><br />

        <input type="submit" value="Log In"/>

        {% debug %}
    </form>
{% endblock %}

EDIT: Le code ci-dessous est en train de fonctionner pour moi (grâce à l'aide de Paulo Bu)! **

Login View:

def login_user(request):

    state = "Please log in below..."
    username = password = ''

    next = ""

    if request.GET:  
        next = request.GET['next']

    if request.POST:
        username = request.POST['username']
        password = request.POST['password']

        user = authenticate(username=username, password=password)
        if user is not None:
            if user.is_active:
                login(request, user)
                state = "You're successfully logged in!"
                if next == "":
                    return HttpResponseRedirect('/issueapp/')
                else:
                    return HttpResponseRedirect(next)
            else:
                state = "Your account is not active, please contact the site admin."
        else:
            state = "Your username and/or password were incorrect."

    return render_to_response(
        'account_login.html',
        {
        'state':state,
        'username': username,
        'next':next,
        },
        context_instance=RequestContext(request)
    )

Modèle de connexion:

{{ state }}

{% if next %}
<form action="/login/?next={{next}}" method="post" >
{%else%}
<form action="/login/" method="post" >
{% endif %}

            {% csrf_token %}

    username:
    <input type="text" name="username" value="{{ username }}" /><br />
    password:
    <input type="password" name="password" value="" /><br />

    <input type="submit" value="Log In"/>

    {% debug %}
</form>
27
James

Votre code est correct, le seul problème est que, sous la forme que vous transmettez à l'attribut next en tant que publication, car la méthode est post. Dans les vues, vous essayez d’obtenir le paramètre next dans le dictionnaire get, ce qui est évident non présent.

Vous devez déclarer le formulaire HTML action comme ceci pour que vos vues fonctionnent.

{% if next %}
<form action="/login/?next={{next}}" method="post" >
{%else%}
<form action="/login/" method="post" >
{% endif %}
        {% csrf_token %}
        username:
        <input type="text" name="username" value="{{ username }}" /><br />
        password:
        <input type="password" name="password" value="" /><br />

        <input type="submit" value="Log In"/>

        {% debug %}
    </form>

Là, s'il existe une variable next, vous devez inclure dans la url pour la récupérer en tant que paramètre get. Sinon, le formulaire ne l'inclut pas.

C'est la meilleure approche, mais vous pouvez également résoudre ce problème dans vos vues en demandant la variable next au dictionnaire POST comme ceci:

return HttpResponseRedirect(request.POST.get('next'))

Notez que cela ne fonctionnera que si le template account_login a une variable appelée next. Vous devez le générer dans les vues et le transmettre au modèle lorsque vous le rendez.

Normalement, dans le modèle, vous feriez quelque chose comme ceci:

# this would be hardcoded
next = '/issueapp/1628/view/22'
# you may add some logic to generate it as you need.

et ensuite vous faites:

return render_to_response(
    'account_login.html',
    {
    'state':state,
    'username': username,
    'next':next
    },
    context_instance=RequestContext(request)
)

J'espère que cela t'aides!

31
Paulo Bu

En bref

Je définirais dans votre vue la fonction next_page = request.GET['next'], puis je la redirigerais par return HttpResponseRedirect(next_page) afin que vous n'ayez jamais besoin de changer de modèle Il suffit de définir @login_required et tout va bien.

À titre d'exemple:

L'utilisateur A tente d'accéder - sans être connecté - https: //www.domain.tld/account/ . Django le redirige parce que @login_required est défini sur le LOGIN_URL défini dans votre fichier settings.py. La méthode UserLogin essaie maintenant de GET le paramètre next et le redirige si l'utilisateur A se connecte avec succès.

settings.py

LOGIN_URL = '/login/'

urls.py

url(r'^account/', account, name='account'),
url(r'^login/$', UserLogin, name='login'),

views.py

@login_required
def account(request):
    return HttpResponseRedirect("https://www.domain.tld/example-redirect/")

def UserLogin(request):
    next_page = request.GET['next']
    if request.user.is_authenticated():
        return HttpResponseRedirect(next_page)
    else:
        if request.method == 'POST':
            if form.is_valid():
                username = form.cleaned_data['username']
                password = form.cleaned_data['password']
                user = authenticate(email=username, password=password)
                if user is not None and user.is_active:
                    login(request, user)
                    return HttpResponseRedirect(next_page)
                else:
                    error_msg = 'There was an error!'
                    return render(request, "login", {'form': form, 'error_msg': error_msg})
            else:
                error_msg = "There was an error!"
                return render(request, "login", {'form':form, 'error_msg':error_msg})
        else:
            form = UserLoginForm()
            return render(request, "login", {'form': form})
6
rwx

Si vous voulez être plus générique, vous pouvez simplement faire quelque chose comme ceci, qui transmet l'un des paramètres GET lors de la publication du formulaire:

<form action="/path-to-whatever/{% if request.GET %}?{{ request.GET.urlencode }}{% endif %}" method="post">
1
seddonym

Plutôt que d’affecter next à votre vue et de le transmettre à un modèle, il n’est pas plus pratique d’utiliser ?next={{request.path}} dans votre modèle. (N'oubliez pas d'activer Django.core.context_processors.request dans settings.py, qui est généralement activé par défaut dans Django 1.6)

Voici le lien dit à propos de la même

https://docs.djangoproject.com/fr/1.6/topics/auth/default/#the-raw-way

<form action="/login/?next={{request.path}}" method="post" >

est le code requis.

Remarque:

Vous pouvez aussi obtenir l'URL actuelle avec request.path à partir de view.

Merci à buffer . Je viens de copier et coller votre commentaire après l'avoir essayé moi-même dans mon propre code.

0
Ajeeb.K.P

Il suffit de mettre

<form action="" method="post" >

Action vide 'what ever current complete url is'

0
Rizwan Mumtaz