day 77 基于form组件的注册功能
Form 表单 py文件
from django import forms #定义一个form类注册用 class RegForm (forms.Form): username =forms.CharField( max_length=16, label='用户名', error_messages={ " max_length":"用户名长度最长为16位", 'required':'用户名不能为空', }, widget=forms.widgets.TextInput( attrs={'class': 'form-control'}, ) ) password =forms.CharField( min_length=6, label='密码', widget=forms.widgets.PasswordInput( attrs={"class": "form-control"}, render_value=True, ), error_messages = { "min_length": "密码至少要6位!", "required": "密码不能为空", } ) re_password= forms.CharField( min_length=6, label='密码', widget=forms.widgets.PasswordInput( attrs={ 'class': 'form-control'}, render_value=True, ), error_messages= { 'min_length':'密码至少要6位', 'required':'密码不能为空', } ) email =forms.EmailField( label='邮箱', widget=forms.widgets.EmailInput( attrs={'class':'form-control'}, ), error_messages= { 'invalid': '邮箱格式不正确!', 'required':'邮箱不能为空', } )
settings文件
""" Django settings for day77 project. Generated by 'django-admin startproject' using Django 1.11.12. For more information on this file, see https://docs.djangoproject.com/en/1.11/topics/settings/ For the full list of settings and their values, see https://docs.djangoproject.com/en/1.11/ref/settings/ """ import os # Build paths inside the project like this: os.path.join(BASE_DIR, ...) BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) # Quick-start development settings - unsuitable for production # See https://docs.djangoproject.com/en/1.11/howto/deployment/checklist/ # SECURITY WARNING: keep the secret key used in production secret! SECRET_KEY = '@qbulznqai1k%twz$(m)76#ztkt6%^+k2airzl5-pt@lu2v)oz' # SECURITY WARNING: don't run with debug turned on in production! DEBUG = True ALLOWED_HOSTS = [] # Application definition INSTALLED_APPS = [ 'django.contrib.admin', 'django.contrib.auth', 'django.contrib.contenttypes', 'django.contrib.sessions', 'django.contrib.messages', 'django.contrib.staticfiles', 'app01.apps.App01Config', ] MIDDLEWARE = [ 'django.middleware.security.SecurityMiddleware', 'django.contrib.sessions.middleware.SessionMiddleware', 'django.middleware.common.CommonMiddleware', 'django.middleware.csrf.CsrfViewMiddleware', 'django.contrib.auth.middleware.AuthenticationMiddleware', 'django.contrib.messages.middleware.MessageMiddleware', 'django.middleware.clickjacking.XFrameOptionsMiddleware', ] ROOT_URLCONF = 'day77.urls' TEMPLATES = [ { 'BACKEND': 'django.template.backends.django.DjangoTemplates', 'DIRS': [os.path.join(BASE_DIR, 'templates')] , 'APP_DIRS': True, 'OPTIONS': { 'context_processors': [ 'django.template.context_processors.debug', 'django.template.context_processors.request', 'django.contrib.auth.context_processors.auth', 'django.contrib.messages.context_processors.messages', ], }, }, ] WSGI_APPLICATION = 'day77.wsgi.application' # Database # https://docs.djangoproject.com/en/1.11/ref/settings/#databases DATABASES = { # 'default': { # 'ENGINE': 'django.db.backends.sqlite3', # 'NAME': os.path.join(BASE_DIR, 'db.sqlite3'), # }, 'default':{ 'ENGINE':'django.db.backends.mysql', 'NAME':'day77', 'USER':'root', 'PASSWORD':'123456', 'HOST':'127.0.0.1', 'PORT':3306, } } # Password validation # https://docs.djangoproject.com/en/1.11/ref/settings/#auth-password-validators AUTH_PASSWORD_VALIDATORS = [ { 'NAME': 'django.contrib.auth.password_validation.UserAttributeSimilarityValidator', }, { 'NAME': 'django.contrib.auth.password_validation.MinimumLengthValidator', }, { 'NAME': 'django.contrib.auth.password_validation.CommonPasswordValidator', }, { 'NAME': 'django.contrib.auth.password_validation.NumericPasswordValidator', }, ] # Internationalization # https://docs.djangoproject.com/en/1.11/topics/i18n/ LANGUAGE_CODE = 'en-us' TIME_ZONE = 'UTC' USE_I18N = True USE_L10N = True USE_TZ = True # Static files (CSS, JavaScript, Images) # https://docs.djangoproject.com/en/1.11/howto/static-files/ STATIC_URL = '/static/' STATICFILES_DIRS=[ os.path.join(BASE_DIR,'static') ] # 告诉Djanog 项目用哪张表做认证 AUTH_USER_MODEL='app01.UserInfo'
modules文件
from django.db import models # Create your models here. from django.contrib.auth.models import AbstractUser class UserInfo(AbstractUser): ''' 用户表 ''' nid =models.AutoField(primary_key=True) phone =models.CharField(max_length=11,null=True,unique=True) avatar = models.FileField(upload_to='avatars/',default='avatars/default.png',verbose_name='头像') create_time =models.DateTimeField(auto_now_add=True) blog =models.OneToOneField(to='Blog',to_field='nid',null=True) def __str__(self): return self.username class Blog(models.Model): ''' 博客信息 ''' nid =models.AutoField(primary_key=True) title =models.CharField(max_length=64) site =models.CharField(max_length=32,unique=True) theme =models.CharField(max_length=32) def __str__(self): return self.title # class Category(models.Model): ''' 个人博客文章分类 ''' nid =models.AutoField(primary_key=True) title =models.CharField(max_length=32)#分类标题 blog = models.ForeignKey(to ='Blog',to_field='nid')#外键关联博客,一个博客站点可以有多个分类 def __str__(self): return self.title class Tag(models.Model): '''' 标签 ''' nid =models.AutoField(primary_key=True) title =models.CharField(max_length=32) blog =models.ForeignKey(to='Blog',to_field='nid') #所属博客 def __str__(self): return self.title class Article(models.Model): ''' 文章 ''' nid =models.AutoField(primary_key=True) title = models.CharField(max_length=50) #文章标题描述 desc =models.CharField(max_length=255) #文章描述 create_time =models.DateTimeField()#创建时间 category = models.ForeignKey(to ='Category',to_field='nid',null=True) user = models.ForeignKey(to='UserInfo',to_field='nid') tags =models.ManyToManyField( # 中介模型 to ='Tag', through='Article2Tag', through_fields=('article','tag')#注意顺序 ) def __str__(self): return self.title class ArticleDetail(models.Model): ''' 文章详情 ''' nid =models.AutoField(primary_key=True) content = models.TextField() article =models.OneToOneField(to ='Article',to_field='nid') class Article2Tag(models.Model): ''' 文章和标签的多对多关系表 ''' nid =models.AutoField(primary_key=True) article =models.ForeignKey(to='Article',to_field='nid') tag =models.ForeignKey(to ='Tag',to_field='nid') class Meta: unique_together = (('article','tag'),) class ArticleUpDown(models.Model): ''' 点赞 ''' nid= models.AutoField(primary_key=True) user =models.ForeignKey(to ='UserInfo',null=True) article = models.BooleanField(default=True) class Meta: unique_together = (('article','user'),) class Comment(models.Model): ''' 评论表 ''' nid = models.AutoField(primary_key=True) article =models.ForeignKey(to ='Article',to_field='nid') user =models.ForeignKey(to ='UserInfo',to_field='nid') content =models.CharField(max_length=255)#评论内容 create_time =models.DateTimeField(auto_now_add=True) parent_comment =models.ForeignKey('self',null=True) def __str__(self): return self.content
views文件
from app01 import form,models from django.db import models def reg(request): if request.method=='POST': ret={'status':0,'msg':''} form_obj =form.RegForm(request.POST) #帮我做校验 if form_obj.is_valid(): #校验通过,去数据库创建一个新的用户 form_obj.cleaned_data.pop('re_password') avatar_img =request.FILES.get('avatar') models.UserInfo.objects.create_user(**form_obj.cleaned_data,avatar =avatar_img) ret['msg']= '/index/' return JsonResponse(ret)
以上代码代表注册成功的情况
以下代码是注册失败的代码 else: print(form_obj.errors) ret['status']=1 ret['msg']= form_obj.errors
print(ret) return JsonResponse(form_obj.errors) # return render(request,'ret.html',{'form_obj': form_obj})
#生成一个form对象
form_obj = form.RegForm()
print(form_obj)
print("== "*120)
return render(request,'reg.html',{'form_obj': form_obj})
输入 web地址
前端代码
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>欢迎注册</title>
<link rel="stylesheet" href="/static/bootstrap/css/bootstrap.min.css">
<link rel="stylesheet" href="/static/mystyle.css">
</head>
<body>
<div class="container">
<div class="row">
<div class="col-md-6 col-md-offset-3">
<form novalidate autocomplete="off" action="/reg/" method="post" class="form-horizontal reg-form" enctype="multipart/form-data">
{% csrf_token %}
<div class="form-group">
<label for="{{ form_obj.username.id_for_label }}"
class="col-sm-2 control-label">{{ form_obj.username.label }}</label>
<div class="col-sm-8">
{{ form_obj.username }}
<span class="help-block">{{ form_obj.username.errors.0 }}</span>
</div>
</div>
<div class="form-group">
<label for="{{ form_obj.password.id_for_label }}"
class="col-sm-2 control-label">{{ form_obj.password.label }}</label>
<div class="col-sm-8">
{{ form_obj.password }}
<span class="help-block">{{ form_obj.password.errors.0 }}</span>
</div>
</div>
<div class="form-group">
<label for="{{ form_obj.re_password.id_for_label }}"
class="col-sm-2 control-label">{{ form_obj.re_password.label }}</label>
<div class="col-sm-8">
{{ form_obj.re_password }}
<span class="help-block">{{ form_obj.re_password.errors.0 }}</span>
</div>
</div>
<div class="form-group">
<label for="{{ form_obj.email.id_for_label }}"
class="col-sm-2 control-label">{{ form_obj.email.label }}</label>
<div class="col-sm-8">
{{ form_obj.email }}
<span class="help-block">{{ form_obj.email.errors.0 }}</span>
</div>
</div>
<div class="form-group">
<label
class="col-sm-2 control-label">头像</label>
<div class="col-sm-8">
<label for="id_avatar"><img id="avatar-img" src="/static/img/default.png" alt=""></label>
<input accept="image/*" type="file" name="avatar" id="id_avatar" style="display: none">
<span class="help-block"></span>
</div>
</div>
<div class="form-group">
<div class="col-sm-offset-2 col-sm-10">
<button type="button" class="btn btn-success" id="reg-submit">注册</button>
</div>
</div>
</form>
</div>
</div>
</div>
<script src="/static/jquery-3.3.1.js"></script>
<script src="/static/bootstrap/js/bootstrap.min.js"></script>
<script>
// 找到头像的input标签绑定change事件
$("#id_avatar").change(function () {
// 1. 创建一个读取文件的对象
var fileReader = new FileReader();
// 取到当前选中的头像文件
// console.log(this.files[0]);
// 读取你选中的那个文件
fileReader.readAsDataURL(this.files[0]); // 读取文件是需要时间的
fileReader.onload = function () {
// 2. 等上一步读完文件之后才 把图片加载到img标签中
$("#avatar-img").attr("src", fileReader.result);
};
});
// AJAX提交注册的数据
$("#reg-submit").click(function () {
// 取到用户填写的注册数据,向后端发送AJAX请求
var formData = new FormData();
formData.append("username", $("#id_username").val());
formData.append("password", $("#id_password").val());
formData.append("re_password", $("#id_re_password").val());
formData.append("email", $("#id_email").val());
formData.append("avatar", $("#id_avatar")[0].files[0]);
formData.append("csrfmiddlewaretoken", $("[name='csrfmiddlewaretoken']").val());
$.ajax({
url: "/reg/",
type: "post",
processData: false, // 告诉jQuery不要处理我的数据
contentType: false, // 告诉jQuery不要设置content类型
data: formData,
success:function (data) {
if (data.status){
// 有错误就展示错误
// console.log(data.msg);
// 将报错信息填写到页面上
$.each(data.msg, function (k,v) {
// console.log("id_"+k, v[0]);
// console.log($("#id_"+k));
$("#id_"+k).next("span").text(v[0]).parent().parent().addClass("has-error");
})
}else {
// 没有错误就跳转到指定页面
location.href = data.msg;
}
}
})
});
// 将所有的input框绑定获取焦点的事件,将所有的错误信息清空
$("form input").focus(function () {
$(this).next().text("").parent().parent().removeClass("has-error");
});
// 给username input框绑定一个失去焦点的事件,失去焦点之后就校验用户名是否已被注册
{#$("#id_username").blur(function () {#}
$("#id_username").on("input", function () {
// 取到用户填写的值
var username = $(this).val();
// 发请求
$.ajax({
url: "/check_username_exist/",
type: "get",
data: {"username": username},
success: function (data) {
if (data.status){
// 用户名已被注册
$("#id_username").next().text(data.msg).parent().parent().addClass("has-error");
}
}
})
})
</script>
</body>
</html>
密码输入错误的案例
打印结果
传到前端的 代码
登录 views
def logout(request): auth.logout(request) return redirect('/index/') def login(request): # if request.is_ajax(): # 如果是AJAX请求 if request.method == "POST": # 初始化一个给AJAX返回的数据 ret = {"status": 0, "msg": ""} # 从提交过来的数据中 取到用户名和密码 username = request.POST.get("username") pwd = request.POST.get("password") # 获取极验 滑动验证码相关的参数 gt = GeetestLib(pc_geetest_id, pc_geetest_key) challenge = request.POST.get(gt.FN_CHALLENGE, '') validate = request.POST.get(gt.FN_VALIDATE, '') seccode = request.POST.get(gt.FN_SECCODE, '') status = request.session[gt.GT_STATUS_SESSION_KEY] user_id = request.session["user_id"] if status: result = gt.success_validate(challenge, validate, seccode, user_id) else: result = gt.failback_validate(challenge, validate, seccode) if result: # 验证码正确 # 利用auth模块做用户名和密码的校验 user = auth.authenticate(username=username, password=pwd) if user: # 用户名密码正确 # 给用户做登录 auth.login(request, user) # 将登录用户赋值给 request.user ret["msg"] = "/index/" else: # 用户名密码错误 ret["status"] = 1 ret["msg"] = "用户名或密码错误!" else: ret["status"] = 1 ret["msg"] = "验证码错误" return JsonResponse(ret) return render(request, "login.html")
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>index</title> <link rel="stylesheet" href="/static/bootstrap/css/bootstrap.min.css"> <link rel="stylesheet" href="/static/mystyle.css"> </head> <body> <nav class="navbar navbar-inverse"> <div class="container-fluid"> <!-- Brand and toggle get grouped for better mobile display --> <div class="navbar-header"> <button type="button" class="navbar-toggle collapsed" data-toggle="collapse" data-target="#bs-example-navbar-collapse-1" aria-expanded="false"> <span class="sr-only">Toggle navigation</span> <span class="icon-bar"></span> <span class="icon-bar"></span> <span class="icon-bar"></span> </button> <a class="navbar-brand" href="#">The Blog</a> </div> <!-- Collect the nav links, forms, and other content for toggling --> <div class="collapse navbar-collapse" id="bs-example-navbar-collapse-1"> <ul class="nav navbar-nav"> <li class="active"><a href="#">Link <span class="sr-only">(current)</span></a></li> <li><a href="#">Link</a></li> </ul> <ul class="nav navbar-nav navbar-right"> {% if request.user.username %} <li><a href="#">{{ request.user.username }}</a></li> <li class="dropdown"> <a href="#" class="dropdown-toggle" data-toggle="dropdown" role="button" aria-haspopup="true" aria-expanded="false">个人中心<span class="caret"></span></a> <ul class="dropdown-menu"> <li><a href="#">Action</a></li> <li><a href="#">Another action</a></li> <li><a href="#">Something else here</a></li> <li role="separator" class="divider"></li> <li><a href="/logout/">注销</a></li> </ul> </li> {% else %} <li><a href="/login/">登录</a></li> <li><a href="/reg/">注册</a></li> {% endif %} </ul> </div><!-- /.navbar-collapse --> </div><!-- /.container-fluid --> </nav> <!-- 主页面 开始--> <div class="container"> <div class="row"> <div class="col-md-2"> <div class="panel panel-primary"> <div class="panel-heading">左侧广告位一</div> <div class="panel-body"> Panel content </div> </div> <div class="panel panel-info"> <div class="panel-heading">左侧广告位二</div> <div class="panel-body"> Panel content </div> </div> </div> <div class="col-md-8"> <!-- 文章列表 开始 --> <div class="article-list"> {% for article in article_list %} <div class="article"> <h3><a href="">{{ article.title }}</a></h3> <div class="media"> <div class="media-left"> <a href="#"> <img class="media-object author-img" src="/media/{{ article.user.avatar }}" alt="..."> </a> </div> <div class="media-body"> <p>{{ article.desc }}</p> </div> </div> <div class="article-footer"> <span><a href="">{{ article.user.username }}</a></span>发布于 <span>{{ article.create_time|date:'Y-m-d H:i:s' }}</span> <span class="glyphicon glyphicon-comment">评论({{ article.comment_count }})</span> <span class="glyphicon glyphicon-thumbs-up">点赞({{ article.up_count }})</span> </div> </div> {% endfor %} </div> <!-- 文章列表 结束--> </div> <div class="col-md-2"> <div class="panel panel-primary"> <div class="panel-heading">右侧广告位一</div> <div class="panel-body"> Panel content </div> </div> <div class="panel panel-info"> <div class="panel-heading">右侧广告位二</div> <div class="panel-body"> Panel content </div> </div> </div> </div> </div> <!-- 主页面 结束--> <script src="/static/jquery-3.3.1.js"></script> <script src="/static/bootstrap/js/bootstrap.min.js"></script> </body> </html>
基于object查询 于基于queryset查询.