Take the drawer as the prototype , Realize user registration and login .
Basic interface :
First point : Automatically send verification code to email , That is to realize the function of automatically sending mail :
To automatically send email to others , First of all, you should have your own mailbox ,msg["From"] Save the name of the sender who sent the message 、 Sender's email address , It's actually your own email address , The sender's name can be written at will .msg["Subject"] Save the title of the sent message .
Then configure the mail sending server , It's your own mailbox server , Set it in your email , start-up POP3/SMTP service , I use Sohu's email , After starting , You will be given a separate login password , To configure server.login You will use .
When sending mail in batches , Just write the mailing list in emailsend In the first parameter of .
Second point , Generate captcha image :
Mainly pillow Library usage , Generate pictures , Random strings with perturbations in the picture .
import random
from PIL import Image, ImageDraw, ImageFont, ImageFilter
# pip3 install Pillow
_letter_cases = "abcdefghjkmnpqrstuvwxy" # Lowercase letters , Remove possible interference i,l,o,z
_upper_cases = _letter_cases.upper() # Capital
_numbers = ''.join(map(str, range(3, 10))) # Numbers
init_chars = ''.join((_letter_cases, _upper_cases, _numbers))
def create_validate_code(size=(120, 30),
chars=init_chars,
img_type="GIF",
mode="RGB",
bg_color=(255, 255, 255),
fg_color=(0, 0, 255),
font_size=18,
font_type="Monaco.ttf",
length=4,
draw_lines=True,
n_line=(1, 2),
draw_points=True,
point_chance = 2):
'''
@todo: Generate captcha image
@param size: Size of picture , Format ( wide , high ), The default is (120, 30)
@param chars: Allowed character set , Format string
@param img_type: The format of picture saving , The default is GIF, Optional is GIF,JPEG,TIFF,PNG
@param mode: Picture mode , The default is RGB
@param bg_color: The background color , The default is white
@param fg_color: The foreground , Verification code character color , The default is blue #0000FF
@param font_size: Captcha font size
@param font_type: Verification code font , The default is ae_AlArabiya.ttf
@param length: Number of verification code characters
@param draw_lines: Whether to draw interference line
@param n_lines: The number range of interference lines , Format tuple , The default is (1, 2), Only draw_lines by True Effective when
@param draw_points: Whether to draw interference points
@param point_chance: Probability of occurrence of interference points , Size range [0, 100]
@return: [0]: PIL Image example
@return: [1]: The string in the verification code picture
'''
width, height = size # wide , high
img = Image.new(mode, size, bg_color) # Create graphics
draw = ImageDraw.Draw(img) # Create a brush
def get_chars():
''' Generates a string of a given length , Return to list format '''
return random.sample(chars, length)
def create_lines():
''' Draw interference line '''
line_num = random.randint(*n_line) # The number of interference lines
for i in range(line_num):
# The starting point
begin = (random.randint(0, size[0]), random.randint(0, size[1]))
# The end point
end = (random.randint(0, size[0]), random.randint(0, size[1]))
draw.line([begin, end], fill=(0, 0, 0))
def create_points():
''' Plot interference point '''
chance = min(100, max(0, int(point_chance))) # Size is limited to [0, 100]
for w in range(width):
for h in range(height):
tmp = random.randint(0, 100)
if tmp > 100 - chance:
draw.point((w, h), fill=(0, 0, 0))
def create_strs():
''' Draw verification code characters '''
c_chars = get_chars()
strs = ' %s ' % ' '.join(c_chars) # Each character is separated by a space
font = ImageFont.truetype(r'd:\Monaco.ttf', font_size)
font_width, font_height = font.getsize(strs)
draw.text(((width - font_width) / 3, (height - font_height) / 3),
strs, font=font, fill=fg_color)
return ''.join(c_chars)
if draw_lines:
create_lines()
if draw_points:
create_points()
strs = create_strs()
# Shape distortion parameters
params = [1 - float(random.randint(1, 2)) / 100,
0,
0,
0,
1 - float(random.randint(1, 10)) / 100,
float(random.randint(1, 2)) / 500,
0.001,
float(random.randint(1, 2)) / 500
]
img = img.transform(size, Image.PERSPECTIVE, params) # Create twist
img = img.filter(ImageFilter.EDGE_ENHANCE_MORE) # Filter , Border strengthening ( The threshold is higher )
return img, strs
stay views Middle function :
from myutils import create_code
import io
def check_code(req):
stream = io.BytesIO()
img,code = create_code.create_validate_code()
print(code)
img.save(stream,'PNG')
req.session['CheckCode'] = code
return HttpResponse(stream.getvalue())
What is returned to the front end is the byte stream of the picture , On the front end , It uses img label :
<img class="check-img" src="check_code" alt=" Verification Code " οnclick="ChangeCode(this);">, The picture is displayed . The random string is saved in session in .
The front end of the whole verification :
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<link rel="stylesheet" href="/static/css/mycommon.css">
</head>
<body>
<div class="head-box">
<div class="head-content">
<a href="#" class="logo"></a>
<div class="action-menu">
<a href="#" class="tb active"> All </a>
<a href="#" class="tb">42 District </a>
<a href="#" class="tb"> Duan Zi </a>
<a href="#" class="tb"> picture </a>
<a href="#" class="tb"> Kick 1024</a>
<a href="#" class="tb"> You asked me to answer </a>
</div>
<div class="key-search">
<form action="/" method="post">
<input type="text" class="search-txt" autocomplete="off">
<a href="#" class="i" >
<span class="ico"></span>
</a>
</form>
</div>
{% if request.session.is_login %}
<div class="action-nav">
<a> dynamic </a>
<a> notice </a>
<a href="#" class="login-user">{
{ request.session.user_info.username }}</a>
<a id="loginout" href="loginout.html"> sign out </a>
</div>
{% else %}
<div class="action-nav">
<a href="#" class="register-login-btn"> register / Sign in </a>
</div>
{% endif %}
</div>
</div>
<div class="shadow hide"></div>
<div class="accountDialog hide">
<div id="model_login" class="login left">
<div class="header"> land </div>
<div class="content">
<div >
<div class="tips">
<span> User name login </span>
<span >|</span>
<span> Email login </span>
</div>
<div id="login_error_summary" class="error-msg">
</div>
<div class="inp">
<input name="user" type="text" placeholder=" Please enter user name or email " />
</div>
<div class="inp">
<input name="pwd" type="password" placeholder=" Please input a password " />
</div>
<div class="inp clearfix">
<input name="code" class="check-code" type="text" placeholder=" Please enter the verification code " />
<span>
<img class="check-img" src="check_code" alt=" Verification Code " onclick="ChangeCode(this);">
</span>
</div>
<div class="extra" >
<input type="checkbox" name="autoLogin" checked="checked" /> <span> Automatically log in within one month </span>
<a class="right" href="javascript:void(0);"> Forget the password ?</a>
</div>
<div class="inp">
<div class="submit" onclick="SubmitLogin(this);">
<span> land </span>
<span class="hide">
<img src="/static/images/loader.gif" >
<span> Landing </span>
</span>
</div>
</div>
</div>
<script>
function ChangeCode(ths) {
ths.src += '?';
}
</script>
</div>
</div>
<div id="model_register" class="register right">
<div class="header">
<span> register </span>
<div class="dialog-close" onclick="CloseDialog('.accountDialog');">X</div>
</div>
<div class="content">
<div >
<div class="tips">
<span> Enter registration information </span>
</div>
<div id="register_error_summary" class="error-msg"></div>
<div class="inp">
<input name="username" type="text" placeholder=" Please enter a user name " />
</div>
<div class="inp">
<input name="email" id="email" type="text" placeholder=" Please enter email address " />
</div>
<div class="inp">
<input name="email_code" class="email-code" type="text" placeholder=" Please enter the verification code " />
<a id="fetch_code" class="fetch-code" href="javascript:void(0);"> Get verification code </a>
<!-- a In the tag href attribute , If it is set to “#”, When the mouse is placed on it, there is a vertical bar , And when you click, the address bar will increase #, As written above , Will become small hands , And the content of the address bar will not be added when clicking -->
</div>
<div class="inp">
<input name="pwd" type="password" placeholder=" Please input a password " />
</div>
<div class="inp">
<div class="submit" onclick="SubmitRegister(this);">
<span> register </span>
<span class="hide">
<img src="/static/images/loader.gif" >
<span> Registering </span>
</span>
</div>
</div>
</div>
</div>
</div>
</div>
<div class="main-content-box">
<div class="main-content">
<div class="content-L">
<div class="top-area">
<div class="child-nav">
<a href="#" class="hotbtn active" > Hottest </a>
<a href="#" class="newbtn" > newest </a>
<a href="#" class="personbtn" > Human release </a>
</div>
<div class="sort-nav">
<a href="#" class="sortbtn active" > Immediate sort </a>
<a href="#" class="newbtn" >24 Hours </a>
<a href="#" class="newbtn" >3 God </a>
</div>
{% if userinfo.is_login %}
<a href="javascript:void(0);" class="publish-btn">
<span class="n2">+ Release </span>
</a>
{% else %}
<a href="javascript:void(0);" class="publish-btn">
<span class="n2">+ Release </span>
</a>
{% endif %}
</div>
<div class="content-list">
{% for item in news_list %}
<div class="item">
<div class="news-pic">
<img src="{
{ item.image_url }}" alt=" New hot drawer ">
</div>
<div class="news-content">
<div class="part1">
<a href="#" class="show-content" target="_blank">
{
{ item.title }}
</a>
<span class="content-source">-{
{ item.url_laiyuan }}</span>
<a href="#" class="n2">
<span class="content-kind">42 District </span>
</a>
</div>
<div class="part2">
<a href="#" class="recommend" title=" recommend ">
<span class="hand-icon icon-recommend"></span>
<b>{
{ item.counts_acc }}</b>
</a>
<a href="javascript:;" class="discuss">
<span class="hand-icon icon-discuss"></span>
<b>5</b>
</a>
<a href="javascript:;" class="collect" title=" Join the private collection ">
<span class="hand-icon icon-collect"></span>
<b> private collection </b>
</a>
<a href="#" class="user-a">
<span>
<img src="/static/images/13.png">
</span>
<b> Luantaro </b>
</a>
<span class="left time-into">
<a class="time-a" href="#" target="_blank">
<b>4 Minutes ago </b>
</a>
<i> Hot list </i>
</span>
<!-- Button for sharing microblogs -->
<span class="share-site-to">
<i> Share the </i>
<span class="share-icon">
<a class="icon-sina" title=" Share to sina weibo " href="#" ></a>
<a class="icon-douban" title=" Share with Douban " href="#" ></a>
<a class="icon-qqzone" title=" Share the QQ Space " href="#" ></a>
<a class="icon-tenxun" title=" Share to Tencent Weibo " href="#" ></a>
<a class="icon-renren" title=" Share on renren " href="#" ></a>
</span>
</span>
</div>
</div>
</div>
{% endfor %}
</div>
<div class="page-area">
<ul>
<li><span class="ct_pagepw">1</span></li>
<li><a href="#" class="ct_pagepa">2</a></li>
<li><a href="#" class="ct_pagepa">3</a></li>
<li><a href="#" class="ct_pagepa">4</a></li>
<li><a href="#" class="ct_pagepa">5</a></li>
<li><a href="#" class="ct_pagepa">6</a></li>
<li><a href="#" class="ct_pagepa">7</a></li>
<li><a href="#" class="ct_pagepa">8</a></li>
<li><a href="#" class="ct_pagepa">9</a></li>
<li><a href="#" class="ct_pagepa">10</a></li>
<li class="next"><a href="#" class="ct_page_edge"> The next page </a></li>
</ul>
</div>
</div>
<div class="content-R">
</div>
</div>
</div>
<div class="footer-box">
<div class="foot-nav">
<a href="#" target="_blank"> About us </a>
<span>|</span>
<a href="#" target="_blank"> Contact us </a>
<span>|</span>
<a href="#" target="_blank"> Terms of service </a>
<span>|</span>
<a href="#" target="_blank"> Privacy policy </a>
<span>|</span>
<a href="#" target="_blank"> Drawer new hot list tool </a>
<span>|</span>
<a href="#" target="_blank"> Download client </a>
<span>|</span>
<a href="#" target="_blank"> Comments and feedback </a>
<span>|</span>
<a href="#" target="_blank"> link </a>
<span>|</span>
<a href="#" target="_blank"> Notice </a>
<a href="#" target="_blank" >
<img src="/static/images/ct_rss.gif" width="36" height="14">
</a>
</div>
<div class="foot-nav2">
<a target="_blank" href="#">
<img class="foot_e" src="/static/images/footer1.gif" width="36" height="14">
</a>
<span class="foot_d"> Its sites </span>
<span class="foot_a">2016chouti.com</span>
<a target="_blank" href="#" class="foot_b"> Beijing ICP To prepare 09053974 Number -3 Beijing public network security 110102004562</a>
<div > copyright : Beijing gezhipu Technology Co., Ltd </div>
</div>
</div>
<script src="/static/jquery-3.6.0.js"></script>
<script>
$(function () {
bindLoginRegister();
bindSendMsg();
});
function bindLoginRegister() {
$('.action-nav a.register-login-btn').click(function () {
$('.shadow,.accountDialog').removeClass('hide');
});
}
function bindSendMsg() {
$('#fetch_code').click(function () {
$('#register_error_summary').empty();
var email = $('#email').val();
if(email.trim().length == 0){
$('#register_error_summary').text(' Please enter email address ');
return;
}
if($(this).hasClass('sending')){
return;
}
var ths = $(this);
var time = 60;
$.ajax({
url: "send_msg/",
type: "POST",
data: {email:email,csrfmiddlewaretoken:'{
{ csrf_token }}'},
dataType: "json",
success: function (arg) {
if(!arg.status){
$('#register_error_summary').text(arg.summary);
}else {
ths.addClass('sending');
var interval = setInterval(function () {
ths.text(" Has been sent (" + time +")");
time -= 1;
if(time<=0){
clearInterval(interval);
ths.removeClass('sending');
ths.text(" Get verification code ");
}
},1000);
}
}
});
});
}
function SubmitRegister(self) {
$('#register_error_summary').empty();
$('#model_register .inp .error').remove();
$(self).children(':eq(0)').addClass('hide');
$(self).addClass('not-allow').children(':eq(1)').removeClass('hide');
var post_dict = {};
$('#model_register input').each(function () {
post_dict[$(this).attr("name")] = $(this).val();
});
post_dict['csrfmiddlewaretoken'] = '{
{ csrf_token }}';
$.ajax({
url: 'register.html',
type: 'POST',
data: post_dict,
dataType: 'json',
success: function (arg) {
if(arg.status){
window.location.href = 'chouti-index.html';
}else {
$.each(arg.message,function (k,v) {
var tag = document.createElement('span');
tag.className = 'error';
tag.innerText = v;
$('#model_register input[name="' + k + '"]').after(tag);
})
}
}
});
$(self).removeClass('not-allow').children(':eq(1)').addClass('hide');
$(self).children(':eq(0)').removeClass('hide');
}
function CloseDialog(dialog) {
$(dialog).addClass('hide');
$('.shadow').addClass('hide');
}
function ChangeCode(self) {
self.src += '?';
}
function SubmitLogin(self) {
$(self).children(':eq(0)').addClass('hide');
$(self).addClass('not-allow').children(':eq(1)').removeClass('hide');
$('#model_login .inp .error').remove();
var post_dict ={};
$('#model_login input').each(function () {
post_dict[$(this).attr('name')] = $(this).val();
});
post_dict['csrfmiddlewaretoken'] = '{
{ csrf_token }}';
$.ajax({
url: 'login.html',
type: 'POST',
data: post_dict,
dataType: 'json',
success: function (arg) {
if(arg.status){
window.location.href = 'chouti-index.html'
}else {
$.each(arg.message,function (k,v) {
alert(v);
var tag = document.createElement('span');
tag.className = 'error';
tag.innerText = v[0]['message'];
$('#model_login input[name="' + k + '"]').after(tag);
});
}
}
});
$(self).removeClass('not-allow').children(':eq(1)').addClass('hide');
$(self).children(':eq(0)').removeClass('hide');
}
</script>
</body>
</html>
The style file :
*{
margin: 0;
padding: 0;
}
a{
text-decoration: none;
}
body{
font-size: 14px;
}
.head-box{
background-color: #2459a2;
height: 44px;
width: 100%;
position: fixed;
top: 0;
left: 0;
/* position Of fixed location , Add position top,left etc. , Let people know where it is fixed , Now it's the screen 0,0 It's about */
/* Is always on the screen 0,0 Location , As the mouse scrolls down , The position remains unchanged */
}
.head-content{
margin: 0 auto; /* The content is centered left and right ,0 Represents up and down ,auto For left and right */
width: 1016px;
height: 44px;
background-color: #2459a2;
line-height: 44px;
position: relative;
}
.logo{
background : url("/static/images/logo.png") no-repeat 0 0;
height: 23px;
width: 121px;
float: left;
margin-top: 11px;
}
.action-menu{
float: left;
margin-left: 20px;
}
.action-menu a.tb{
color: #c0cddf;
margin-left: -6px; /* Between the two menu items margin yes 0, Use padding To separate , Because the default margin There is a value , Use a negative value to make it 0*/
padding: 0 13px 0 13px;
display: inline-block;
}
.action-menu a.tb:hover{
color: #fff;
background-color: #c0cddf;
}
.action-menu a.active,.action-menu a.active:hover{
color: #fff;
background-color: #204982;
}
.key-search{
float: right;
margin-top: 7px;
}
.key-search .search-txt,.key-search a.i{
float: left;
}
.key-search .search-txt{
width: 91px;
height: 25px;
padding: 2px 2px 2px 5px;
color: #333;
}
.key-search .ico{ /* span Background picture in label , Adjustment , Make the magnifying glass image display in the small window */
background: url("/static/images/icon.png") no-repeat 0 -197px;
height: 12px;
width: 12px;
display: inline-block;
/* span Itself is an inline tag , Need to change to inline-block*/
margin-bottom: 5px;
margin-left: 8px;
/* margin Used to adjust the following span The location of the label */
}
.key-search a.i{ /* a The label contains the above span label */
margin-top: 1px;
height: 31px;
width: 30px;
background-color: #f4f4f4;
display: inline-block;
/*border: 1px yellow solid;*/
border-left: none;
}
.action-nav{
position: absolute;
right: 131px;
}
.action-nav a{
color: white;
padding: 0 20px;
display: inline-block;
}
.action-nav a:hover{
background-color: #c0cddf;
}
.shadow{
position: fixed;
top: 0;
right: 0;
bottom: 0;
left: 0;
background-color: rgba(0,0,0,0.4);
z-index: 1000;
}
.hide{
display: none;
}
.main-content-box{
background-color: #ededed;
width: 100%;
padding-top: 44px;
}
.main-content{
margin: 0 auto;
background-color: white;
width: 960px;
height: auto!important;
min-height: 500px;
padding: 6px 28px 60px 28px;
overflow: hidden;
}
.content-L{
float: left;
width: 630px;
}
.child-nav,.sort-nav{
float: left;
padding: 10px;
}
.publish-btn{
float: right;
padding: 10px;
}
.top-area{
overflow: hidden;
border-bottom: 1px solid #99aecb;
}
.child-nav a{
display: inline-block;
width: 60px;
height: 26px;
line-height: 26px;
text-align: center;
color: #369;
font-weight: 700;
margin-top: 3px;
}
.child-nav .hotbtn{
background: url("/static/images/tip.png") no-repeat 0 -299px;
/*display: inline-block;*/
/*width: 60px;*/
/*height: 26px;*/
/*line-height: 26px;*/
/*text-align: center;*/
color: black;
}
.sort-nav{
margin-left: 100px;
margin-top: 6px;
}
.sort-nav a{
margin-left: 1px;
color: green;
}
.sort-nav .sortbtn{
color: #b4b4b4;
}
.publish-btn{
display: inline-block;
background-color: #84a42b;
width: 120px;
height: 18px;
color: white;
line-height: 18px;
text-align: center;
margin-top: 3px;
}
.content-list .item{
border-bottom: 1px solid red;
margin-top: 10px;
}
.item .news-pic{
float: right;
margin-top: 3px;
margin-left: 8px;
}
.part2{
padding-top: 10px;
margin-bottom: 12px;
}
.hand-icon{
background: url("/static/images/icon_18_118.png") no-repeat 0 0;
width: 18px;
height: 18px;
display: inline-block;
vertical-align: -4px;
}
.icon-recommend{
background-position: 0 -40px;
}
.icon-discuss{
background-position: 0 -100px;
}
.icon-collect{
background-position: 0 -140px;
}
.part2 .user-a span{
vertical-align: -4px;
}
.part2 a{
margin-left: 10px;
}
.part1{
line-height: 20px;
}
.part1 .content-source,.content-kind{
color: #b4b4b4;
}
.part1 .content-kind{
text-decoration: underline;
}
.part1 .show-content{
color: #369;
font-size: 14px;
font-weight: 700;
}
.part2 b,.time-into i{
color: #b4b4b4;
}
.share-icon a{
background: url("/static/images/share_icon.png") no-repeat 0 0;
height: 14px;
width: 17px;
display: inline-block;
vertical-align: -4px;
opacity: 0.5;
}
.share-icon a:hover{
opacity: 1;
}
.icon-sina{
}
.share-site-to .share-icon a.icon-sina{
background-position: 0 -90px;
}
.share-site-to .share-icon a.icon-douban{
background-position: 0 -105px;
}
.share-site-to .share-icon a.icon-qqzone{
background-position: 0 -120px;
}
.share-site-to .share-icon a.icon-tenxun{
background-position: 0 -136px;
}
.share-site-to .share-icon a.icon-renren{
background-position: 0 -151px;
}
.share-site-to{
float: right;
}
.page-area ul li{
display: inline-block;
float: left;
color: #369;
height: 34px;
width: 34px;
line-height: 34px;
text-align: center;
border: 1px solid #a3a3a1;
border-radius: 20%;
margin-left: 4px;
}
.page-area{
margin-left: 10px;
margin-top: 10px;
}
ul li.next{
width: 60px;
}
.page-area ul li:hover{
color: white;
background-color: #204982;
}
.footer-box{
margin-top: -20px;
background-color: #ededed;
width: 100%;
}
.foot-nav,.foot-nav2{
width: 1016px;
margin: 0 auto;
padding-top: 10px;
background-color: white;
text-align: center;
}
.foot-nav{
border-top: 1px solid #a3a3a1;
}
.accountDialog{
position: fixed;
width: 700px;
height: 375px;
left: 50%;
top: 50%;
margin-left: -350px;
margin-top: -250px;
z-index: 1001;
background-color: rgb(230,236,243);
}
.accountDialog .login{
width: 349px;
background-color: #fff;
height: 375px;
border-right: 1px solid #cbdcee;
float: left;
}
.accountDialog .register{
width: 350px;
background-color: white;
height: 375px;
float: right;
}
.accountDialog .login .header,.accountDialog .register .header{
background: #e7ecf2;
padding: 0 10px;
font-size: 14px;
height: 30px;
line-height: 30px;
font-weight: bold;
color: #abb6d2;
position: relative;
}
.accountDialog .register .content .tips,.accountDialog .login .content .tips{
/*padding: 20px 0 0 -10px;*/
padding-top: 10px;
font-size: 14px;
color: #abb6d2;
cursor: pointer;
text-align: left;
}
.accountDialog .login .content .inp,.accountDialog .register .content .inp{
padding: 10px 0;
position: relative;
}
.accountDialog .login .content .inp input,.accountDialog .register .content .inp input{
width: 150px;
padding: 6px;
border: 1px solid #CDDDEF;
}
.accountDialog .register .content .inp .fetch-code{
display: inline-block;
background-color: #336699;
height: 29px;
line-height: 29px;
padding: 0 5px;
color: #ffffff;
text-decoration: none;
}
.accountDialog .login .content .error-msg,.accountDialog .register .content .error-msg{
color: red;
height: 14px;
}
.accountDialog .login .content .inp .check-code{
width: 117px;
padding: 6px;
border: 1px solid #CDDDEF;
display: inline-block;
margin-right: 3px;
}
.accountDialog .login .content .inp .check-img{
height: 29px;
width: 70px;
display: inline-block;
cursor: pointer;
vertical-align: top;
}
.accountDialog .register .content .inp .email-code{
width: 122px;
padding: 6px;
border: 1px solid #CDDDEF;
}
.accountDialog .register .content .inp .fetch-code.sending{
cursor: not-allowed;
background-color: #a3a3a1 !important
}
.accountDialog .register .content .inp .submit,.accountDialog .login .content .inp .submit{
width: 95px;
height: 31px;
line-height: 31px;
margin-top: 5px;
background-color: #336699;
color: #ffffff;
text-align: center;
cursor: pointer;
font-size: 14px;
font-weight: 700;
display: inline-block;
}
.accountDialog .login .content .extra{
padding-bottom: 10px;
}
.accountDialog .login .content .extra a{
color: #369;
}
.accountDialog .register .header .dialog-close{
position: absolute;
right: 10px;
top: 1px;
color: #99aecb;
cursor: pointer;
}
.accountDialog .register{
width: 350px;
background-color: #ffffff;
height: 375px;
}
.accountDialog .register .content .inp .error,.accountDialog .login .content .inp .error{
font-size: 10px;
position: absolute;
color: #e4393c;
background: #FFEBEB;
border: 1px solid #ffbdbe;
z-index: 10;
height: 15px;
width: 208px;
line-height: 15px;
display: block;
overflow: hidden;
}
.not-allow{
cursor: not-allowed !important;
}
views function :
from django.shortcuts import render,redirect,HttpResponse
from projectct import models
from myutils.myresponse import BaseResponse
from myutils.myforms import SendMsgForm,RegisterForm,LoginForm
import json
import datetime
from myutils import commons
from django.utils import timezone
from chouti import settings
import pytz
def test(req):
news_list = models.News.objects.all().values("title", "url_laiyuan", "counts_acc", "image_url","auth__username")
return render(req,'test.html',{'obj':news_list})
def login(req):
rep = BaseResponse() # Return the front-end information encapsulation class
form = LoginForm(req.POST) # Verify the format of the entered login information , Not the validation of database data
if form.is_valid(): # When the verification is correct
_value_dict =form.clean()
print(_value_dict)
if _value_dict['code'].lower() != req.session["CheckCode"].lower(): # The entered verification code is the same as the server session Verification code comparison in
rep.message = {'code':[{'message':' Verification code error '}]}
print('::::::::==>',rep.__dict__)
return HttpResponse(json.dumps(rep.__dict__)) # __dict__, The attributes in the class are stored in this variable in the form of a dictionary
# The verification code is correct
from django.db.models import Q
# Q Is or logical relation query , Verify the database data
con = Q()
q1 = Q()
q1.connector = 'AND'
q1.children.append(('email',_value_dict['user']))
q1.children.append(('pwd',_value_dict['pwd']))
q2 = Q()
q2.connector = 'AND'
q2.children.append(('username', _value_dict['user']))
q2.children.append(('pwd', _value_dict['pwd']))
con.add(q1,'OR')
con.add(q2,'OR')
# con The final result is query “email With the code ” or “username With the code ”, That is, log in by email or by user name
# General filter Add field name directly in = In the form of , They are related to each other
obj = models.UserInfo.objects.filter(con).first()
if not obj:
rep.message = {'user':[{'message':' User name or email 、 Wrong password '}]}
return HttpResponse(json.dumps(rep.__dict__))
req.session['is_login'] = True
req.session['user_info'] = {'nid':obj.id,'email':obj.email,'username':obj.username}
rep.status = True
else:
error_msg = form.errors.as_json()
rep.message = json.loads((error_msg))
return HttpResponse(json.dumps(rep.__dict__))
def chouti(req):
# news_list = models.News.objects.all().values("title","url_laiyuan","counts_acc","contents","image_url","auth__username")
news_list = models.News.objects.all().values("title", "url_laiyuan", "counts_acc", "image_url","auth__username")
print(req.session.session_key)
print(req.session.keys())
print(req.session.values())
return render(req,'chouti-index.html',{"news_list":news_list})
import pytz
def send_msg(req):
# Registration time , Send email verification code
rep = BaseResponse()
form = SendMsgForm(req.POST)
if form.is_valid():
_value_dict = form.clean()
email = _value_dict['email']
has_exisits_email = models.UserInfo.objects.filter(email=email).count()
if has_exisits_email:
rep.summary = " This mailbox has been registered "
return HttpResponse(json.dumps(rep.__dict__))
# current_date = datetime.datetime.now(pytz.UTC) # What you get is UTC Time , With time zone , That is active datetime
# print(current_date) # 2022-06-29 00:29:16.044477+00:00
current_date = datetime.datetime.now(pytz.timezone('Asia/Shanghai')) # Get the time without time zone , namely naive datetime
print(current_date) # 2022-06-29 08:37:05.017300, It's local time , Not converted to UTC
# When models The classes defined in use DateTimeField A field , Required active datetime Date time object , Otherwise, report the following warning :
# RuntimeWarning: DateTimeField SendMsg.ctime received a naive datetime (2022-06-29 08:37:05.017300) while time zone support is active.
# current_date = timezone.make_aware(current_date)
# print(current_date)
# print(timezone.now()) # 2022-06-29 00:47:02.625482+00:00, Default UTC Of active datetime object , Local time minus 8
code = commons.random_code()
emailsend([email,],code) # Send verification code to email
count = models.SendMsg.objects.filter(email=email).count()
if not count:
models.SendMsg.objects.create(code=code,email=email,ctime=current_date)
rep.status = True
else:
limit_day = current_date - datetime.timedelta(hours=1)
times = models.SendMsg.objects.filter(email=email,ctime__gt=limit_day,times__gt=9).count()
if times:
rep.summary = "' The maximum number of times has been exceeded (1 Try again in hours )'"
else:
unfreeze = models.SendMsg.objects.filter(email=email,ctime__lt=limit_day).count()
if unfreeze:
models.SendMsg.objects.filter(email=email).update(times=0)
else:
from django.db.models import F
models.SendMsg.objects.filter(email=email).update(code=code,ctime=current_date,times=F('times')+1)
rep.status=True
else:
rep.summary = form.errors['email'][0]
return HttpResponse(json.dumps(rep.__dict__))
import smtplib
from email.mime.text import MIMEText
from email.utils import formataddr
def emailsend(email_list,content,subject=" Test automatic email sending "):
msg = MIMEText(content,'plain','utf-8')
msg['From'] = formataddr([" Test mailbox ","[email protected]"])
msg['Subject'] = subject
server = smtplib.SMTP("smtp.sohu.com",25)
server.login("[email protected]"," password ")
server.sendmail("[email protected]",email_list,msg.as_string())
server.quit()
def register(req):
rep = BaseResponse()
form = RegisterForm(req.POST)
if form.is_valid():
current_date = datetime.datetime.now(pytz.timezone('Asia/Shanghai'))
limit_day = current_date -datetime.timedelta(minutes=1)
_value_dict = form.clean()
is_valid_code = models.SendMsg.objects.filter(email=_value_dict['email'],code=_value_dict['email_code'],ctime__gt=limit_day).count()
if not is_valid_code:
rep.message['email_code'] = ' The email verification code is incorrect or expired '
return HttpResponse(json.dumps(rep.__dict__))
has_exists_email = models.UserInfo.objects.filter(email=_value_dict['email']).count()
if has_exists_email:
rep.message['email'] = ' The mailbox already exists '
return HttpResponse(json.dumps(rep.__dict__))
has_exists_username = models.UserInfo.objects.filter(username=_value_dict['username']).count()
if has_exists_username:
rep.message['username'] = ' The user name already exists '
return HttpResponse(json.dumps(rep.__dict__))
_value_dict['ctime'] = current_date
_value_dict.pop('email_code')
obj = models.UserInfo.objects.create(**_value_dict)
user_info_dict = {'nid':obj.id,'email':obj.email,'username':obj.username}
models.SendMsg.objects.filter(email=_value_dict['email']).delete()
req.session['is_login'] = True
req.session['user_info'] = user_info_dict
rep.status = True
else:
error_msg = form.errors.as_json()
rep.message = json.loads(error_msg)
return HttpResponse(json.dumps(rep.__dict__))
def loginout(req):
req.session.clear()
return redirect('chouti-index.html')
from myutils import create_code
import io
def check_code(req):
stream = io.BytesIO()
img,code = create_code.create_validate_code()
img.save(stream,'PNG')
req.session['CheckCode'] = code
return HttpResponse(stream.getvalue())
models modular :
from django.db import models
# Create your models here.
class UserInfo(models.Model):
username = models.CharField(max_length=32,db_index=True)
email = models.CharField(max_length=32,unique=True)
pwd = models.CharField(max_length=64)
ctime = models.DateTimeField(auto_now_add=True)
"""
Define union index
class Meta:
index_together = [
('username','pwd'),
]
unique_together = [
('username','pwd'),
]
"""
class SendMsg(models.Model):
email = models.EmailField(max_length=64,unique=True)
code = models.CharField(max_length=6)
ctime = models.DateTimeField()
times = models.IntegerField(default=1)
# Use SendMsg.objects.create(email="111111",code="1234",stime=datetime.now())
# The above statement will save the database successfully , It's not going to happen email verification
# Mr. can be an object :obj = SendMsg(email="111111",code="1234",stime=datetime.now())
# then obj.clean() When executing this sentence , Will be verified ,email Unqualified , It will directly report an abnormal error
# If correct , Use obj.save() Save database
# django Admin It can also be verified
class News(models.Model):
title = models.CharField(max_length=256)
content = models.CharField(max_length=1024)
url_laiyuan = models.URLField()
counts_acc = models.IntegerField()
image_url = models.CharField(max_length=128)
contents = models.TextField()
auth = models.ForeignKey("UserInfo",on_delete=models.DO_NOTHING)
form Verification module :
from django import forms
class SendMsgForm(forms.Form):
email = forms.EmailField()
class RegisterForm(forms.Form):
username = forms.CharField()
email = forms.EmailField()
pwd = forms.CharField()
email_code = forms.CharField()
class LoginForm(forms.Form):
user = forms.CharField()
pwd = forms.CharField()
code = forms.CharField()
Route item :
from django.contrib import admin
from django.urls import path
from projectct import views
urlpatterns = [
path('admin/', admin.site.urls),
path('test.html',views.test),
path('index.html',views.login),
path('chouti-index.html',views.chouti),
path('send_msg/',views.send_msg),
path('register.html',views.register),
path('loginout.html',views.loginout),
path('check_code/',views.check_code),
path('login.html',views.login),
]
The third point of knowledge : Use of time function , Mainly datetime,pytz,timezone Use of modules , Pay attention to the difference between date and time with time zone and without time zone , Be consistent when using .
The fourth knowledge point :F and Q,F It is necessary to use ,Q Used to combine or query ( Use connector It can also be with ), Build complex query statements .
Through this little experiment , I think the front-end writing is troublesome , To develop B/S Architecture program , Need to strengthen js、jQuery、CSS Study .