Django类视图CBV扩展基类之通用编辑视图FormView、CreateView、UpdateView、DeleteView

前言

这几年一直在it行业里摸爬滚打,一路走来,不少总结了一些python行业里的高频面试,看到大部分初入行的新鲜血液,还在为各样的面试题答案或收录有各种困难问题

于是乎,我自己开发了一款面试宝典,希望能帮到大家,也希望有更多的Python新人真正加入从事到这个行业里,让python火不只是停留在广告上。

微信小程序搜索:Python面试宝典

或可关注原创个人博客:https://lienze.tech

也可关注微信公众号,不定时发送各类有趣猎奇的技术文章:Python编程学习

通用编辑视图

FormView

这是用来处理表单的视图;出错时,显示出关于表单验证的错误;如果成功,则跳转到新的url

class FormMixin(ContextMixin):
    """Provide a way to show and handle a form in a request."""
    initial = {
    
    } # 初始化默认值
    form_class = None # 某个表单类
    success_url = None # 验证成功之后跳转的地址
    prefix = None # 控制在表单页面中的name值前缀,用以区分不同表单的name属性
  • FormView有一个非常重要的父类,用来控制分析表单
class ProcessFormView(View):
    """Render a form on GET and processes it on POST."""
    def get(self, request, *args, **kwargs):
        """Handle GET requests: instantiate a blank version of the form."""
        return self.render_to_response(self.get_context_data())

    def post(self, request, *args, **kwargs):
        """
        Handle POST requests: instantiate a form instance with the passed
        POST variables and then check if it's valid.
        """
        form = self.get_form()
        if form.is_valid():
            return self.form_valid(form)
        else:
            return self.form_invalid(form)
class FormMixin(ContextMixin):
  	def get_form_class(self):
        """Return the form class to use."""
        return self.form_class

    def get_form(self, form_class=None):
        """Return an instance of the form to be used in this view."""
        if form_class is None:
            form_class = self.get_form_class()
        return form_class(**self.get_form_kwargs())

在这个类中定义了主要的post请求,用来分析form表单是否是正确的输入,有关的self.form_validself.form_invalid函数定义如下,还是非常简单的,出错的话,会通过get_context_data将错误返回,成功的话将会通过get_success_url重定向

class FormMixin(ContextMixin):
    def form_invalid(self, form):
        """If the form is invalid, render the invalid form."""
        return self.render_to_response(self.get_context_data(form=form))
    def form_valid(self, form):
        """If the form is valid, redirect to the supplied URL."""
        return HttpResponseRedirect(self.get_success_url())
  • 来做一个简单的测试,使用FormView进行表单页面的提供以及数据的验证入库
#forms 
class UserForm(forms.Form):
    name = forms.CharField(max_length=30)
#views
class FormViewTest(FormView):
    model = User # 添加model全局属性,以供代码整洁良好复用
    template_name = 'test_form.html' # 因为FormView并没有自动提供模版后缀,需要我们手动指定
    form_class = UserForm # 表单页面渲染的表单类
    success_url = '/' # 表单验证成功之后的重定向地址
    prefix = 'a1' # 在表单页面的name属性值前缀,一般不要重复即可

    def post(self, request, *args, **kwargs): # 重写post方法,因为我们要数据入库
        form = self.get_form()
        if form.is_valid():
            name = form.cleaned_data['name']
            self.model._default_manager.create(name=name) # 验证之后的数据入库
            return self.form_valid(form)
        else:
            return self.form_invalid(form)
  • 需要配合的表单页面就更加简单了
<!-- test_form.html -->
<form action="" method="POST">
    {% csrf_token %}
    {
   
   { form }}
    <button type="submit">提交</button>
</form>
  • 注意:如果在继承类中使用success_url属性,进行反向解析路由命名,要使用reverse_lazy而非reverse,因为success_url属性为类属性,而Django的urlconf加载在所有类加载之后,而reverse_lazy可以让success_url的加载在路由被访问时。

CreateView

快速创建某个模型数据

因为继承父类太多了,简单一些,直接列举了他一些设置属性

class CreateView(SingleObjectTemplateResponseMixin, BaseCreateView):
    """
    View for creating a new object, with a response rendered by a template.
    """
    template_name_suffix = '_form'
    # 这个视图默认的表单页地址是:appname/modelname_from.html
    #---ModelFormMixin---
    fields = [] # 模型类中需要表单提供的字段值
    #---FormMixin---
    initial = {
    
    } # 初始化默认值
    form_class = None # 某个表单类
    success_url = None # 验证成功之后跳转的地址
    prefix = None # 控制在表单页面中的name值前缀,用以区分不同表单的name属性
    #---SingleObjectMixin---
    model = None # 需要表单创建的模型类
  • 在ModelFormMixin这个类中重写了form_valid函数,不光进行了数据校验,还进行了数据入库
