【问题标题】:How to write general django views, where one ListView or DetailView can be used for many models如何编写通用 django 视图,其中一个 ListView 或 DetailView 可用于多个模型
【发布时间】:2020-11-10 21:39:05
【问题描述】:

如何编写可用于多种模型的 url 和视图?

假设我的 models.py 中有 3 个模型 型号名称 : Bike, Scooty, Mobile

现在我们需要通用视图的 Bike 模型:

1]5 views : ListView, DetailView, CreateView, UpdateView, DeleteView
2]5 urls : one for each 5 views we need 1 url
3]4 html files are required : 
    bike_list.html : for ListView
    bike_detail.html : for DetailView
    bike_form.html : for CreateView and UpdateView
    conifirm_delete_view.html : for DeleteView

现在我们需要用于通用视图的 Scooty 模型:

1]again 5 views : ListView, DetailView, CreateView, UpdateView, DeleteView
2]again 5 urls : one for each 5 views we need 1 url
3]4 html files are required : 
    scooty_list.html : for ListView
    scooty_detail.html : for DetailView
    scooty_form.html : for CreateView and UpdateView
    conifirm_delete_view.html : for DeleteView

对于另一个模型,我需要:5 个视图、5 个 URL、4 个 html 文件。

但是,如果您编写通用视图并在 URL 中传递模型的名称,则它的自身并在视图中抓取它并将其传递给通用视图。

所以相同的 5 个视图、5 个 url 和 4 个 html 文件可以用于许多模型。

