【问题标题】:Django class based view ListView with form带有表单的基于 Django 类的视图 ListView
【发布时间】:2011-09-18 09:23:48
【问题描述】:

主视图是一个简单的分页 ListView,我想给它添加一个搜索表单。

我认为这样的事情可以解决问题:

class MyListView(ListView, FormView):
    form_class = MySearchForm
    success_url = 'my-sucess-url'
    model = MyModel
    # ...

但显然我弄错了..我在官方文档中找不到如何做到这一点。

建议?

【问题讨论】:

    标签: django views


    【解决方案1】:

    在 Django 2.2 中,您可以这样做(至少使用 get-request 可以正常工作):

    from django.views.generic import ListView
    from django.views.generic.edit import FormMixin
    
    from .models import MyModel
    from .forms import MySearchForm
    
    class ListPageView(FormMixin, ListView):
        template_name = 'property_list.html'
        model = MyModel
        form_class = MySearchForm
        queryset = MyModel.objects.all()
    

    ListView 之前使用FormMixin。如果你想在TemplateView 中使用SearchForm,你可以这样做:

    from django.views.generic.base import TemplateView
    from django.views.generic.edit import FormMixin
    
    from .models import MyModel
    from .forms import MySearchForm
    
    class HomePageView(FormMixin, TemplateView):
        template_name = 'home.html'
        form_class = MySearchForm
    

    【讨论】:

      【解决方案2】:

      the official documentation 中介绍了使用 mixins 向索引和列表视图添加表单。

      文档通常建议不要使用这种方法。它建议改为简单地编写更多 python,并手动编写视图。

      【讨论】:

      • 值得注意的是,他们建议不要这样做,因为它很复杂,而不是因为这样做会产生任何固有问题。他们甚至提供了示例代码,尽管他们的示例是子类化(FormMixin, DetailView),而不是ListView
      【解决方案3】:

      我也一直在寻找合适的解决方案。但我找不到任何东西,所以只好自己想出一个。

      views.py

      class VocationsListView(ListView):
      
          context_object_name = "vocations"
          template_name = "vocations/vocations.html"
          paginate_by = 10
      
          def get_queryset(self):
              get = self.request.GET.copy()
              if(len(get)):
                  get.pop('page')
              self.baseurl = urlencode(get)
              model = Vocation
              self.form = SearchForm(self.request.GET)
              filters = model.get_queryset(self.request.GET)
              if len(filters):
                  model = model.objects.filter(filters)
              else:
                  model = model.objects.all()
              return model
      
      
      
      def get_context_data(self):
          context = super(VocationsListView, self).get_context_data()
          context['form'] = self.form
          context['baseurl']= self.baseurl
          return context
      

      models.py

      class Vocation(models.Model):
          title = models.CharField(max_length = 255)
          intro = models.TextField()
          description = models.TextField(blank = True)
          date_created = models.DateTimeField(auto_now_add = True)
          date_modified = models.DateTimeField(auto_now = True)
          created_by = models.ForeignKey(User, related_name = "vocation_created")
          modified_by = models.ForeignKey(User, related_name = "vocation_modified")
      
          class Meta:
              db_table = "vocation"
      
          @property
          def slug(self):
              return defaultfilters.slugify(self.title)
      
          def __unicode__(self):
              return self.title
      
          @staticmethod
          def get_queryset(params):
      
              date_created = params.get('date_created')
              keyword = params.get('keyword')
              qset = Q(pk__gt = 0)
              if keyword:
                  qset &= Q(title__icontains = keyword)
              if date_created:
                  qset &= Q(date_created__gte = date_created)
              return qset
      

      所以基本上我将这段代码添加到我想要实现搜索功能的每个模型类中。这是因为必须明确准备每个模型的过滤器

      @staticmethod
      def get_queryset(params):
      
          date_created = params.get('date_created')
          keyword = params.get('keyword')
          qset = Q(pk__gt = 0)
          if keyword:
              qset &= Q(title__icontains = keyword)
          if date_created
              qset &= Q(date_created__gte = date_created)
          return qset
      

      它准备了我用来从模型中检索数据的 qset 过滤器

      【讨论】:

        【解决方案4】:

        根据以前的答案,这是我对用于在与 ListView 相同的页面上显示表单的视图的看法:

        class IndexView(FormMixin, ListView):
            ''' Homepage: displays list of links, and a form used to create them '''
            template_name = "links/index.html"
            context_object_name = "links"
            form_class = LinkForm
        
            def get_queryset(self):
                return Links.objects.all()
        
        def add_link(request):
            # Sole job of this function is to process the form when POSTed. 
            if request.method == "POST":
                form = LinkForm(request.POST)
        
                if form.is_valid():
                    Links.objects.create(address=form.cleaned_data['address'])
        
                return HttpResponseRedirect('/')
        

        然后,最后一件事是将 add_link 视图函数绑定到表单的操作 url,我认为你可以开始了。

        【讨论】:

          【解决方案5】:

          这些答案极大地帮助了我朝着正确的方向前进。谢谢各位。

          对于我的实现,我需要一个在获取和发布时都返回 ListView 的表单视图。 我不喜欢重复 get 函数的内容,但它需要一些更改。该表单现在也可以从 get_queryset 使用 self.form 获得。

          from django.http import Http404
          from django.utils.translation import ugettext as _
          from django.views.generic.edit import FormMixin
          from django.views.generic.list import ListView
          
          class FormListView(FormMixin, ListView):
              def get(self, request, *args, **kwargs):
                  # From ProcessFormMixin
                  form_class = self.get_form_class()
                  self.form = self.get_form(form_class)
          
                  # From BaseListView
                  self.object_list = self.get_queryset()
                  allow_empty = self.get_allow_empty()
                  if not allow_empty and len(self.object_list) == 0:
                      raise Http404(_(u"Empty list and '%(class_name)s.allow_empty' is False.")
                                    % {'class_name': self.__class__.__name__})
          
                  context = self.get_context_data(object_list=self.object_list, form=self.form)
                  return self.render_to_response(context)
          
              def post(self, request, *args, **kwargs):
                  return self.get(request, *args, **kwargs)
          
          
          class MyListView(FormListView):
              form_class = MySearchForm
              model = MyModel
              # ...
          

          【讨论】:

          • 完美!我不得不交换继承顺序(ListView,FormMixin)以保持分页工作。
          • 这很好,但我应该在模板中使用它来输出所有表单。我只看到一个表单实例,它是第一个元素,而 objects_list 是模型列表。
          • 好的,我设法在页面上获得了一个表格和一个列表,谢谢。但是我该如何处理搜索?我想必须在 MyListView 中覆盖 post(self, request, *args, **kwargs)。但是怎么做?从 get 复制代码并在那里进行搜索?有时候我的印象是 LisViews 最终让事情变得比写一个简单的视图函数更复杂。还是我错过了什么?
          猜你喜欢
          • 2013-10-22
          • 2011-11-08
          • 2018-03-12
          • 1970-01-01
          • 2015-07-26
          • 1970-01-01
          • 2017-04-06
          • 1970-01-01
          • 2012-10-23
          相关资源
          最近更新 更多