class ModelFormMixin(FormMixin, SingleObjectMixin):
    def form_valid(self, form):
    	"""If the form is valid, save the associated model."""
        self.object = form.save()
    	return super().form_valid(form)

在ModelFormMixin类中还使用了modelform_factory函数,这是为什么我们不需要在这个视图类中进行表单类的定义

可以单独使用 modelform_factory() 函数来直接从 Model 创建表单。在不需要很多自定义的情况下是更方便的,比如

UserForm = modelform_factory(User, fields=("name",))
  • 列举一个使用示例
class CreateTest(CreateView):
    model = Info
    fields = ['user','info']
    success_url = '/' # 数据创建成功之后的跳转地址
<form action="" method="post">
    {% csrf_token %}
    {
   
   { form }}
    <button type="submit">提交</button>
</form>

字段中的多对一,多对多关系会自动成为下拉菜单或复选框的样式供你使用,非常的简单!


UpdateView

更新某个数据的视图类,更新通过链接传递的pk值,或者对应的字段过滤条件,参见DetailView

class UpdateView(SingleObjectTemplateResponseMixin, BaseUpdateView):
    """View for updating an object, with a response rendered by a template."""
    template_name_suffix = '_form'
   	# 默认的表单页面后缀,appname/modelname_form.html
    #---FormMixin---
    initial = {
    
    } # 初始化默认值
    form_class = None # 某个表单类
    success_url = None # 验证成功之后跳转的地址
    prefix = None # 控制在表单页面中的name值前缀,用以区分不同表单的name属性
    #---SingleObjectMixin---
    model = None # 数据模型,将在视图页面展示数据
    queryset = None # queryset如果提供,则值queryset取代设置model的值
    slug_field = 'slug' # 过滤的字段
    context_object_name = None
    slug_url_kwarg = 'slug' # 过滤条件,通过链接参数给定;如 a.com/<str:slug>/
    pk_url_kwarg = 'pk' # 启用主键作为链接参数过滤条件
    query_pk_and_slug = False # 当依赖主键查询不为空时,设置该值为True,可以继续过滤字段,就是又过滤pk还过滤field

使用UpdateView,首先要通过路由传递对应的pk或者指明的slug_url_kwarg字段确定要更新的数据是哪个,然后进行更新,更新完毕会跳转到由success_url定义的路由之中。

  • 看个demo,比如我想更新张三
class UpdateTest(UpdateView):
    model = Info
    fields = ['id','info','user']
    success_url = '/'
    slug_field = 'user__name' 
    # 外键关联关系可以通过链式查询给定
    slug_url_kwarg = 'user_name'
    # 在链接中的给定传递给user__name的形参名
path('update/<str:user_name>/',UpdateTest.as_view())
# 对应上方的user_name

DeleteView

删除self.get_object()获取到的数据对象

class DeleteView(SingleObjectTemplateResponseMixin, BaseDeleteView):
    """
    View for deleting an object retrieved with self.get_object(), with a
    response rendered by a template.
    """
    template_name_suffix = '_confirm_delete'
    # 默认模版的路径是appname/modelname_confirm_delete.html
    #---SingleObjectMixin---
    model = None # 数据模型,将在视图页面展示数据
    queryset = None # queryset如果提供,则值queryset取代设置model的值
    slug_field = 'slug' # 过滤的字段
    context_object_name = None
    slug_url_kwarg = 'slug' # 过滤条件,通过链接参数给定;如 a.com/<str:slug>/
    pk_url_kwarg = 'pk' # 启用主键作为链接参数过滤条件
    query_pk_and_slug = False # 当依赖主键查询不为空时,设置该值为True,可以继续过滤字段,就是又过滤pk还过滤field
  • get方式访问时,会先返回符合匹配条件的数据对象,默认的模版上下文名为object

  • post、delete方式访问时,会将所匹配的数据对象删除

class DeleteTest(DeleteView):
    model = Info
    slug_url_kwarg = 'user_name'
    slug_field = 'user__name' # user为外键,根据外键的链式查询进行筛选
    success_url = '/'
    context_object_name = 'info' # 当get访问时,模版页面渲染时的上下文变量名
path('delete/<str:user_name>/',DeleteTest.as_view()),

猜你喜欢

转载自blog.csdn.net/HeroicLee/article/details/121508086