【问题讨论】:

    标签: html python-3.x django python-3.6


    【解决方案1】:

    GitHub 仓库中的完整代码

    https://github.com/punisher21maximum/Blog/tree/master/Minimise_Django_Code
    

    urls.py

    from django.urls import path
    from .views import (
        #subcat Views
        SubcatListView,
        SubcatDetailView,
        SubcatCreateView,
        SubcatUpdateView,
        SubcatDeleteView,
    )
    from . import views
    
    urlpatterns = [
        #subcat
        path('<str:model>/new/', SubcatCreateView.as_view(), name='subcat-create'),
        path('<str:model>/', SubcatListView.as_view(), name='subcat-list'), 
        path('<str:model>/<int:pk>/', SubcatDetailView.as_view(), name='subcat-detail'), 
        path('<str:model>/<int:pk>/update/', SubcatUpdateView.as_view(), name='subcat-update'),
        path('<str:model>/<int:pk>/delete/', SubcatDeleteView.as_view(), name='subcat-delete'),
    
    ]
    

    views.py

    from django.urls import reverse_lazy
    from .models import Post, Bike, Scooty, Bicycle, Mobile
    model_dict = {
        "Post":Post, 
        "Bike":Bike, 
        "Scooty":Scooty, 
        "Bicycle":Bicycle, 
        "Mobile":Mobile
        }
    
    #get my fields
    def my_get_model_fields(model):
        all_f = [field.name for field in model._meta.get_fields()] 
        rf = ['id', 'date_posted']
        all_f.remove('author')
        for f in all_f: 
            if f in rf or f.endswith('_ptr'):
                all_f.remove(f)
        return all_f
    
    """subcat view"""
    #ListView
    class SubcatListView(ListView):
    
        template_name = 'blog/subcat_list.html'  # <app>/<model>_<viewtype>.html
        context_object_name = 'posts'
        ordering = ['-date_posted']
        paginate_by = 3
    
        """overriding "dispatch" func to set model passed as arg in URL"""
        def dispatch(self, request, *args, **kwargs):
            self.model = model_dict[ kwargs.get('model', None) ]
            return super(SubcatListView, self).dispatch(request, *args, **kwargs)
    
        """ "get_queryset" also Required to override model name """
        def get_queryset(self):
            return self.model.objects.filter()
    
        def get_context_data(self, **kwargs):
            """override "get_context_data" to pass model_name to subcat_list.html"""
            context = super().get_context_data(**kwargs)
            context['class_name'] = self.model._meta.model_name.title() # kwargs.get('model', None) 
            return context
    
    #DetailView
    class SubcatDetailView(DetailView):
        """overriding "dispatch" func to set model passed as arg in URL"""
    
        # template_name = <app>/<model>_<viewtype>.html
        context_object_name = 'post'
        template_name = 'blog/subcat_detail.html'
    
        def dispatch(self, request, *args, **kwargs):
            self.model = model_dict[ kwargs.get('model', None) ]
            return super(SubcatDetailView, self).dispatch(request, *args, **kwargs)
    
        def get_queryset(self):
            return self.model.objects.filter()
    
        def get_context_data(self, **kwargs):
            """override "get_context_data" to pass model_name to subcat_list.html"""
            context = super().get_context_data(**kwargs)
            context['class_name'] = self.model._meta.model_name.title() # kwargs.get('model', None) 
            return context
    
    #CreateView
    class SubcatCreateView(LoginRequiredMixin, CreateView):
        # model = Bike
        
        # fields = my_get_model_fields(Bike)
        template_name = 'blog/subcat_form.html'
    
        def form_valid(self, form):
            """check form author and current logged in user is same"""
            form.instance.author = self.request.user
            return super().form_valid(form)
    
        def dispatch(self, request, *args, **kwargs):
            """overriding "dispatch" func to set model passed as arg in URL"""
            self.model = model_dict[ kwargs.get('model', None) ]
            return super(SubcatCreateView, self).dispatch(request, *args, **kwargs)
    
        def get_form_class(self):
            """overriding "get_form_class" func to get fields for model passed in URL"""
            self.fields = my_get_model_fields(model_dict[self.model._meta.model_name.title()])
            return super(SubcatCreateView, self).get_form_class()
    
    #UpdateView
    class SubcatUpdateView(LoginRequiredMixin, UserPassesTestMixin, UpdateView):
    
        template_name = 'blog/subcat_form.html'
    
        def form_valid(self, form):
            form.instance.author = self.request.user
            return super().form_valid(form)
    
        def test_func(self):
            post = self.get_object()
            if self.request.user == post.author:
                return True
            return False
    
        def dispatch(self, request, *args, **kwargs):
            """overriding "dispatch" func to set model passed as arg in URL"""
            self.model = model_dict[ kwargs.get('model', None) ]
            return super(SubcatUpdateView, self).dispatch(request, *args, **kwargs)
    
        def get_form_class(self):
            """overriding "get_form_class" func to get fields for model passed in URL"""
            self.fields = my_get_model_fields(model_dict[self.model._meta.model_name.title()])
            return super(SubcatUpdateView, self).get_form_class()
    
    #DeleteView
    class SubcatDeleteView(LoginRequiredMixin, UserPassesTestMixin, DeleteView):
    
        template_name = 'blog/post_confirm_delete.html'
    
        def test_func(self):
            post = self.get_object()
            if self.request.user == post.author:
                return True
            return False
    
        def dispatch(self, request, *args, **kwargs):#model
            """overriding "dispatch" func to set model passed as arg in URL"""
            self.model = model_dict[ kwargs.get('model', None) ]
            return super(SubcatDeleteView, self).dispatch(request, *args, **kwargs)   
    
        def get_context_data(self, **kwargs):#class_name
            """override "get_context_data" to pass model_name to subcat_list.html"""
            context = super().get_context_data(**kwargs)
            context['class_name'] = self.model._meta.model_name.title() # kwargs.get('model', None) 
            return context
    
        def get_success_url(self):
            return reverse_lazy('subcat-list', kwargs={'model':self.model._meta.model_name.title()})
    

    subcat_list.html

            {% if class_name  == "Bike" %}
              <a class="article-title" href="{% url 'subcat-detail' pk=post.id model='Bike' %}"> 
            {% elif class_name  == "Scooty" %}
              <a class="article-title" href="{% url 'subcat-detail' pk=post.id model='Scooty' %}"> 
            {% elif class_name  == "Mobile" %}
              <a class="article-title" href="{% url 'subcat-detail' pk=post.id model='Mobile' %}"> 
            {% endif %} 
              <img class="d-block w-100" src="{{ post.img1.url }}" height="250px;" alt="First slide"> 
            </a>
    
            {% if class_name  == "Bike" %}
                {% include "blog/bike_list2.html" %}
            {% elif class_name  == "Scooty" %}
                {% include "blog/scooty_list2.html" %}
            {% elif class_name  == "Mobile" %}
                {% include "blog/mobile_list2.html" %}
            {% endif %}  
    

    subcat_detail.html

         {% if object.author == user %}
          <div>
            <!-- update and delete -->
            {% if class_name  == "Bike" %}
            <a class="btn btn-secondary btn-sm mt-1 mb-1" href="{% url 'subcat-update' pk=object.id model='Bike' %}">Update</a>
            <a class="btn btn-danger btn-sm mt-1 mb-1" href="{% url 'subcat-delete' pk=object.id model='Bike' %}">Delete</a>
            {% elif class_name  == "Scooty" %}
            <a class="btn btn-secondary btn-sm mt-1 mb-1" href="{% url 'subcat-update' pk=object.id model='Scooty' %}">Update</a>
            <a class="btn btn-danger btn-sm mt-1 mb-1" href="{% url 'subcat-delete' pk=object.id model='Scooty' %}">Delete</a>            
            {% elif class_name  == "Mobile" %}
            <a class="btn btn-secondary btn-sm mt-1 mb-1" href="{% url 'subcat-update' pk=object.id model='Mobile' %}">Update</a>
            <a class="btn btn-danger btn-sm mt-1 mb-1" href="{% url 'subcat-delete' pk=object.id model='Mobile' %}">Delete</a>            
            {% endif %}
          </div>
        {% endif %}
    
    
    
            
            <div style="font-size: 12px;">
                {% if class_name  == "Bike" %}
                    {% include "blog/bike_list2.html" %}
                {% elif class_name  == "Scooty" %}
                    {% include "blog/scooty_list2.html" %}
                {% elif class_name  == "Mobile" %}
                    {% include "blog/mobile_list2.html" %}
                {% endif %}
            </div>
    

    【讨论】:

      猜你喜欢
      • 2023-03-27
      • 2012-12-31
      • 2015-03-05
      • 1970-01-01
      • 2010-10-25
      • 1970-01-01
      • 1970-01-01
      • 2017-03-21
      • 1970-01-01
      相关资源
      最近更新 更多