o que é reverse () no Django

218

Quando leio código django algumas vezes, vejo em alguns modelos reverse(). Não sei ao certo o que é isso, mas é usado junto com o HttpResponseRedirect. Como e quando isso reverse()deve ser usado?

Seria bom se alguém desse uma resposta com alguns exemplos ...

lago
fonte
26
Dado um padrão de URL, o Django usa url () para escolher a visualização correta e gerar uma página. Isto é url--> view name. Mas às vezes, como no redirecionamento, você precisa ir na direção inversa e dar ao Django o nome de uma visualização, e o Django gera o URL apropriado. Em outras palavras view name --> url,. Ou seja, reverse()(é o inverso da função url). Pode parecer mais transparente para chamá-lo generateUrlFromViewName, mas isso é muito tempo e provavelmente não o suficiente geral: docs.djangoproject.com/en/dev/topics/http/urls/...
eric
4
@neuronet Ótima explicação, obrigado. Esse nome me pareceu (e parece) particularmente não intuitivo, que considero um pecado grave. Quem não odeia ofuscação desnecessária?
mike roedor
Este é um exemplo típico de nomeação que enfatiza um aspecto de uma entidade (por exemplo, função) que estava na mente do programador na época, dado seu contexto, mas não é a opção mais útil no contexto amplo de qualquer outro desenvolvedor. . Freqüentemente caímos nessa armadilha como programadores - a nomeação é tão importante para a descoberta que vale a pena parar e pensar nos diferentes contextos e escolher o mais apropriado.
Cornel Masson

Respostas:

346

reverse()| Documentação do Django


Vamos supor que urls.pyvocê tenha definido isso:

url(r'^foo$', some_view, name='url_name'),

Em um modelo, você pode consultar esse URL como:

<!-- django <= 1.4 -->
<a href="{% url url_name %}">link which calls some_view</a>

<!-- django >= 1.5 or with {% load url from future %} in your template -->
<a href="{% url 'url_name' %}">link which calls some_view</a>

Isso será renderizado como:

<a href="/foo/">link which calls some_view</a>

Agora diga que deseja fazer algo semelhante ao seu views.py- por exemplo, você está lidando com outra URL (não /foo/) em outra visão (não some_view) e deseja redirecionar o usuário para /foo/(geralmente o caso de envio bem-sucedido de formulário).

Você poderia apenas fazer:

return HttpResponseRedirect('/foo/')

Mas e se você quiser alterar o URL no futuro? Você precisaria atualizar sua urls.py e todas as referências a ela no seu código. Isso viola a DRY (Não se repita) , toda a idéia de editar apenas um lugar, o que é algo pelo qual se esforçar.

Em vez disso, você pode dizer:

from django.urls import reverse
return HttpResponseRedirect(reverse('url_name'))

Ele procura em todos os URLs definidos no seu projeto o URL definido com o nome url_namee retorna o URL real /foo/.

Isso significa que você se refere ao URL apenas por seu nameatributo - se quiser alterar o próprio URL ou a visualização a que se refere, você pode fazer isso editando apenas um local - urls.py.

scytale
fonte
2
Para sua informação, {{ url 'url_name' }}deve estar {% url url_name %}no Django 1.4 ou anterior. Isso vai mudar no próximo lançamento do Django (1.5) e deve ser {% url 'url_name' %}. Os docs para a url templatetag dar algumas boas informações se você rolar para baixo um pouco para a "frente de compatibilidade" seção
j_syk
1
j_syk obrigado - eu venho fazendo @load url do futuro @ desde a versão 1.3 e esqueci que ainda não é o padrão. Vou atualizar minha resposta para que não tropeçar nos inexperientes.
scytale
2
corrigido - Eu acho que é totalmente aceitável que você edite erros de digitação nas respostas de outras pessoas, por isso, se você vir mais, basta pular para dentro :-) #
1013
3
Uma das respostas mais sutis que se pode encontrar neste site.
Manas Chaturvedi
1
">>> mas e se você quiser alterar o URL no futuro", esses tipos de sutilezas que são úteis em 0,0001% do tempo e a solução é enviada como um recurso útil, e as pessoas o usam como se fossem ' melhores práticas "e deixar a bagunça. TBH se, quando alguém alterar os URLs no futuro, você apenas fizer uma substituição global de localização. Mesmo essa solução (use url_name) é propensa ao problema de 'e se você quiser alterar o url_name no futuro?' Faz codificação no Django há mais de 5 anos e ainda atende a necessidade url_reverse. A melhor maneira de lidar com esses tipos de esquisitices é recusar usá-los.
Nehem 13/11
10

Esta é uma pergunta antiga, mas aqui está algo que pode ajudar alguém.

Dos documentos oficiais:

O Django fornece ferramentas para executar a reversão de URL que corresponde às diferentes camadas em que os URLs são necessários: Nos modelos: usando a tag de modelo de URL. No código Python: Usando a função reverse (). No código de nível superior relacionado ao tratamento de URLs das instâncias do modelo Django: O método get_absolute_url ().

Por exemplo. em modelos (tag de URL)

<a href="{% url 'news-year-archive' 2012 %}">2012 Archive</a>

Por exemplo. no código python (usando a reversefunção)

