apa yang terbalik () di Django

218

Ketika saya membaca kode Django kadang-kadang, saya melihat di beberapa template reverse(). Saya tidak yakin apa ini, tetapi digunakan bersama dengan HttpResponseRedirect. Bagaimana dan kapan ini reverse()seharusnya digunakan?

Alangkah baiknya jika seseorang memberi jawaban dengan beberapa contoh ...

Lakesh
sumber
26
Diberi pola url, Django menggunakan url () untuk memilih tampilan yang benar dan menghasilkan halaman. Yaitu url--> view name,. Tetapi kadang-kadang, seperti saat mengarahkan, Anda harus pergi ke arah sebaliknya dan memberi Django nama tampilan, dan Django menghasilkan url yang sesuai. Dengan kata lain view name --> url,. Yaitu, reverse()(ini kebalikan dari fungsi url). Mungkin terlihat lebih transparan untuk menyebutnya saja generateUrlFromViewNametapi itu terlalu lama dan mungkin tidak cukup umum: docs.djangoproject.com/en/dev/topics/http/urls/…
eric
4
@neuronet Penjelasan luar biasa, terima kasih. Nama ini tampaknya (dan tampaknya) sangat tidak intuitif bagi saya, yang saya anggap sebagai dosa besar. Siapa yang tidak membenci kebingungan yang tidak perlu?
mike rodent
Ini adalah contoh khas dari penamaan yang menekankan satu aspek entitas (misalnya fungsi) yang paling utama dalam pikiran programmer pada saat itu, mengingat konteksnya, tetapi bukan pilihan yang paling berguna dalam konteks luas pengembang lain . Kita sering jatuh ke dalam perangkap ini sebagai programmer - penamaan sangat penting untuk dapat ditemukan, ada baiknya berhenti dan berpikir tentang konteks yang berbeda dan memilih yang paling tepat.
Cornel Masson

Jawaban:

346

reverse()| Dokumentasi Django


Misalkan dalam diri Anda, urls.pyAnda telah mendefinisikan ini:

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

Di templat Anda dapat merujuk ke url ini sebagai:

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

Ini akan diterjemahkan sebagai:

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

Sekarang katakan Anda ingin melakukan sesuatu yang serupa di Anda views.py- misalnya Anda sedang menangani beberapa url lain (tidak /foo/) dalam beberapa tampilan lain (tidak some_view) dan Anda ingin mengarahkan pengguna ke /foo/(sering kali pada pengiriman formulir yang berhasil).

Anda bisa melakukannya:

return HttpResponseRedirect('/foo/')

Tetapi bagaimana jika Anda ingin mengubah url di masa depan? Anda harus memperbarui urls.py dan semua referensi Anda ke dalam kode Anda. Ini melanggar KERING (Jangan Ulangi Diri Sendiri) , seluruh ide untuk mengedit satu tempat saja, yang merupakan sesuatu untuk diperjuangkan.

Sebaliknya, Anda bisa mengatakan:

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

Ini memeriksa semua url yang ditentukan dalam proyek Anda untuk url yang ditentukan dengan nama url_namedan mengembalikan url yang sebenarnya /foo/.

Ini berarti bahwa Anda merujuk ke url hanya dengan nameatributnya - jika Anda ingin mengubah url itu sendiri atau tampilan yang merujuknya Anda dapat melakukan ini dengan mengedit satu tempat saja - urls.py.

scytale
sumber
2
FYI, {{ url 'url_name' }}harus {% url url_name %}di Django 1.4 atau lebih awal. Ini akan berubah dalam rilis Django berikutnya (1,5) dan seharusnya {% url 'url_name' %}. Dokumen untuk templatetag url memberikan beberapa info bagus jika Anda gulirkan sedikit ke bagian "kompatibilitas ke depan"
j_syk
1
j_syk terima kasih - saya sudah melakukan @load url dari future @ sejak 1.3 keluar dan lupa bahwa itu belum default. Saya akan memperbarui jawaban saya sehingga tidak naik hingga yang tidak berpengalaman.
scytale
2
diperbaiki - Saya pikir itu dianggap benar-benar dapat diterima bagi Anda untuk mengedit sendiri kesalahan ketik dalam jawaban orang lain, jadi jika Anda melihat lebih banyak langsung saja masuk :-)
scytale
3
Salah satu jawaban paling halus yang dapat ditemukan di situs ini.
Manas Chaturvedi
1
">>> tetapi bagaimana jika Anda ingin mengubah url di masa depan", Jenis seluk-beluk yang berguna pada .0001% dari waktu dan solusinya dikirimkan seperti fitur yang berguna, dan orang-orang menggunakannya seolah-olah mereka ' praktik terbaik dan tinggalkan kekacauan. TBH jika ketika seseorang mengubah url di masa depan Anda hanya melakukan pencarian-ganti global. Bahkan solusi ini (gunakan url_name) rentan terhadap masalah 'bagaimana jika Anda ingin mengubah url_name di masa mendatang?' Sudah coding di Django selama lebih dari 5 tahun dan belum memenuhi kebutuhan url_reverse. Cara terbaik untuk menghadapi keanehan semacam ini adalah dengan menolak menggunakannya.
nehem
10

Ini adalah pertanyaan lama, tapi di sini ada sesuatu yang mungkin bisa membantu seseorang.

Dari dokumen resmi:

Django menyediakan alat untuk melakukan pembalikan URL yang cocok dengan berbagai lapisan tempat URL dibutuhkan: Dalam kerangka: Menggunakan tag templat url. Dalam kode Python: Menggunakan fungsi reverse (). Dalam kode tingkat yang lebih tinggi terkait dengan penanganan URL contoh model Django: Metode get_absolute_url ().

