Parameter URL dan logika dalam tampilan berbasis kelas Django (TemplateView)

97

Tidak jelas bagi saya bagaimana cara terbaik mengakses parameter URL dalam tampilan berbasis kelas di Django 1.5.

Pertimbangkan hal berikut:

Melihat:

from django.views.generic.base import TemplateView


class Yearly(TemplateView):
    template_name = "calendars/yearly.html"

    current_year = datetime.datetime.now().year
    current_month = datetime.datetime.now().month

    def get_context_data(self, **kwargs):
        context = super(Yearly, self).get_context_data(**kwargs)
        context['current_year'] = self.current_year
        context['current_month'] = self.current_month
        return context

URLCONF:

from .views import Yearly


urlpatterns = patterns('',
    url(
        regex=r'^(?P<year>\d+)/$',
        view=Yearly.as_view(),
        name='yearly-view'
    ),
)

Saya ingin mengakses yearparameter dalam tampilan saya, jadi saya bisa melakukan logika seperti:

month_names = [
    "January", "February", "March", "April", 
    "May", "June", "July", "August", 
    "September", "October", "November", "December"
]

for month, month_name in enumerate(month_names, start=1):
    is_current = False
    if year == current_year and month == current_month:
        is_current = True
        months.append({
            'month': month,
            'name': month_name,
            'is_current': is_current
        })

Bagaimana cara terbaik mengakses parameter url di CBV seperti di atas yang merupakan subkelas TemplateViewdan di mana idealnya menempatkan logika seperti ini, mis. dalam suatu metode?

Nayan
sumber
Ada opsi extra_contextdikt sederhana di django2, lihat di sini
Timo

Jawaban:

117

Untuk mengakses parameter url dalam tampilan berbasis kelas, gunakan self.argsatau self.kwargslebih Anda akan mengaksesnya dengan melakukanself.kwargs['year']

Ngenator
sumber
1
Apakah dipahami dengan benar bahwa saya tidak seharusnya membuat variabel langsung dalam tampilan seperti yang saya miliki di atas? (sesuatu tentang mereka yang gigih). Juga saya tidak mengerti di mana saya seharusnya menempatkan logika seperti di atas, misalnya. dengan metode apa? Juga ketika saya melakukannya year = self.kwargs['year']dalam tampilan yang saya dapatkan NameError: self not defined.
2
Secara teknis Anda tidak boleh karena mereka berada di tingkat kelas dan merupakan variabel kelas. Adapun NameError, di mana Anda coba lakukan year = self.kwargs['year']? Anda harus melakukannya dengan metode, Anda tidak dapat melakukannya di tingkat kelas. Jadi misalnya, Anda menggunakan a TemplateViewyang berarti Anda akan melakukan logika dalam get_context_datapenggantian.
Ngenator
4
Hanya untuk referensi: Dokumentasi tentang self.request, self.args dll dapat ditemukan di docs.djangoproject.com/en/1.10/topics/class-based-views/…
LShi
Anda juga dapat melakukannya dalam def __init__(self):fungsi di kelas jika Anda ingin mengaksesnya di luar fungsi lain.
Rahat Zaman
61

Jika Anda melewatkan parameter URL seperti ini:

http://<my_url>/?order_by=created

Anda dapat mengaksesnya dalam tampilan berbasis kelas dengan menggunakan self.request.GET(tidak disajikan dalam self.argsatau dalam self.kwargs):

class MyClassBasedView(ObjectList):
    ...
    def get_queryset(self):
        order_by = self.request.GET.get('order_by') or '-created'
        qs = super(MyClassBasedView, self).get_queryset()
        return qs.order_by(order_by)
niekas
sumber
5
Terima kasih! Ini membingungkan saya ... Saya terus membaca hal-hal yang menyiratkan parameter HTTP akan berada di kwargs.
foobarbona
Dapatkah Anda menampilkan get_queryset () dari superclass dari MyClassBasedView? Saya hanya akan melakukannya qs=<Object>.objects.<method>
Timo
24

Saya menemukan solusi elegan ini, dan untuk django 1.5 atau lebih tinggi, seperti yang ditunjukkan di sini :

Tampilan berbasis kelas umum Django sekarang secara otomatis menyertakan variabel tampilan dalam konteks. Variabel ini menunjuk ke objek tampilan Anda.

Di views.py Anda:

from django.views.generic.base import TemplateView    

class Yearly(TemplateView):
    template_name = "calendars/yearly.html"
    # Not here 
    current_year = datetime.datetime.now().year
    current_month = datetime.datetime.now().month

    # dispatch is called when the class instance loads
    def dispatch(self, request, *args, **kwargs):
        self.year = kwargs.get('year', "any_default")

    # other code

    # needed to have an HttpResponse
    return super(Yearly, self).dispatch(request, *args, **kwargs)

Solusi pengiriman ditemukan dalam pertanyaan ini .
Karena tampilan telah diteruskan dalam konteks Template, Anda tidak perlu mengkhawatirkannya. Dalam file template Anda yearly.html, dimungkinkan untuk mengakses atribut tampilan tersebut hanya dengan:

{{ view.year }}
{{ view.current_year }}
{{ view.current_month }}

Anda dapat mempertahankan urlconf Anda apa adanya.

Perlu disebutkan bahwa mendapatkan informasi ke dalam konteks cetakan anda menimpa get_context_data (), jadi entah bagaimana merusak aliran kacang aksi django .

Evhz
sumber
8

Sejauh ini saya hanya dapat mengakses parameter url ini dari dalam metode get_queryset, meskipun saya hanya mencobanya dengan ListView bukan TemplateView. Saya akan menggunakan parameter url untuk membuat atribut pada instance objek, lalu menggunakan atribut itu di get_context_data untuk mengisi konteks:

class Yearly(TemplateView):
    template_name = "calendars/yearly.html"

    current_year = datetime.datetime.now().year
    current_month = datetime.datetime.now().month

    def get_queryset(self):
        self.year = self.kwargs['year']
        queryset = super(Yearly, self).get_queryset()
        return queryset

    def get_context_data(self, **kwargs):
        context = super(Yearly, self).get_context_data(**kwargs)
        context['current_year'] = self.current_year
        context['current_month'] = self.current_month
        context['year'] = self.year
        return context
gerbang Neraka
sumber
Saya merasa aneh, apakah ada kesalahan atau sesuatu ketika Anda mencoba melakukannya context['year'] = self.kwargs['year']? Ini harus dapat diakses di mana saja di kelas.
Ngenator
@ Ngenator: Saya baru saja menyiapkan proyek django bersih untuk diperiksa ulang dan ternyata Anda benar. Saya tidak yakin apa yang mencegah ini dalam kode asli saya tetapi saya akan mencari tahu :). Terima kasih atas perhatiannya
hellsgate
7

Bagaimana kalau menggunakan dekorator Python untuk membuat ini bisa dimengerti:

class Yearly(TemplateView):

    @property
    def year(self):
       return self.kwargs['year']
danizen
sumber
Saya suka yang ini. Properti ini dapat digunakan kembali.
cezar