มุมมองตามคลาส Django: ฉันจะส่งผ่านพารามิเตอร์เพิ่มเติมไปยังเมธอด as_view ได้อย่างไร


100

ฉันมีมุมมองตามคลาสที่กำหนดเอง

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

ฉันต้องการส่งผ่านพารามิเตอร์ slug (หรือพารามิเตอร์อื่น ๆ ไปยังมุมมอง) เช่นนี้

MyView.as_view(slug='hello_world')

ฉันต้องลบล้างวิธีการใด ๆ จึงจะสามารถทำได้หรือไม่?

คำตอบ:


115

หาก urlconf ของคุณมีลักษณะดังนี้:

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

จากนั้นกระสุนจะพร้อมใช้งานในฟังก์ชันมุมมองของคุณ (เช่น 'get_queryset') ดังนี้:

self.kwargs['slug']

18
เพื่อหลีกเลี่ยงข้อยกเว้นในกรณีที่เป็นพารามิเตอร์ทางเลือกให้ใช้self.kwargs.get('slug', None)
Risadinha

6
แค่อยากรู้ว่า "self.kwargs" นี้มีประชากรเมื่อไร / ที่ไหน ฉันกำลังมองหาฟังก์ชันคลาสพื้นฐานที่ตั้งค่านี้
binithb

ในgithub.com/django/django/blob/master/django/views/generic/… inclass View: def as_view(cls, **initkwargs): def view(request, *args, **kwargs):
Apollo Data

ไม่ตอบคำถาม.
Kireeti K

วิธีนี้เลิกใช้แล้วตอนนี้คุณสามารถใช้ได้url('<slug:slug>', MyView.as_view(), name='my_named_view')
Rahat Zaman

96

ทุกพารามิเตอร์ที่ส่งไปยังas_viewเมธอดคือตัวแปรอินสแตนซ์ของคลาส View นั่นหมายถึงการเพิ่มslugเป็นพารามิเตอร์คุณต้องสร้างเป็นตัวแปรอินสแตนซ์ในคลาสย่อยของคุณ:

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

ที่ควรจะMyView.as_view(slug='hello_world')ทำงาน

หากคุณส่งผ่านตัวแปรผ่านคีย์เวิร์ดให้ใช้สิ่งที่คุณ Erikkson แนะนำ: https://stackoverflow.com/a/11494666/9903


3
import *ไม่เคยทำ แก้ไขโพสต์ของคุณ
Holms

@holms เพื่อการรู้แจ้งของผู้อ่านในอนาคต PEP8 กล่าวว่า " ควรหลีกเลี่ยงการนำเข้าสัญลักษณ์แทน (จากการนำเข้า <โมดูล> )" ไม่ควรแรงเท่าที่ควรและนี่คือตัวอย่าง แต่ใช่แน่นอน * ควรหลีกเลี่ยงการนำเข้าไวลด์การ์ด: python.org/dev/peps/pep-0008/#imports

ไม่มีอะไรที่ต้องทำในทุกที่เราสามารถทำลายทุกสิ่งที่เราต้องการได้ทุกวิธีที่เราต้องการ แต่ pep8 เป็นเพียงคำแนะนำของการปฏิบัติและในชุมชน python มันเป็นกฎง่ายๆที่จะใช้การปฏิบัติทั้งหมดนี้ให้มากที่สุดเพื่อหลีกเลี่ยงปัญหาเพิ่มเติม เศษกระดาษของฉันว่างเปล่าเสมอเมื่อฉันยอมรับรหัสของฉัน :) ไม่ว่าจะเกิดอะไรขึ้น
Holms

slug = 'hello_world' สำหรับตัวแปรจริงคืออะไร?
Gonzalo Dambra

ฉันเดาว่า slug เป็นตัวแปรคลาสและไม่ใช่ตัวแปรอินสแตนซ์ที่นี่
Aagam Sheth

19

เป็นที่น่าสังเกตว่าคุณไม่จำเป็นต้องลบล้างget_object()เพื่อค้นหาวัตถุตามกระสุนที่ส่งผ่านเป็นคำหลัก arg - คุณสามารถใช้แอตทริบิวต์ของ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 }}

(ทั้งคู่slug_fieldและslug_url_kwargค่าเริ่มต้นเป็น'slug')


1
ฉันควรเปลี่ยนคำตอบให้เป็นคำตอบวิกิและเพิ่มรหัสของคุณลงไปหรือไม่

15

หากคุณต้องการเพิ่มออบเจ็กต์ในบริบทสำหรับเทมเพลตคุณสามารถแทนที่get_context_dataและเพิ่มลงในบริบทได้ การร้องขอนอกจากนี้ยังเป็นส่วนหนึ่งของตัวเองในกรณีที่คุณต้อง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

คืออะไรMyObject?
Rob Kwasowski

13

คุณสามารถส่งผ่านพารามิเตอร์จาก urls.py https://docs.djangoproject.com/en/1.7/topics/http/urls/#passing-extra-options-to-view-functions

นอกจากนี้ยังใช้ได้กับมุมมองทั่วไป ตัวอย่าง:

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

ในกรณีนี้พารามิเตอร์ที่ส่งไปยังมุมมองไม่ควรเป็นตัวแปรอินสแตนซ์ของคลาส View การใช้วิธีนี้คุณไม่จำเป็นต้องฮาร์ดโค้ดชื่อเพจเริ่มต้นลงในโมเดล YourView แต่คุณสามารถส่งเป็นพารามิเตอร์จาก urlconf ได้


7

ตามที่ระบุไว้โดยYaroslav Nikitenkoหากคุณไม่ต้องการฮาร์ดโค้ดตัวแปรอินสแตนซ์ใหม่ไปยังคลาส View คุณสามารถส่งตัวเลือกเพิ่มเติมเพื่อดูฟังก์ชันจากurls.pyสิ่งนี้:

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

ฉันแค่อยากจะเพิ่มวิธีการใช้งานจากมุมมอง คุณสามารถใช้วิธีใดวิธีหนึ่งต่อไปนี้:

# 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
ฉันต้องการแก้ไขสิ่งนี้ในคำตอบของYaroslav Nikitenkoแต่ถูกปฏิเสธดังนั้นฉันจึงทำเองเพราะฉันรู้สึกว่ามันเป็นข้อมูลที่ขาดหายไปเมื่อฉันต้องการ
Emile Bergeron

@YaroslavNikitenko ในการมองย้อนกลับมันใหญ่เกินไปสำหรับการแก้ไขและดีที่สุดสำหรับการตอบกลับในรูปแบบของคำตอบใหม่
Emile Bergeron

@EmileBergeron คำถามเริ่มต้นเกี่ยวกับมุมมองทั่วไปเช่นDetailViewชั้นเรียน คุณช่วยอธิบายวิธีใช้ที่นั่นได้ไหม
bartaelterman

3

สำหรับ django 3.0 นี่คือสิ่งที่ใช้ได้ผลสำหรับฉัน:

# 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'),
]
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.