Misalnya. dalam templat (tag url)

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

Misalnya. dalam kode python (menggunakan reversefungsi)

return HttpResponseRedirect(reverse('news-year-archive', args=(year,)))
Kishy Nivas
sumber
1
butuh deskripsi lengkap bos
giveJob
OP secara khusus menyebutkan bahwa ia membaca dokumen, ia membutuhkan penjelasan, bukan hanya menyalin / menempel dari dokumen tersebut.
RusI
8

Jawaban yang ada sangat membantu dalam menjelaskan apareverse() fungsi ini di Django.

Namun, saya berharap bahwa jawaban saya memberi penjelasan berbeda tentang alasannya : mengapa digunakan reverse()sebagai pengganti pendekatan yang lebih langsung, lebih bisa dibilang lebih pythonic dalam pengikatan tampilan templat, dan apa saja alasan sah untuk popularitas "redirect via ini reverse() pola "dalam logika routing Django.

Salah satu manfaat utama adalah pembangunan terbalik dari url, seperti yang lain telah disebutkan. Seperti cara Anda menggunakan {% url "profile" profile.id %}untuk menghasilkan url dari file konfigurasi url aplikasi Anda: mis path('<int:profile.id>/profile', views.profile, name="profile").

Tetapi seperti yang telah dicatat OP, penggunaan reverse()juga biasanya dikombinasikan dengan penggunaan HttpResponseRedirect. Tapi kenapa?

Saya tidak yakin apa ini, tetapi digunakan bersama dengan HttpResponseRedirect. Bagaimana dan kapan reverse ini () seharusnya digunakan?

Pertimbangkan yang berikut ini 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)
        ))

Dan minimal kami 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')
]

Dalam vote()fungsinya, kode di elseblok kami digunakan reversebersama dengan HttpResponseRedirectdalam pola berikut:

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

Ini yang pertama dan terutama, berarti kita tidak perlu melakukan hardcode URL (konsisten dengan prinsip KERING) tetapi yang lebih penting, reverse()memberikan cara yang elegan untuk membangun string URL dengan menangani nilai yang dibongkar dari argumen ( args=(question.id)ditangani oleh URLConfig). Misalkan questionmemiliki atribut idyang berisi nilai 5, URL yang dibangun dari itu reverse()akan menjadi:

'/polls/5/results/'

Dalam kode pengikatan tampilan templat normal, kami menggunakan HttpResponse()atau render()karena biasanya melibatkan lebih sedikit abstraksi: satu fungsi tampilan mengembalikan satu templat:

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

Namun dalam banyak kasus pengalihan yang sah, kami biasanya peduli tentang pembuatan URL dari daftar parameter. Ini termasuk kasus-kasus seperti:

  • Pengiriman formulir HTML melalui POSTpermintaan
  • Validasi pasca masuk pengguna
  • Setel ulang kata sandi melalui token web JSON

Sebagian besar melibatkan beberapa bentuk pengalihan, dan URL dibangun melalui serangkaian parameter. Semoga ini menambah utas jawaban yang sudah membantu!

onlyphantom
sumber
4

Fungsi ini mendukung prinsip kering - memastikan Anda tidak membuat url kode yang sulit di seluruh aplikasi Anda. Sebuah url harus didefinisikan di satu tempat, dan hanya satu tempat - url conf Anda. Setelah itu Anda benar-benar hanya mereferensikan info itu.

Gunakan reverse()untuk memberi Anda url suatu halaman, diberikan path ke view, atau parameter page_name dari conf url Anda. Anda akan menggunakannya dalam kasus di mana tidak masuk akal untuk melakukannya di template dengan {% url 'my-page' %}.

Ada banyak tempat yang memungkinkan Anda menggunakan fungsi ini. Satu tempat yang saya temukan saya gunakan adalah ketika mengarahkan pengguna dalam tampilan (seringkali setelah pemrosesan formulir berhasil) -

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

Anda juga dapat menggunakannya saat menulis tag templat.

Waktu lain yang saya gunakan reverse()adalah dengan pewarisan model. Saya memiliki ListView pada model induk, tetapi ingin mendapatkan dari salah satu objek induk tersebut ke DetailView dari objek anak terkait. Saya melampirkan get__child_url()fungsi ke orang tua yang mengidentifikasi keberadaan anak dan mengembalikan url menggunakan DetailView itu reverse().

Ashish Kumar Sahoo
sumber
2

Jawaban yang ada cukup jelas. Kalau-kalau Anda tidak tahu mengapa itu disebut reverse: Dibutuhkan input dari nama url dan memberikan url yang sebenarnya, yang terbalik dengan memiliki url pertama dan kemudian memberikannya nama.

yyFred
sumber
1
Baru belajar Django dari tutorial (Django Girls). Ini kurva pembelajaran yang curam. Saya pikir nama fungsi ini mengerikan: "cadangan" tanpa kualifikasi apa pun SANGAT SANGAT menyarankan memesan daftar atau string, yang jelas tidak ada hubungannya dengan itu.
mike rodent
@mikerodent saya sepenuhnya setuju dengan Anda. Selain itu, tidak ada jawaban yang menjelaskan mengapa fungsi ini disebut terbalik. Itu nama yang buruk imo.
Soham Dongargaonkar
1

Reverse () digunakan untuk mematuhi prinsip DRY django yaitu jika Anda mengubah url di masa depan maka Anda dapat mereferensikan url tersebut menggunakan reverse (urlname).

AEROCODE
sumber