在 Django ListView 中接受输入

Posted

技术标签:

【中文标题】在 Django ListView 中接受输入【英文标题】:Accepting input in Django ListView 【发布时间】:2016-10-22 10:27:43 【问题描述】:

在一个 Django 网站中,我有一个分页的 ListView,它显示了某些对象的列表,每页 100 个。

我想在此页面上包含一个文本框并接受+处理用户输入。但在 Django 中,这将要求我:

i) 使用FormView(在这种情况下我会丢失分页),或者

ii) 编写基于函数的视图,我手动处理分页和表单处理。

是否有第三种方法可以实现我想要做的事情,理想情况下不会破坏ListView

【问题讨论】:

您为什么不使用一个简单的基于函数的视图来轻松处理您的列表和表单? @ettanany:是的,在 (ii) 中的非 cbvs,我的意思是基于函数的视图 我明白了。我认为您的情况与此类似ListView and CreateView in one template Django @ettanany:好吧。如果您编写一个基于函数的视图的说明性示例,该视图既可以分页又可以接受表单输入,我会接受它作为答案。 那么,对于文本框,您是否使用 Ajax 发送数据并获取处理后的数据?还是您通过页面刷新将其发送到 django? 【参考方案1】:

在我看来,每个视图都应该有一个目的。并不意味着您不能在一个页面中包含多个表单元素。你可以这样做

制作一个只处理数据的普通视图。您将设置视图的 url,然后对该视图进行 ajax 调用。如果您也愿意为此使用 javascript,这很容易实现。(简单的 xhr 方法、模糊、更改事件)

例如:-

class FormElementProcess(View):
    def post(self,request,*args,**kwargs):
        #Do your processing and return httpresponse

如果还使用了表单类,您可以进一步自定义上述类,也可以使用表单视图来处理和返回表单数据。

我猜这将是解决这个问题的方法。假设我的主页中有几十个表格。诸如 -> 搜索、登录、注册等形式。我不会通过我的 IndexView 处理所有事情。当应用程序规模变大时,这会使一切变得过于复杂。

2) 如果页面刷新,那么我建议你使用 FormMixin。 我找到了一个很好的实现 FormListView

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

Detailed Code Explanation

您将进一步修改 post 方法以进行处理。可以直接使用表单类,包含请求中的参数进行处理。

【讨论】:

【参考方案2】:

使用基于函数的视图来实现你想要的示例如下:

contacts/models.py:

from django.db import models
from django.utils.encoding import python_2_unicode_compatible


@python_2_unicode_compatible
class Contact(models.Model):
    email = models.EmailField(unique=True)
    first_name = models.CharField(max_length=40, blank=True)
    last_name = models.CharField(max_length=40, blank=True)
    created_at = models.DateTimeField(auto_now_add=True)
    updated_at = models.DateTimeField(auto_now=True)

    def __str__(self):
        return self.email

联系人/forms.py:

from django import forms


class UserForm(forms.Form):
    search = forms.CharField(label='Search', max_length=100)

contacts/views.py:

from django.core.paginator import Paginator, EmptyPage, PageNotAnInteger
from django.shortcuts import render, redirect
from .models import Contact
from .forms import UserForm


def my_contacts(request):
    form = UserForm()
    if request.method == 'POST':
        form = UserForm(request.POST)
        if form.is_valid():
            # Do something with form data here
            print(form.cleaned_data['search'])
        redirect('my_contacts')

    contacts_list = Contact.objects.all()
    page = request.GET.get('page', 1)

    paginator = Paginator(contacts_list, 10)
    try:
        contacts = paginator.page(page)
    except PageNotAnInteger:
        contacts = paginator.page(1)
    except EmptyPage:
        contacts = paginator.page(paginator.num_pages)

    return render(request, 'contacts/contacts.html', 'contacts': contacts, 'form': form)

联系人/urls.py:

from django.conf.urls import patterns, url

urlpatterns = patterns(
   'contacts.views',
    url(r'^$', 'my_contacts', name='my_contacts'),
)

模板/联系人/contacts.html:

% extends 'base.html' %

% block 'container' %
<div class="row">
  <div class="col-sm-12">
    <form action="" method="post">
      % csrf_token %
       form 
      <input type="submit" value="Submit" />
    </form>
  </div>
</div>
<div class="row">
<div class="col-sm-12">
<table class="table table-bordered">
  <thead>
    <tr>
      <th>Email</th>
      <th>First name</th>
      <th>Last name</th>
    </tr>
  </thead>
  <tbody>
    % for contact in contacts %
      <tr>
        <td> contact.email </td>
        <td> contact.first_name </td>
        <td> contact.last_name </td>
      </tr>
    % endfor %
  </tbody>
</table>

% if contacts.has_other_pages %
  <ul class="pagination">
    % if contacts.has_previous %
      <li><a href="?page= contacts.previous_page_number ">&laquo;</a></li>
    % else %
      <li class="disabled"><span>&laquo;</span></li>
    % endif %
    % for i in contacts.paginator.page_range %
      % if contacts.number == i %
        <li class="active"><span> i  <span class="sr-only">(current)</span></span></li>
      % else %
        <li><a href="?page= i "> i </a></li>
      % endif %
    % endfor %
    % if contacts.has_next %
      <li><a href="?page= contacts.next_page_number ">&raquo;</a></li>
    % else %
      <li class="disabled"><span>&raquo;</span></li>
    % endif %
  </ul>
% endif %
</div>
</div>
% endblock %

模板/base.html:

% load static %

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="utf-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <meta name="description" content="">
    <meta name="author" content="">
    <title>% block 'title'%% endblock %</title>
    <!-- Bootstrap Core CSS -->
    <link href=% static 'css/bootstrap.min.css' % rel="stylesheet">
</head>
<body>
    <!-- Page Content -->
    <div class="container" style="padding-top: 50px;">
        % block 'container' %% endblock %
    </div>
    <!-- /.container -->

    <script src="% static 'js/jquery.js' %"></script>
    <!-- Bootstrap Core JavaScript -->
    <script src="% static 'js/bootstrap.min.js' %"></script>
</body>
</html>

【讨论】:

以上是关于在 Django ListView 中接受输入的主要内容,如果未能解决你的问题,请参考以下文章

django:在同一页面中接受输入并显示输出

Django中的详细模板不接受值

Django:在 DataTables、ListView 中显示图像

如果这个 django 表单本身也生成选项,为啥它不接受我的输入?

在 Django 中接受垃圾 url 时重定向到登录页面

公共控件Listview