Chế độ xem dựa trên lớp Django: Làm cách nào để chuyển các tham số bổ sung cho phương thức as_view?


95

Tôi có một chế độ xem dựa trên lớp tùy chỉnh

# myapp/views.py
from django.views.generic import *

class MyView(DetailView):
    template_name = 'detail.html'
    model = MyModel

    def get_object(self, queryset=None):
        return queryset.get(slug=self.slug)

Tôi muốn chuyển tham số slug (hoặc các tham số khác cho chế độ xem) như thế này

MyView.as_view(slug='hello_world')

Tôi có cần ghi đè bất kỳ phương thức nào để có thể thực hiện việc này không?

Câu trả lời:


113

Nếu urlconf của bạn trông giống như sau:

url(r'^(?P<slug>[a-zA-Z0-9-]+)/$', MyView.as_view(), name = 'my_named_view')

thì slug sẽ có sẵn bên trong các hàm xem của bạn (chẳng hạn như 'get_queryset') như sau:

self.kwargs['slug']

18
Để tránh một ngoại lệ trong trường hợp này là một tham số tùy chọn: sử dụngself.kwargs.get('slug', None)
Risadinha

6
Chỉ tò mò, khi / ở đâu "self.kwargs" này được cư trú? Tôi đang tìm kiếm hàm lớp cơ sở nơi điều này được đặt.
binithb

Trong github.com/django/django/blob/master/django/views/generic/… trongclass View: def as_view(cls, **initkwargs): def view(request, *args, **kwargs):
Dữ liệu Apollo

Không trả lời câu hỏi.
Kireeti K

Phương pháp này hiện đang bị phản đối, bây giờ bạn có thể sử dụngurl('<slug:slug>', MyView.as_view(), name='my_named_view')
Rahat Zaman

91

Mọi tham số được truyền cho as_viewphương thức là một biến thể hiện của lớp View. Điều đó có nghĩa là để thêm slugdưới dạng một tham số, bạn phải tạo nó dưới dạng một biến thể hiện trong lớp con của bạn:

# myapp/views.py
from django.views.generic import DetailView

class MyView(DetailView):
    template_name = 'detail.html'
    model = MyModel
    # additional parameters
    slug = None

    def get_object(self, queryset=None):
        return queryset.get(slug=self.slug)

Điều đó sẽ làm cho MyView.as_view(slug='hello_world')công việc.

Nếu bạn đang chuyển các biến thông qua các từ khóa, hãy sử dụng những gì ông Erikkson đề xuất: https://stackoverflow.com/a/11494666/9903


2
Không bao giờ làm import *. Đã chỉnh sửa bài viết của bạn.
holms

@holms cho sự hiểu biết của độc giả trong tương lai, PEP8 nói rằng " Nên tránh nhập ký tự đại diện (từ nhập <mô-đun> )". Không nên là mạnh mẽ như bắt buộc và đây là một ví dụ nhưng có chắc chắn * nên tránh nhập khẩu wildcard: python.org/dev/peps/pep-0008/#imports

Không có gì là bắt buộc ở bất cứ đâu, chúng tôi có thể phá vỡ bất cứ thứ gì chúng tôi muốn theo bất kỳ cách nào chúng tôi muốn, nhưng pep8 chỉ là đề xuất của các phương pháp thực hành và trong cộng đồng python, quy tắc chung là sử dụng tất cả các phương pháp này càng nhiều càng tốt để tránh các vấn đề tiếp theo. Linter của tôi luôn trống khi tôi cam kết mã của mình :) không có vấn đề gì.
holms

Giá trị của slug = 'hello_world' cho một biến thực tế là gì?
Gonzalo Dambra

19

Cần lưu ý rằng bạn không cần phải ghi đè get_object()để tìm kiếm một đối tượng dựa trên một slug được truyền dưới dạng từ khóa arg - bạn có thể sử dụng các thuộc tính của SingleObjectMixin https://docs.djangoproject.com/en/1.5/ref/ class-based-views / mixins-single-object / # singleobjectmixin

# views.py
class MyView(DetailView):
    model = MyModel
    slug_field = 'slug_field_name'
    slug_url_kwarg = 'model_slug'
    context_object_name = 'my_model'

