1 创建子应用
cd ~/projects/meiduo_project/meiduo_mall/meiduo_mall/apps
python ../../manage.py startapp users
2 添加导包路径
BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
sys.path.append(BASE_DIR + '/apps')
print(sys.path)
3 注册应用
INSTALLED_APPS = [
'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
'users'
]
4 路由配置
url(r'^', include('users.urls', namespace='users'))
url(r'^register/$', views.RegisterView.as_view(), name='register')
5 返回页面接口
class RegisterView(View):
"""注册"""
def get(self, request):
return render(request, 'register.html')
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en">
<head>
<meta http-equiv="Content-Type" content="text/html;charset=UTF-8">
<title>美多商城-注册title>
<link rel="stylesheet" type="text/css" href="/static/css/reset.css">
<link rel="stylesheet" type="text/css" href="/static/css/main.css">
<script type="text/javascript" src="/static/js/host.js">script>
<script type="text/javascript" src="/static/js/axios-0.18.0.min.js">script>
<script type="text/javascript" src="/static/js/jquery-1.12.4.min.js">script>
<script type="text/javascript" src="/static/js/vue-2.5.16.js">script>
head>
<body>
<div class="register_con">
<div class="l_con fl">
<a href="index.html" class="reg_logo"><img src="images/logo.png">a>
<div class="reg_slogan">商品美 · 种类多 · 欢迎光临div>
<div class="reg_banner">div>
div>
<div class="r_con fr">
<div class="reg_title clearfix">
<h1>用户注册h1>
<a href="login.html">登录a>
div>
<div class="reg_form clearfix" id="app">
<form method="post" class="register_form">
<ul>
<li>
<label>用户名:label>
<input type="text" name="user_name" id="user_name" v-model="username" @blur="check_username">
<span class="error_tip">[[ error_name_message ]]span>
li>
<li>
<label>密码:label>
<input type="password" name="pwd" id="pwd" v-model="password" @blur="check_pwd">
<span class="error_tip">[[error_password_message]]span>
li>
<li>
<label>确认密码:label>
<input type="password" name="cpwd" id="cpwd" v-model="password2" @blur="check_cpwd">
<span class="error_tip">[[error_password2_message]]span>
li>
<li>
<label>手机号:label>
<input type="text" name="phone" id="phone" v-model="mobile" @blur="check_phone">
<span class="error_tip">[[error_phone_message]]span>
li>
<li>
<label>图形验证码:label>
<input type="text" name="pic_code" id="pic_code" class="msg_input" v-model="image_code" @blur="check_image_code">
<img src="images/pic_code.jpg" alt="图形验证码" class="pic_code">
<span class="error_tip">[[error_image_code_message]]span>
li>
<li>
<label>短信验证码:label>
<input type="text" name="msg_code" id="msg_code" class="msg_input" v-model="sms_code" @blur="check_sms_code">
<a href="javascript:;" class="get_msg_code">获取短信验证码a>
<span class="error_tip">[[error_sms_code_message]]span>
li>
<li class="agreement">
<input type="checkbox" name="allow" id="allow" checked="checked" v-model="allow" @blur="check_allow">
<label>同意”美多商城用户使用协议“label>
<span class="error_tip">[[error_allow_message]]span>
li>
<li class="reg_sub">
<input type="submit" value="注 册">
li>
ul>
form>
div>
div>
div>
<div class="footer no-mp">
<div class="foot_link">
<a href="#">关于我们a>
<span>|span>
<a href="#">联系我们a>
<span>|span>
<a href="#">招聘人才a>
<span>|span>
<a href="#">友情链接a>
div>
<p>CopyRight © 2016 北京美多商业股份有限公司 All Rights Reservedp>
<p>电话:010-****888 京ICP备*******8号p>
div>
<script type="text/javascript" src="/static/js/common.js">script>
<script type="text/javascript" src="/static/js/register.js">script>
body>
html>
var vm = new Vue({
el: '#app',
delimiters: ['[[', ']]'],
data: {
host: host,
error_name: false,
error_password: false,
error_check_password: false,
error_phone: false,
error_image_code: false,
error_sms_code: false,
error_allow: false,
error_name_message: '',
error_password_message: '',
error_password2_message: '',
error_phone_message: '',
error_image_code_message: '',
error_sms_code_message: '',
error_allow_message: '请勾选用户协议',
image_code_id: '',
image_code_url: '',
sms_code_tip: '获取短信验证码',
sending_flag: false,
username: '',
password: '',
password2: '',
mobile: '',
image_code: '',
sms_code: '',
allow: true
},
mounted: function () {
this.generate_image_code();
},
methods: {
generateUUID: function () {
var d = new Date().getTime();
if (window.performance && typeof window.performance.now === "function") {
d += performance.now();
}
var uuid = 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function (c) {
var r = (d + Math.random() * 16) % 16 | 0;
d = Math.floor(d / 16);
return (c == 'x' ? r : (r & 0x3 | 0x8)).toString(16);
});
return uuid;
},
generate_image_code: function () {
this.image_code_id = this.generateUUID();
this.image_code_url = this.host + "/image_codes/" + this.image_code_id + "/";
console.log(this.image_code_url);
},
check_username: function () {
var re = /^[a-zA-Z0-9_-]{5,20}$/;
if (re.test(this.username)) {
this.error_name = false;
this.error_name_message = '';
} else {
this.error_name_message = '请输入5-20个字符的用户名';
this.error_name = true;
}
if (this.error_name == false) {
var url = this.host + '/usernames/' + this.username + '/count/';
axios.get(url, {
responseType: 'json'
})
.then(response => {
if (response.data.count > 0) {
this.error_name_message = '用户名已存在';
this.error_name = true;
} else {
this.error_name = false;
this.error_name_message = '';
}
})
.catch(error => {
console.log(error.response);
})
}
},
check_pwd: function () {
var re = /^[0-9A-Za-z]{8,20}$/;
if (re.test(this.password)) {
this.error_password = false;
this.error_password_message = '';
} else {
this.error_password = true;
this.error_password_message = '请输入8-20位的密码';
}
},
check_cpwd: function () {
if (this.password != this.password2) {
this.error_check_password = true;
this.error_password2_message = '两次输入的密码不一致';
} else {
this.error_check_password = false;
this.error_password2_message = '';
}
},
check_phone: function () {
var re = /^1[345789]\d{9}$/;
if (re.test(this.mobile)) {
this.error_phone = false;
this.error_phone_message = '';
} else {
this.error_phone_message = '您输入的手机号格式不正确';
this.error_phone = true;
}
if (this.error_phone == false) {
var url = this.host + '/mobiles/' + this.mobile + '/count/';
axios.get(url, {
responseType: 'json'
})
.then(response => {
if (response.data.count > 0) {
this.error_phone_message = '手机号已存在';
this.error_phone = true;
} else {
this.error_phone = false;
this.error_phone_message = '';
}
})
.catch(error => {
console.log(error.response);
})
}
},
check_image_code: function () {
if (!this.image_code) {
this.error_image_code_message = '请填写图片验证码';
this.error_image_code = true;
} else {
this.error_image_code = false;
this.error_image_code_message = '';
}
},
check_sms_code: function () {
if (!this.sms_code) {
this.error_sms_code_message = '请填写短信验证码';
this.error_sms_code = true;
} else {
this.error_sms_code = false;
this.error_sms_code_message = '';
}
},
check_allow: function () {
if (!this.allow) {
this.error_allow = true;
this.error_allow_message = '请勾选用户协议';
} else {
this.error_allow = false;
this.error_allow_message = '';
}
},
send_sms_code: function () {
if (this.sending_flag == true) {
return;
}
this.sending_flag = true;
this.check_phone();
this.check_image_code();
if (this.error_phone == true || this.error_image_code == true) {
this.sending_flag = false;
return;
}
var url = this.host + '/sms_codes/' + this.mobile + '/?image_code=' + this.image_code + '&image_code_id=' + this.image_code_id;
axios.get(url, {
responseType: 'json'
})
.then(response => {
if (response.data.code == '0') {
var num = 60;
var t = setInterval(() => {
if (num == 1) {
clearInterval(t);
this.sms_code_tip = '获取短信验证码';
this.sending_flag = false;
} else {
num -= 1;
this.sms_code_tip = num + '秒';
}
}, 1000, 60)
} else {
if (response.data.code == '4001') {
this.error_image_code_message = response.data.errmsg;
this.error_image_code = true;
} else {
this.error_sms_code_message = response.data.errmsg;
this.error_sms_code = true;
}
this.generate_image_code();
this.sending_flag = false;
}
})
.catch(error => {
console.log(error.response);
this.sending_flag = false;
})
},
on_submit(){
this.check_username();
this.check_pwd();
this.check_cpwd();
this.check_phone();
this.check_sms_code();
this.check_allow();
if (this.error_name == true || this.error_password == true || this.error_check_password == true
|| this.error_phone == true || this.error_sms_code == true || this.error_allow == true) {
window.event.returnValue = false;
}
}
}
});
1.vue与html内容的双向绑定
解:用v-model
2.触发验证调用方法
解:用@blur,光标挪开触发
6 定义用户模型
class User(AbstractUser):
"""自定义用户模型类"""
mobile = models.CharField(max_length=11, unique=True, verbose_name='手机号')
class Meta:
db_table = 'tb_users'
verbose_name = '用户'
verbose_name_plural = verbose_name
def __str__(self):
return self.username
auth.User.groups: (fields.E304) Reverse accessor for 'User.groups' clashes with reverse accessor for 'User.groups'.
HINT: Add or change a related_name argument to the definition for 'User.groups' or 'User.groups'.
auth.User.user_permissions: (fields.E304) Reverse accessor for 'User.user_permissions' clashes with reverse accessor for 'User.user_permissions'.
HINT: Add or change a related_name argument to the definition for 'User.user_permissions' or 'User.user_permissions'.
users.User.groups: (fields.E304) Reverse accessor for 'User.groups' clashes with reverse accessor for 'User.groups'.
HINT: Add or change a related_name argument to the definition for 'User.groups' or 'User.groups'.
users.User.user_permissions: (fields.E304) Reverse accessor for 'User.user_permissions' clashes with reverse accessor for 'User.user_permissions'.
HINT: Add or change a related_name argument to the definition for 'User.user_permissions' or 'User.user_permissions'.
AUTH_USER_MODEL = 'users.User'
python manage.py makemigrations
python manage.py migrate
7 注册逻辑
def post(self, request):
username = request.POST.get('user_name')
pwd = request.POST.get('pwd')
cpwd = request.POST.get('cpwd')
phone = request.POST.get('phone')
image_code = request.POST.get('pic_code')
sms_code = request.POST.get('msg_code')
allow = request.POST.get('allow')
if not all([username, pwd, cpwd, phone, image_code, sms_code]):
return http.HttpResponseForbidden('缺少必传参数')
if not re.match(r'^[a-zA-z0-9_-]{5,20}$', username):
return http.HttpResponseForbidden('请输入5-20个字符的用户名')
if not re.match(r'^[a-zA-Z0-9]{8,20}$', pwd):
return http.HttpResponseForbidden('请输入8-20位的密码')
if pwd != cpwd:
return http.HttpResponseForbidden('两次密码输入不一致')
if not re.match(r'^1[3-9]\d{9}$', phone):
return http.HttpResponseForbidden('请输入正确的手机号')
if allow != 'on':
return http.HttpResponseForbidden('请勾选用户协议')
try:
User.objects.create_user(username=username, password=pwd, mobile=phone)
except DatabaseError:
return render(request, 'register.html', {
'register_errmsg': '注册失败'})
return redirect('/')
创建子应用contents,然后三部曲:
注册子应用
总路由
子路由
class IndexView(View):
def get(self, request):
"""首页"""
return render(request, 'index.html')
8 状态保持
try:
user = User.objects.create_user(username=username, password=pwd, mobile=phone)
except DatabaseError:
return render(request, 'register.html', {
'register_errmsg': '注册失败'})
login(request, user)
return redirect('/')
9 用户名重复检测
class UsernameRepeatView(View):
"""用户名重复检测"""
def get(self, request, username):
count = User.objects.filter(username=username).count()
return http.JsonResponse({
'code': '200', 'errmsg': 'ok', 'count': count})
10 手机号重复检测
class PhoneRepeatView(View):
"""手机号重复检测"""
def get(self, request, mobile):
count = User.objects.filter(mobile=mobile).count()
return http.JsonResponse({
'code':200, 'errmsg': 'ok', 'count': count})