【问题标题】:Django - Pass model name as parameter to generic viewDjango - 将模型名称作为参数传递给通用视图
【发布时间】:2013-04-18 10:21:31
【问题描述】:

假设我有一些继承自基类 Animal 的模型。我可以使用通用视图并将 Cat/12 路由到详细视图,将 Dod/10 路由到具有不同上下文的相同详细视图。 但我想从 url 中获取模型名称,这样我就不必定义路由了。

我有这样的事情:

url(r'^cat/(?P<slug>[-\w]+)/$',
    DetailView.as_view(
        queryset=Cat.objects.filter(),
        model=Cat,
        context_object_name='animal',
        template_name='animal/detail.html'),
    name='detail'),
url(r'^dog/(?P<slug>[-\w]+)/$',
    DetailView.as_view(
        queryset=Dog.objects.filter(),
        model=Dog,
        context_object_name='animal',
        template_name='animal/detail.html'),
    name='detail'),
...

显然,这是太多重复的代码。我宁愿做这样的事情:

url(r'^?P<my_animal>\w+/(?P<slug>[-\w]+)/$',
    DetailView.as_view(
        queryset=my_animal.objects.filter(),
        model=my_animal,
        context_object_name='animal',
        template_name='animal/detail.html'),
    name='detail'),
...

我可以这样做吗?

编辑

感谢达尔文的帮助,这就是我最终得到的结果。它避免了 if/else 来获取模型名称:

class AnimalDetailView(DetailView):
    context_object_name='animal'
    template_name='animals/detail.html'

    def dispatch(self, request, *args, **kwargs):
        my_animal = kwargs.get('my_animal', None)
        self.model = get_model('animals',my_animal.capitalize())
        try:
            ret = super(AnimalDetailView, self).dispatch(request, *args, **kwargs)
        except AttributeError:
            raise Http404
        return ret

    def get_queryset(self):
        return self.model.objects.filter()

下次我有关于继承的问题时,我会咨询达尔文!大声笑

【问题讨论】:

    标签: django django-generic-views


    【解决方案1】:

    您可以从 DetailView 继承并覆盖 dispatch 方法来构建您自己的规则,如下所示:

    class AnimalDetailView(DetailView):
        context_object_name='animal'
        template_name='animal/detail.html'
    
        def dispatch(self, request, *args, **kwargs):
            my_animal = kwargs.get('my_animal', None)
            if my_animal == 'dog':
                self.model = Dog
            elif my_animal == 'cat':
                self.model = Cat
    
            return super(AnimalDetailView, self).dispatch(request, *args, **kwargs)
    
        def get_queryset(self):
            return self.model.objects.filter()
    

    并使用这样的 urlpattern:

    url(r'^?P<my_animal>\w+/(?P<slug>[-\w]+)/$', AnimalDetailView.as_view())
    

    编辑: 上次我犯了一个错误,因为我们不能实例化视图类,只能使用'as_view()'方法。尝试新方法,我认为这会有所帮助。

    【讨论】:

    • 一种无益的错误:This method is available only on the view class.
    • 再看代码,handler是在AnimalDetailView之后定义的,不是在里面。
    • 我在 AnimalDetailView 类之外定义了它。在我的 views.py 中,我使用 from animals.views import handler 导入
    • 不错,达尔文。感谢您在这方面坚持我!我会投票给你,但我的名声不够好。我猜妈妈是对的,:-(
    【解决方案2】:

    是的,您的网址中的任何命名参数(即?P&lt;my_animal&gt;will automatically be passed as keyword arguments to your views,

    让这个[Class Based Views]工作的关键部分是,当调用基于类的视图时,各种有用的东西都存储在self上;以及请求 (self.request) 这包括根据 URLconf 捕获的位置 (self.args) 和基于名称 (self.kwargs) 的参数。

    因此您可以在视图中以self.kwargs['my_animal'] 的身份访问它们。

    如果您使用look at the __init__ method of BaseDetailViewDetailView 从中继承),您会看到它所做的只是获取 kwargs 并将它们分配给实例属性,因此您可以轻松地执行以下操作:

    url(r'^?P<model>\w+/(?P<slug>[-\w]+)/$',...
    

    并且视图应该自动将 URL 中传递的值分配给self.model。当然,您需要小心并确保在此处验证输入,但这是从用户指定的模型中动态抓取对象的好方法

    【讨论】:

    • 很好,但我做错了,我猜:我在 urls.py 中得到 name 'my_plant' is not defined
    【解决方案3】:

    另一种方法是直接传递模型而不是通过变量传递它

    url.py

    from django.urls import path
    from . import views
    # Common url
    urlpatterns = [
        path('', views.MoneyIndex.as_view(), name='money_index'),
        path('cat', views.CatListView.as_view(), name='cat_list'),
        path('dog', views.DogListView.as_view(), name='dog_list'),
        ]
    
    # Dynamic url
    MYMODELS = ['Cat','Dog',]
    for modelX in MYMODELS:
        urlpatterns = urlpatterns + [
            path('{0}/add'.format(modelX.lower()), views.MyCreateView.as_view(model=modelX), name='{0}_create'.format(modelX.lower())),
            path('{0}/<pk>'.format(modelX.lower()), views.MyDetailView.as_view(model=modelX), name='{0}_detail'.format(modelX.lower())),
            path('{0}/<pk>/upd'.format(modelX.lower()), views.MyUpdateView.as_view(model=modelX), name='{0}_update'.format(modelX.lower())),
            path('{0}/<pk>/del'.format(modelX.lower()), views.MyDeleteView.as_view(model=modelX), name='{0}_delete'.format(modelX.lower())),
        ]
    

    view.py

    from django.views import generic
    from .models import Cat, Dog
    from .forms import CatForm, DogForm
    
    class MyDetailView(generic.DetailView):     
            def __init__(self, *args, **kwargs):
                super(MyDetailView, self).__init__(*args, **kwargs)
                modeltxt = self.model
                self.model = eval(modeltxt)
    
    
     class MyCreateView(generic.CreateView):
        def __init__(self, *args, **kwargs):
            super(MyCreateView, self).__init__(*args, **kwargs)
            modeltxt = self.model
            self.model = eval(modeltxt)
            self.form_class = eval('{0}Form'.format(modeltxt))
            self.success_url = reverse_lazy('{0}_list'.format(modeltxt.lower()))    
    
    
    class MyUpdateView(generic.UpdateView):
        def __init__(self, *args, **kwargs):
            super(MyUpdateView, self).__init__(*args, **kwargs)
            modeltxt = self.model
            self.model = eval(modeltxt)
            self.form_class = eval('{0}Form'.format(modeltxt))
            self.success_url = reverse_lazy('{0}_list'.format(modeltxt.lower())) 
    
    
    class MyDeleteView(generic.DeleteView):
        def __init__(self, *args, **kwargs):
            super(MyDeleteView, self).__init__(*args, **kwargs)
            modeltxt = self.model
            self.model = eval(modeltxt)
            # Must be done because default points to modelname_confirm_delete.html
            self.template_name = 'appname/{0}_detail.html'.format(modeltxt.lower())
            self.success_url = reverse_lazy('{0}_list'.format(modeltxt.lower()))
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2014-07-03
      • 1970-01-01
      • 2012-01-17
      • 2015-04-04
      • 1970-01-01
      • 1970-01-01
      • 2018-05-04
      • 1970-01-01
      相关资源
      最近更新 更多