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

97

Мне неясно, как лучше всего получить доступ к параметрам 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, см. Здесь
Тимо

Ответы:

117

Чтобы получить доступ к параметрам URL-адреса в представлениях на основе классов, используйте self.argsили self.kwargsчтобы получить к нему доступ, выполнивself.kwargs['year']

Ngenator
источник
1
Правильно ли понятно, что я не должен создавать переменные непосредственно в представлении, как показано выше? (что-то в их настойчивости). Также я не понимаю, где я должен разместить логику, подобную приведенной выше, например. в каком методе? Также когда я делаю year = self.kwargs['year']вид, я получаю NameError: self not defined.
2
Технически вы не должны этого делать, поскольку они находятся на уровне класса и являются переменными класса. Что до того NameError, что вы пытаетесь сделать year = self.kwargs['year']? Вы должны делать это в методе, вы не можете сделать это на уровне класса. Так, например, вы используете, TemplateViewчто означает, что вы будете выполнять логику в своем get_context_dataпереопределении.
Ngenator 02
4
Только для справки: документацию по self.request, self.args и т. Д. Можно найти в docs.djangoproject.com/en/1.10/topics/class-based-views/…
LShi
Также вы можете сделать это в def __init__(self):функции класса, если хотите получить к нему доступ вне других функций.
Rahat Zaman
61

Если вы передаете параметр 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)
Niekas
источник
5
Благодарность! Это сбивает меня с толку ... Я продолжаю читать материал, который подразумевает, что параметры HTTP будут в kwargs.
foobar барбекю
Можете ли вы показать 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)

Решение по отправке, найденное в этом вопросе .
По мере того как вид уже пройдена в контексте шаблона, вы действительно не нужно беспокоиться об этом. В вашем файле шаблона Annual.html можно получить доступ к этим атрибутам представления просто:

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

Вы можете оставить свой urlconf как есть.

Стоит упомянуть, что получение информации в контексте вашего шаблона перезаписывает get_context_data (), поэтому это каким-то образом нарушает поток bean-компонентов действия django .

Evhz
источник
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 для двойной проверки, и оказалось, что вы правы. Я не уверен, что мешало этому в моем исходном коде, но я выясню :). Спасибо за хедз-ап
hellsgate
7

Как насчет использования декораторов Python, чтобы сделать это понятным:

class Yearly(TemplateView):

    @property
    def year(self):
       return self.kwargs['year']
данизен
источник
Мне нравится этот. Недвижимость многоразового использования.
cezar