Параметри URL-адреси та логіка у поданнях на основі класу Django (TemplateView)


94

Мені незрозуміло, як найкраще отримувати доступ до параметрів URL-адрес у переглядах на основі класів у Django 1.5.

Розглянемо наступне:

Вид:

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'
    ),
)

Я хочу отримати доступ до yearпараметра в моєму поданні, тому я можу робити логіку, як:

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

Як найкраще отримати доступ до параметра url у CBV, як зазначений вище, який підкласифіковано, TemplateViewі де в ідеалі слід розмістити таку логіку, наприклад. у методі?


Є варіант простого extra_contextдикту в django2, див. Тут
Тимо

Відповіді:


113

Щоб отримати доступ до параметрів url у поданнях на основі класу, використовуйте, self.argsабо self.kwargsприблизно так, ви отримаєте доступ до нього, виконавшиself.kwargs['year']


1
Чи правильно зрозуміло, що я не повинен створювати змінні безпосередньо у поданні, як у мене вище? (щось про те, що вони наполегливі). Також я не розумію, де я повинен розміщувати логіку, як вище, наприклад. в якому методі? Крім того, коли я year = self.kwargs['year']переглядаю, я отримую NameError: self not defined.

2
Технічно ви не повинні, оскільки вони знаходяться на рівні класу і є змінними класу. Щодо того NameError, де ти намагаєшся робити year = self.kwargs['year']? Ви повинні робити це методом, ви не можете робити це на рівні класу. Так, наприклад, ви використовуєте a, TemplateViewщо означає, що ви зробите логіку у своєму get_context_dataзаміну.
Нгенатор

4
Тільки для посилання: Документацію щодо self.request, self.args тощо можна знайти на docs.djangoproject.com/en/1.10/topics/class-based-views/…
LShi

Також ви можете зробити це у def __init__(self):функції у класі, якщо хочете отримати до нього доступ за межами інших функцій.
Рахат Заман

60

Якщо ви передаєте такий параметр URL:

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

Ви можете отримати доступ до нього у поданні на основі класу, використовуючи self.request.GET(це не представлено self.argsні в, ні в 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)

4
Дякую! Це мене бентежило ... Я продовжую читати матеріали, які передбачають, що параметри HTTP будуть у kwargs.
foobarbecue

Чи можете ви показати get_queryset () суперкласу MyClassBasedView? Я б просто зробив qs=<Object>.objects.<method>
Тимо

24

Я знайшов це елегантне рішення для django 1.5 або вище, як зазначено тут :

Загальні подання на основі класу Django тепер автоматично включають змінну подання в контекст. Ця змінна вказує на ваш об'єкт перегляду.

У вашому views.py:

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)

Рішення диспетчерським знайдено в цьому питанні .
Оскільки подання вже передано в контексті Шаблону, тобі не потрібно над цим турбуватися. У вашому файлі шаблону yearly.html можна отримати доступ до цих атрибутів подання просто за допомогою:

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

Ви можете зберегти urlconf таким, яким він є.

Варто згадати, що потрапляння інформації в контекст вашого шаблону перезаписує get_context_data (), тож це якось порушує потік дій django .


8

Наразі я мав доступ до цих параметрів url лише з методу get_queryset, хоча я пробував це лише за допомогою ListView, а не TemplateView. Я буду використовувати параметр url для створення атрибута на екземплярі об'єкта, а потім використовувати цей атрибут у get_context_data для заповнення контексту:

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

Я вважаю це дивним, чи є помилка чи щось інше, коли ви намагаєтесь це зробити context['year'] = self.kwargs['year']? Вона повинна бути доступна в будь-якому місці класу.
Ngenator

@Ngenator: Я щойно створив чистий проект django, щоб подвійно перевірити, і виявляється, ти маєш рацію. Я не впевнений, що заважало цьому у моєму оригінальному коді, але я дізнаюся :). Дякую за
хедс

7

Як би просто використовувати декоратори Python, щоб зробити це зрозумілим:

class Yearly(TemplateView):

    @property
    def year(self):
       return self.kwargs['year']

Мені цей подобається. Власність багаторазове.
cezar
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.