Tham số URL và logic trong các chế độ xem dựa trên lớp Django (TemplateView)


94

Tôi không rõ cách tốt nhất để truy cập tham số URL trong chế độ xem dựa trên lớp trong Django 1.5.

Hãy xem xét những điều sau:

Lượt xem:

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

Tôi muốn truy cập yeartham số trong chế độ xem của mình, vì vậy tôi có thể thực hiện logic như:

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

Làm thế nào để truy cập tốt nhất vào tham số url trong các CBV như ở trên được phân lớp TemplateViewvà nơi lý tưởng nhất nên đặt logic như thế này, ví dụ. trong một phương pháp?


Có thể lựa chọn đơn giản extra_contextdict trong django2, xem đây
Timo

Câu trả lời:


113

Để truy cập các tham số url trong các chế độ xem dựa trên lớp, hãy sử dụng self.argshoặc self.kwargsnhư vậy, bạn sẽ truy cập nó bằng cáchself.kwargs['year']


1
Nó có được hiểu một cách chính xác rằng tôi không phải tạo các biến trực tiếp trong dạng xem như tôi đã nói ở trên không? (điều gì đó về việc họ kiên trì). Ngoài ra, tôi không hiểu nơi tôi phải đặt logic như trên, ví dụ. trong phương pháp nào? Ngoài ra khi tôi làm year = self.kwargs['year']trong quan điểm tôi nhận được NameError: self not defined.

2
Về mặt kỹ thuật, bạn không nên vì chúng ở cấp độ lớp và là các biến lớp. Về phần NameError, bạn đang cố gắng làm ở year = self.kwargs['year']đâu? Bạn nên làm điều đó trong một phương pháp, bạn không thể làm điều đó ở cấp độ lớp học. Vì vậy, ví dụ, bạn đang sử dụng TemplateViewcó nghĩa là bạn sẽ thực hiện logic trong get_context_dataghi đè của mình .
Ngenator

4
Chỉ để tham khảo: Bạn có thể tìm thấy tài liệu về self.request, self.args, v.v. trong docs.djangoproject.com/en/1.10/topics/class-based-views/…
LShi

Ngoài ra, bạn có thể thực hiện nó trong def __init__(self):hàm trong lớp nếu bạn muốn truy cập nó bên ngoài các hàm khác.
Rahat Zaman

60

Trong trường hợp bạn chuyển tham số URL như thế này:

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

Bạn có thể truy cập nó trong chế độ xem dựa trên lớp bằng cách sử dụng self.request.GET(nó không được trình bày trong self.argscũng như trong 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
Cảm ơn! Điều này đã làm tôi bối rối ... Tôi tiếp tục đọc những thứ ngụ ý rằng các thông số HTTP sẽ nằm trong kwargs.
foobar BBQ

Bạn có thể hiển thị get_queryset () của lớp cha MyClassBasedView không? Tôi sẽ chỉ làm qs=<Object>.objects.<method>
Timo

24

Tôi đã tìm thấy giải pháp thanh lịch này và cho django 1.5 hoặc cao hơn, như được chỉ ra ở đây :

Các khung nhìn dựa trên lớp chung của Django giờ đây tự động bao gồm một biến chế độ xem trong ngữ cảnh. Biến này chỉ vào đối tượng xem của bạn.

Trong views của bạn.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)

Giải pháp công văn được tìm thấy trong câu hỏi này .
chế độ xem đã được chuyển trong ngữ cảnh Mẫu, bạn không thực sự cần phải lo lắng về nó. Trong tệp mẫu yearly.html của bạn, có thể truy cập các thuộc tính chế độ xem đó chỉ bằng cách:

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

Bạn có thể giữ nguyên urlconf của mình .

Điều đáng nói là việc đưa thông tin vào ngữ cảnh mẫu của bạn sẽ ghi đè get_context_data (), do đó, bằng cách nào đó nó đang phá vỡ luồng action bean của django .


8

Cho đến nay, tôi chỉ có thể truy cập các tham số url này từ bên trong phương thức get_queryset, mặc dù tôi chỉ thử nó với ListView chứ không phải TemplateView. Tôi sẽ sử dụng tham số url để tạo một thuộc tính trên cá thể đối tượng, sau đó sử dụng thuộc tính đó trong get_context_data để điền ngữ cảnh:

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

Tôi thấy điều đó thật kỳ lạ, có lỗi hay điều gì đó khi bạn cố gắng thực hiện context['year'] = self.kwargs['year']không? Nó phải có thể truy cập được ở bất kỳ đâu trong lớp.
Ngenator

@Ngenator: Tôi vừa thiết lập một dự án django sạch để kiểm tra lại và hóa ra là bạn đã đúng. Tôi không chắc điều gì đã ngăn chặn điều này trong mã gốc của mình nhưng tôi sẽ tìm hiểu :). Cảm ơn vì đã quan tâm
hellsgate

7

Bạn chỉ cần sử dụng trình trang trí Python để làm cho điều này trở nên dễ hiểu:

class Yearly(TemplateView):

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

Tôi thích cái này. Tài sản có thể tái sử dụng.
cezar
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.