blog开发之注册功能
注册功能
先看代码:
modelform:
from django import forms from django.core.exceptions import ValidationError from blog import models class UserModelForm(forms.ModelForm): confirm_password = forms.CharField(label='确认密码') class Meta: model = models.UserInfo fields = ['username', 'password', 'confirm_password','email'] def __init__(self, *args, **kwargs): super(UserModelForm, self).__init__(*args, **kwargs) for name, field in self.fields.items(): field.widget.attrs = {'class':'form-control'} def clean_username(self): val = self.cleaned_data.get('username') obj = models.UserInfo.objects.filter(username=val).first() if not obj: return val raise ValidationError('用户名已经存在!') def clean_email(self): val = self.cleaned_data.get('email') if not val: raise ValidationError('邮箱不能为空!') return val def clean(self): pwd = self.cleaned_data.get('password') re_pwd = self.cleaned_data.get('confirm_password') if re_pwd and pwd: if re_pwd != pwd: raise ValidationError('两次密码输入不一致!') return self.cleaned_data return self.cleaned_data
1.通过重写init方法,给每一个字段加上统一的字段。
2.局部钩子需要返回原数据,全局钩子记得返回cleaned_data。
视图函数:
def register(request): if request.method == 'GET': form = UserModelForm() return render(request, 'blog/register.html', {'form': form}) form = UserModelForm(data=request.POST) if form.is_valid(): clean_data = form.cleaned_data clean_data.pop('confirm_password') avatar = request.FILES.get('avatarimg') if avatar: clean_data['avatar'] = avatar models.UserInfo.objects.create_user(**clean_data) return redirect(reverse('blog:login')) all_error = form.errors.get('__all__') if all_error: all_error = form.errors.get('__all__') return render(request, 'blog/register.html', {'form': form, 'all_error': all_error})
注意:
1.cleaned_data里面存的是你定义的modelform的字段,把不需要的字段confirm_password弹出后,创建用户的时候直接就可以**clean_data了。
2.全局错误,需要在视图函数中先判断,获取到后再返回给页面。
注册页面:
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> <link rel="stylesheet" href="/static/blog/bs/css/bootstrap.css"> <style> #avatar_img { margin-left: 20px; } #avatar { display: none; } </style> </head> <body> <h3>注册页面</h3> <div class="container"> <div class="row"> <div class="col-md-6 col-md-offset-3"> <form method="post" enctype="multipart/form-data"> {% csrf_token %} {% for item in form %} <div class="form-group"> <label for="{{ item.auto_id }}">{{ item.label }}</label> {{ item }} {{ item.errors.0 }} </div> {% endfor %} <div class="form-group"> <label for="avatar"> 头像 <img src="/static/blog/img/default.png" width="56" height="56" alt="" id="avatar_img"> </label> <input type="file" id="avatar" name="avatarimg"> </div> <input type="submit" class="btn btn-success" value="提交" id="register_btn">{% if all_error %} <span class="error">{{ all_error.0 }}</span> {% endif %} </form> </div> </div> </div> <script src="/static/jquery-3.3.1.js"></script> <script> $("#avatar").change(function () { let file_obj = $(this)[0].files[0]; let reader = new FileReader(); reader.readAsDataURL(file_obj); // 异步操作,不会等待文件读取完毕,直接下一步 reader.onload = function () { $("#avatar_img").attr("src", reader.result) }; }); $('.error').text('{{ all_error.0 }}').css({"color": "red", "margin": "10px"}); setTimeout(function () { $('.error').text('') }, 1500); </script> </body> </html>
注意:
1.局部错误(每一个字段的错误),用{{ item.errors.0 }} 来显示。全局错误,通过{{ all_error.0 }} 来获取。
2.头像动态展示:通过一个FileReader()对象来读取图片,为了正确显示,使用onload来等待图片加载完毕后,再修改src属性来显示图片。