return HttpResponseRedirect(reverse('news-year-archive', args=(year,)))
Kishy Nivas
fonte
1
precisa de descrição completa boss
giveJob
O OP mencionou especificamente que ele leu os documentos, ele precisava de explicação, não apenas copiar / colar os documentos.
RusI
8

As respostas existentes fizeram um ótimo trabalho ao explicar o quê dessa reverse()função no Django.

No entanto, esperava que minha resposta esclarecesse o porquê : por que usar reverse()no lugar de outras abordagens mais diretas e discutivelmente mais pitônicas na ligação de exibição de modelo e quais são algumas das razões legítimas para a popularidade desse "redirecionamento via reverse() padrão "na lógica de roteamento do Django.

Um benefício importante é a construção reversa de um URL, como outros mencionaram. Assim como você usaria {% url "profile" profile.id %}para gerar o URL a partir do arquivo de configuração de URL do seu aplicativo: por exemplo path('<int:profile.id>/profile', views.profile, name="profile").

Mas, como o OP observou, o uso de reverse()também é comumente combinado com o uso de HttpResponseRedirect. Mas por que?

Não sei ao certo o que é isso, mas é usado junto com o HttpResponseRedirect. Como e quando esse reverse () deve ser usado?

Considere o seguinte views.py:

from django.http import HttpResponseRedirect
from django.urls import reverse

def vote(request, question_id):
    question = get_object_or_404(Question, pk=question_id)
    try:
        selected = question.choice_set.get(pk=request.POST['choice'])
    except KeyError:
        # handle exception
        pass
    else:
        selected.votes += 1
        selected.save()
        return HttpResponseRedirect(reverse('polls:polls-results',
                                    args=(question.id)
        ))

E nosso mínimo urls.py:

from django.urls import path
from . import views

app_name = 'polls'
urlpatterns = [
    path('<int:question_id>/results/', views.results, name='polls-results'),
    path('<int:question_id>/vote/', views.vote, name='polls-vote')
]

Na vote()função, o código em nosso elsebloco usa reversejunto com HttpResponseRedirecto seguinte padrão:

HttpResponseRedirect(reverse('polls:polls-results',
                                        args=(question.id)

Em primeiro lugar, significa que não precisamos codificar a URL (consistente com o princípio DRY), mas, mais crucialmente, reverse()fornece uma maneira elegante de construir cadeias de URL manipulando valores descompactados dos argumentos ( args=(question.id)é tratado por URLConfig). Suposto questiontem um atributo idque contém o valor 5, a URL construída a partir do reverse()seria então:

'/polls/5/results/'

No código de ligação normal da visualização de modelo, usamos HttpResponse()ou, render()como geralmente envolvem menos abstração: uma função de exibição retornando um modelo:

def index(request):
    return render(request, 'polls/index.html') 

Mas em muitos casos legítimos de redirecionamento, normalmente nos preocupamos em construir o URL a partir de uma lista de parâmetros. Isso inclui casos como:

  • Envio de formulário HTML por POSTsolicitação
  • Pós-validação de login do usuário
  • Redefinir senha por meio de tokens da Web JSON

A maioria delas envolve alguma forma de redirecionamento e uma URL construída através de um conjunto de parâmetros. Espero que isso melhore o já útil tópico de respostas!

onlyphantom
fonte
4

A função suporta o princípio seco - garantindo que você não codifique os URLs em todo o aplicativo. Um URL deve ser definido em um lugar e apenas em um lugar - seu URL conf. Depois disso, você está realmente apenas referenciando essas informações.

Use reverse()para fornecer o URL de uma página, o caminho para a exibição ou o parâmetro page_name do seu URL conf. Você o usaria nos casos em que não faz sentido fazê-lo no modelo {% url 'my-page' %}.

Existem muitos lugares possíveis em que você pode usar essa funcionalidade. Um local que descobri que uso é ao redirecionar usuários em uma exibição (geralmente após o processamento bem-sucedido de um formulário) -

return HttpResponseRedirect(reverse('thanks-we-got-your-form-page'))

Você também pode usá-lo ao escrever tags de modelo.

Outra vez que usei reverse()foi com herança de modelo. Eu tinha um ListView em um modelo pai, mas queria ir de qualquer um desses objetos pai para o DetailView do objeto filho associado. Anexei uma get__child_url()função ao pai, que identificou a existência de um filho e retornou o URL do DetailView usando reverse().

Ashish Kumar Sahoo
fonte
2

As respostas existentes são bastante claras. Apenas no caso de você não saber por que ele é chamado reverse: ele recebe uma entrada com um nome de URL e fornece o URL real, o que é inverso ao primeiro ter um URL e, em seguida, nomeá-lo.

yyFred
fonte
1
Apenas aprendendo o Django a partir de um tutorial (Django Girls). É uma curva de aprendizado acentuada. Eu acho que o nome dessa função é terrível: "reserve" sem qualquer qualificação MUITO FORTE sugere reservar uma lista ou string, que obviamente não tem nada a ver com isso.
mike roedor
@mikerodent Concordo plenamente com você. Além disso, nenhuma dessas respostas explica por que a função é chamada reversa. É um nome tão ruim assim.
Soham Dongargaonkar
1

O reverse () é usado para aderir ao princípio django DRY, ou seja, se você alterar o URL no futuro, poderá referenciá-lo usando reverse (urlname).

AEROCODE
fonte