Django学习22-基于类的视图2

使用基于类的通用视图处理表单

表单处理程序大致上分为3种:

  • 初始化的GET请求,显示空值或预设值;
  • 使用了无效的数据进行POST提交,重新显示表单并报错;
  • 正确地进行POST提交,会重定向到其他网页;

可以观察一个简单的联系表:

from django import forms

class ContactForm(forms.Form):
    name = forms.CharField()
    message = forms.CharField(widget=forms.Textarea)

    def send_email(self):
        # send email using the self.cleaned_data dictionary
        pass

可以使用FormView来构成它的视图函数,:

from myapp.forms import ContactForm
from django.views.generic.edit import FormView

class ContactView(FormView):
    template_name = 'contact.html'
    form_class = ContactForm
    success_url = '/thanks/'

    def form_valid(self, form):
        # This method is called when valid form data has been POSTed.
        # It should return an HttpResponse.
        form.send_email()
        return super().form_valid(form)

FormViewTemplateResponseMixin继承了template_name来指定渲染使用的模板,form_valid会重定向success_url所指定的地址。

处理模型表单Model forms

在处理模型时,使用通用视图会很方便。通用视图会自动创建ModelForm,只要在模型类中:

  • 如果指定了model属性,就会使用该模型类;
  • 如果使用 get_object()返回一个对象,就会使用该对象的类;
  • 如果给出了queryset,就会使用该查询集;

模型表单视图提供了一个form_valid()实现,可以自动保存模型。 如果您有任何特殊要求,可以覆盖它; 见下面的例子。您甚至不需要为CreateViewUpdateView提供success_url,它们将在模型对象上使用get_absolute_url()。如果要使用自定义ModelForm(例如添加额外验证),只需在视图上设置form_class即可。
首先为UserProfile添加get_absolute_url方法,告诉Django如何计算对象的规范URL的方法:

class UserProfile(models.Model):
    """为已经使用了内置User模型的项目来拓展用户模型 """
    # user对象可使用 user.userprofile, 或 user.proflie 得到用户信息
    user = models.OneToOneField(User, on_delete=models.CASCADE, related_name='profile')
    location = models.CharField('地址', max_length=64, blank=True)
    tel = models.CharField('联系方式', max_length=50, blank=True)
    about_me = models.TextField('关于我')
    mod_date = models.DateTimeField('上次修改日期', auto_now=True)
    avatar = models.ImageField('用户头像', upload_to='avatar/%Y/%m/%d',
                               default='avatar/wenhuang.jpg', blank=True, null=True)

    class Meta:
        verbose_name = "用户信息"
        app_label = 'users'

    def __str__(self):
        return f"{self.user.__str__()} profile"

    def get_absolute_url(self):

        return reverse('users:profile', args=(self.user.id,))

在views中导入UpdateView来构建编辑用户信息时使用的表单:

from django.views.generic.edit import CreateView, DeleteView, UpdateView


@method_decorator(login_required, name='dispatch')
class ProfileUpdate(UpdateView):
    model = UserProfile
    template_name = "edit_profile.html"
    # form_class = UserProfileForm
    fields = ['location', 'tel', 'about_me', 'avatar']

其中:

  • model指定使用的Model类;
  • template_name指定渲染的模板;
  • fields指定表单显示的字段;

可以看到无需编写逻辑,只需要配置基于类的视图即可。
如过需要使用自定义的ModelForm,可以使用form_class来指定,在Meta类中使用fields来指定要显示的字段

扫描二维码关注公众号,回复: 4356241 查看本文章
class UserProfileForm(ModelForm):

    class Meta:
        model = UserProfile
        fields = ('location', 'tel', 'about_me', 'avatar')
        widgets = {
            'about_me': Textarea(attrs={'cols': 80}),
        }

但他和fields同时存在时,就会抛出ImproperlyConfigured错误。
最后,在URLconf中需要使用<int:pk>的形式指定具体的对象:

urlpatterns = [
    # path('edit_profile/<profile_id>', edit_profile, name='edit_profile'),
    path('edit_profile/<int:pk>', ProfileUpdate.as_view(), name='edit_profile'),
]

CreateViewDeleteView的使用可以参考 Form handling with class-based

Model和request.user

例如,要使用CreateView跟踪创建对象的用户,可以使用自定义ModelForm执行此操作。 首先,将外键关系添加到模型中:

from django.contrib.auth.models import User
from django.db import models

class Author(models.Model):
    name = models.CharField(max_length=200)
    created_by = models.ForeignKey(User, on_delete=models.CASCADE)

    # ...

在视图中,确保不要将created_by添加到fields字段中,需要重写form_valid()来添加user:

from django.views.generic.edit import CreateView
from myapp.models import Author

class AuthorCreate(CreateView):
    model = Author
    fields = ['name']

    def form_valid(self, form):
        form.instance.created_by = self.request.user
        return super().form_valid(form)

CBV 模式下的用户验证和权限

一般基于函数的视图要进行用户验证直接使用 @login_required 装饰器,而基于类的视图
除了像上文提到的使用@method_decorator(login_required, name='dispatch')装饰器方法来进行用户验证,还可以继承LoginRequiredMixin来实现:

from django.contrib.auth.mixins import LoginRequiredMixin

class MyView(LoginRequiredMixin, View):
    login_url = '/login/'
    redirect_field_name = 'redirect_to'

与@login_required装饰器类似的,如果没有设置login_url,默认会重定向到settings.LOGIN_URL,未经身份验证的用户的所有请求都将重定向到登录页面或显示HTTP 403 Forbidden错误,具体取决于raise_exception参数-True:抛出PermissionDenied错误;False(默认):会重定向到登录页面。

而要对登录的用户进行测试时,使用UserPassesTestMixin类,需要重写test_func(),同时可以设置AccessMixin任意值来定制如何处理验证未通过的用户:

from django.contrib.auth.mixins import UserPassesTestMixin

class MyView(UserPassesTestMixin, View):

    def test_func(self):
        return self.request.user.email.endswith('@example.com')

要进行权限验证时,要多重继承PermissionRequiredMixin

from django.contrib.auth.mixins import PermissionRequiredMixin

class MyView(PermissionRequiredMixin, View):
    permission_required = 'polls.can_vote'
    # Or multiple of permissions:
    permission_required = ('polls.can_open', 'polls.can_edit')

就像使用@permission_required装饰器一样,使用permission_required字段指定特定的权限。同样的这个类也是继承自AccessMixin的,所以可以设置它的任何属性。

CBV模式下添加消息

FBV模式下使用消息:

from django.contrib import messages
	def confirm(request, token):
		# ...
        no_user_message = _('no this user please register')
        messages.add_message(request, DANGER, no_user_message)

在CBV模式下,需要继承SuccessMessageMixin类, 源码:

from django.contrib import messages


class SuccessMessageMixin:
    """
    Add a success message on successful form submission.
    """
    success_message = ''

    def form_valid(self, form):
        response = super().form_valid(form)
        success_message = self.get_success_message(form.cleaned_data)
        if success_message:
            messages.success(self.request, success_message)
        return response

    def get_success_message(self, cleaned_data):
        return self.success_message % cleaned_data

cleaning_data是表单中用于字符串格式化的已清理数据,
使用时

from django.contrib.messages.views import SuccessMessageMixin
from django.views.generic.edit import CreateView
from myapp.models import Author

class AuthorCreate(SuccessMessageMixin, CreateView):
    model = Author
    success_url = '/success/'
    success_message = "%(name)s was created successfully"

猜你喜欢

转载自blog.csdn.net/qq_19268039/article/details/84304933