# urls.py
url(r'^(?P<model_slug>[\w-]+)/$', MyView.as_view(), name = 'my_named_view')

# mymodel_detail.html
{{ my_model.slug_field_name }}

(cả hai slug_fieldslug_url_kwargmặc định thành 'slug')


1
tôi có nên chuyển câu trả lời của mình thành câu trả lời wiki và thêm mã của bạn vào đó không?

15

Nếu bạn muốn thêm một đối tượng vào ngữ cảnh cho mẫu, bạn có thể ghi đè get_context_datavà thêm vào ngữ cảnh của nó. Yêu cầu cũng là một phần của bản thân trong trường hợp bạn cần người dùng request.user .

def get_context_data(self, **kwargs):
        context = super(MyTemplateView, self).get_context_data(**kwargs)
        if 'slug' in self.kwargs:
            context['object'] = get_object_or_404(MyObject, slug=self.kwargs['slug'])
            context['objects'] = get_objects_by_user(self.request.user)

        return context

Là gì MyObject?
Rob Kwasowski

13

Bạn có thể chuyển các tham số từ urls.py https://docs.djangoproject.com/en/1.7/topics/http/urls/#passing-extra-options-to-view-functions

Điều này cũng hoạt động đối với các chế độ xem chung. Thí dụ:

url(r'^$', views.SectionView.as_view(), { 'pk': 'homepage', 'another_param':'?'}, name='main_page'),

Trong trường hợp này, các tham số được truyền cho khung nhìn không nhất thiết phải là các biến thể hiện của lớp View. Sử dụng phương pháp này, bạn không cần phải mã hóa tên trang mặc định vào mô hình YourView mà chỉ cần chuyển nó dưới dạng tham số từ urlconf.


cảm ơn bạn, tôi đã tìm kiếm khá lâu cho cái này!
Ilja

7

Như đã trình bày bởi Yaroslav Nikitenko , nếu bạn không muốn hardcode một biến Ví dụ mới đến lớp View, bạn có thể vượt qua tùy chọn bổ sung để xem chức năng từ urls.pynhư thế này:

url(r'^$', YourView.as_view(), {'slug': 'hello_world'}, name='page_name')

Tôi chỉ muốn thêm cách sử dụng nó từ chế độ xem. Bạn có thể thực hiện một trong các phương pháp sau:

# If slug is optional
def the_function(self, request, slug=None):
    # use slug here

# if slug is an optional param among others
def the_function(self, request, **kwargs):
    slug = kwargs.get("slug", None)
    other_param = kwargs.get("other_param", None)

# If slug is required
def the_function(self, request, slug):
    # use slug here

1
Tôi muốn chỉnh sửa điều này trong câu trả lời của Yaroslav Nikitenko , nhưng nó đã bị từ chối, vì vậy tôi đã tự sửa vì tôi cảm thấy đó là thông tin bị thiếu khi tôi cần.
Emile Bergeron

Cảm ơn vì bài đăng của bạn! Tôi không nhớ có phải tôi đã từ chối chỉnh sửa của bạn hay không và tại sao.
Yaroslav Nikitenko

@YaroslavNikitenko Nhìn lại thì quá lớn đối với một bản chỉnh sửa và tốt nhất là một câu trả lời dưới dạng một câu trả lời mới.
Emile Bergeron

@EmileBergeron Câu hỏi ban đầu là về các quan điểm chung như DetailViewlớp học. Bạn có thể giải thích làm thế nào để sử dụng nó ở đó?
bartaelterman,

3

Đối với django 3.0, đây là những gì phù hợp với tôi:

# myapp/views.py
from django.views.generic import DetailView

class MyView(DetailView):
    template_name = 'detail.html'
    slug = None

    def get_object(self, queryset=None):
        self.slug = self.kwargs.get('slug', None)
        return queryset.get(slug=self.slug)

# myapp/urls.py
from django.urls import path
from . import views

urlpatterns = [
    path('slug/<slug:slug>/', views.MyView.as_view(), name='myview_by_tag'),
]
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.