前戏

上篇文章写了一个简单的登录页面,那我们可不可以实现一个简单的登录功能呢?如果登录成功,给返回一个页面,失败给出错误的提示呢?

在之前学HTML的时候,我们知道,网页在往服务器提交数据的时候,都是在form表单里,并且要满足下面的几个条件:

1.form标签必须要有action和method属性,如果是文件上传还要加上下面的一句

<form action="www.baidu.com" enctype="multipart/form-data"></form>

2.所有获取用户的标签必须放在form表单中,必须要有name属性

3.必须要有submit按钮

Django必学三件套

Django 基础必会三件套,render,HttpResponse,redirect

from django.shortcuts import HttpResponse, render, redirect

HttpResponse:返回一个指定的字符串

render:返回一个HTML文件

redirect:跳转url,如果是同一个网站,可以省略域名,如果想跳转到其他网站,要写上全部的网址

知道了form表单提交数据的三个要素后,我们修改一下login.html文件

<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta http-equiv="content-Type" charset="UTF-8">
<meta http-equiv="x-ua-compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Title</title>
<link rel="stylesheet" href="/static/bootstrap-3.3.7/css/bootstrap.css">
<link rel="stylesheet" href="/static/font-awesome-4.7.0/css/font-awesome.css">
<style>
body {
background-color: #eeeeee;
} .login-box {
margin-top: 50px;
} </style>
</head>
<body>
<div class="container">
<div class="row">
<div class="col-md-4 col-md-offset-4 login-box">
<form class="form-horizontal" action="/login/" method="post">
<div class="col-sm-9">
<h2 class="text-center">请登录</h2>
</div> <div class="form-group"> <div class="col-sm-9">
<div class="input-group margin-bottom-sm">
<label for="email" class="hidden">邮箱</label>
<span class="input-group-addon"><i class="fa fa-envelope-o fa-fw"></i></span>
<input class="form-control" type="text" name="email" id="email" placeholder="您的邮箱地址">
</div>
<span class="help-block"></span>
</div>
</div> <div class="form-group">
<div class="col-sm-9">
<div class="input-group">
<label for="password" class="hidden" >密码</label>
<span class="input-group-addon"><i class="fa fa-key fa-fw"></i></span>
<input class="form-control" type="password" name="pwd" id="password" placeholder="请输入密码">
</div>
<span class="help-block"></span>
</div>
</div> <div class="form-group">
<div class="col-sm-9">
<div class="checkbox">
<label>
<input type="checkbox"> 记住我
</label>
</div>
</div>
</div> <div class="form-group">
<div class="col-sm-9">
<button type="submit" id="b1" class="btn btn-block btn-primary">登录</button>
<p style="color: red;text-align: center">{{ error_msg}}</p>
</div>
</div>
</form>
</div>
</div>
</div> <script src="/static/jquery-3.3.1.js"></script>
<script>
$("#b1").click(function () {
$("input:not([type='checkbox'])").each(function () {
// 判断值为不为空
if ($(this).val().length === 0) {
// 展示错误提示
var errMsgPrefix = $(this).prev().prev().text();
$(this).parent().next().text(errMsgPrefix + "不能为空");
$(this).parent().parent().parent().addClass("has-error");
}
});
}); // 给输入框绑定获取焦点的事件
$("input:not([type='checkbox'])").focus(function () {
// 清空错误提示
$(this).parent().next().text("");
// 移除父标签的has-error
$(this).parent().parent().removeClass("has-error");
});
</script>
</body>
</html>

注意:action="/login/"要加/,要不然下面的错误时路径会是这样的:login/login

我们在去login函数里打印一下request.GET

def login(request):
print(request.GET)
return render(request,'login.html')

结果:

[02/Jul/2019 20:46:35] "GET /login/login?email=%40163.com&pwd=123 HTTP/1.1" 200 3532
<QueryDict: {'email': ['@163.com'], 'pwd': ['']}>

可以看到,我们在登录页面输入的邮箱和密码都以字典的方式传给了后台,其中字典的key就是我们在html文件里对应标签的name属性,如果没有name属性,则为空

我们提交数据的时候,通常都是以post方法来提交的,get通常是用于获取数据的,那我们把login.html文件里的method=‘get’改为post,在来试一下

<form class="form-horizontal" action="login" method="post">

上面的错误信息告诉了我们:CSRF验证失败。请求中止。我们只需要把setting.py里的CSRF注释掉就可以了

'django.middleware.csrf.CsrfViewMiddleware' #注释掉这行

先去把login函数里的GET换成POST

print(request.POST),然后就可以正常访问了

那我们登录之后能不能给浏览器返回一个“登录成功”的提示呢?

index.html

<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta http-equiv="content-Type" charset="UTF-8">
<meta http-equiv="x-ua-compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Title</title>
<link rel="stylesheet" href="/static/bootstrap-3.3.7/css/bootstrap.css">
</head>
<body> <div class="container">
<div class="row">
<div class="col-md-12">
<div class="page-header">
<h1>信息收集卡
<small>共三步</small>
</h1>
</div>
<div class="progress">
<div class="progress-bar progress-bar-success" role="progressbar" aria-valuenow="60" aria-valuemin="0"
aria-valuemax="100" style="width: 33%;">
1/3
</div>
</div>
<!--面板-->
<div class="panel panel-primary">
<div class="panel-heading">基本信息
<span class="glyphicon glyphicon-pushpin pull-right"></span>
</div>
<div class="panel-body">
<!--表单-->
<form class="form-horizontal">
<div class="form-group">
<label for="inputEmail3" class="col-sm-2 control-label">姓名</label>
<div class="col-sm-4">
<input type="text" class="form-control" id="inputEmail3" placeholder="Email">
</div>
</div>
<div class="form-group">
<label for="inputPassword3" class="col-sm-2 control-label">手机号</label>
<div class="col-sm-4">
<input type="text" class="form-control" id="inputPassword3" placeholder="Password">
</div>
</div>
<div class="form-group">
<label for="inputPassword3" class="col-sm-2 control-label">邮箱</label>
<div class="col-sm-4">
<input type="email" class="form-control" id="inputPassword" placeholder="Password">
</div>
</div>
<div class="form-group">
<label for="inputPassword3" class="col-sm-2 control-label">密码</label>
<div class="col-sm-4">
<input type="password" class="form-control" id="inputPassword4" placeholder="Password">
</div>
</div>
<div class="form-group">
<label for="inputPassword3" class="col-sm-2 control-label">头像</label>
<div class="col-sm-4">
<input type="file" id="inputPassword5" placeholder="Password">
<span class="help-block">只支持jpg,png,gif格式</span>
</div>
</div>
<hr>
<div class="form-group">
<label for="inputPassword3" class="col-sm-2 control-label">属性</label>
<div class="col-sm-10">
<div class="radio">
<label>
<input type="radio" name="optionsRadios" id="optionsRadios1" value="option1"
checked>
Option one is this and that&mdash;be sure to include why it's great
</label>
</div>
<div class="radio">
<label>
<input type="radio" name="optionsRadios" id="optionsRadios2" value="option2">
Option two can be something else and selecting it will deselect option one
</label>
</div>
<div class="radio disabled">
<label>
<input type="radio" name="optionsRadios" id="optionsRadios3" value="option3"
disabled>
Option three is disabled
</label>
</div>
</div>
</div>
</form>
</div>
</div>
<!--下一步按钮-->
<button class="btn btn-success pull-right">下一步</button>
</div>
</div>
</div>
</body>
</html>

先在view里创建一个index的函数


def index(request):
return render(request,"index.html")

这里我们需要导入HttpResponse,然后再url.py新增index的路径

from . import views
urlpatterns = [
url(r'^admin/', admin.site.urls),
url(r'^login/', views.login),
url(r'^index/', views.index),
]

在login函数里写如下代码

def login(request):
if request.method == 'POST':
email = request.POST.get('email')
pwd = request.POST.get('pwd')
if email == 'zouzou' and pwd == '':
return redirect('/index/')
# return HttpResponse('ok')
else: return render(request,'login.html')

这样我们如果输入的是zouzou和123,则会跳转到index页面,那如果我们需要错误的时候给我们提示怎么办呢?django提供了我们模版语言;{{变量名}},我们在login.html的button按钮下面加入如下代码

<button type="submit" id="b1" class="btn btn-block btn-primary">登录</button>
<p style="color: red;text-align: center">{{ error_msg}}</p>

在去修改login函数里的代码

def login(request):
error_msg=''
if request.method == 'POST': #如果是post,表示提交数据
email = request.POST.get('email')
pwd = request.POST.get('pwd')
if email == 'zouzou' and pwd == '':
#登录成功跳转到index页面
return redirect('/index/')
# return HttpResponse('ok')
else:
#登录失败,提示用户名密码错误
error_msg = '邮箱或密码错误'
#如果是GET,表示要获取这个页面
return render(request,'login.html',{"error_msg":error_msg})

这样,我们输入正确的邮箱和密码就会跳转到index页面,错误的会提示

app

上面我们把login函数和index函数都放到了views.py文件里面。试想一下,如果我们的项目有成百上千个函数呢?放到一个py文件里是不是很麻烦。

python给我们提供了app的功能,我们可以把一个模块放到一个app里,可以有多个app,不同的功能放到不同的app里面。

创建app:

如下我们创建了一个叫“appTest01”的项目

python manage.py startapp appTest01

创建完app后,我们要告诉Django我们创建了一个叫“appTest01”的app,去setting.py里加上下面的代码。

INSTALLED_APPS = [
'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
'appTest01.apps.Apptest01Config', # 告诉django我们创建了一个叫appTest01的app
# 'appTest01', # 上面代码的简写方式
]

上面的设置好了之后,我们把之前在view.py里写的代码放到刚创建的appTest01下的view.py里面,然后去url.py里把导入的view.py改一下。启动我们的项目,访问登录页面,能正常访问就表示我们的设置是没有问题的

ORM

前面我们的邮箱和密码是写死的。我们可不可以从数据库里面读取数据做一个判断呢?这时我们就要用到ORM了,那什么是ORM呢?

ORM就是一群写代码的,懒的写sql语句,写了一个工具,自动生成sql语句

ORM:Object Relational Mapping(关系对象映射)

类名对应------------》数据库中的表名

类属性对应---------》数据库里的字段

类实例对应---------》数据库表里的一行数据 

ORM的优势

Django的orm操作本质上会根据对接的数据库引擎,翻译成对应的sql语句;所有使用Django开发的项目无需关心程序底层使用的是MySQL、Oracle、sqlite....,如果数据库移只需要更换Django的数据库引擎即可

ORM的缺点就是执行效率低

1.创建数据库

由于ORM没有没有创建数据库的方法,所以我们手动创建一个数据库:

create database mysite;

2.告诉Django连接哪个数据库

因为Django默认的数据库是sqlite3,我们要使用mysql,所以要告诉mysql,去setting.py里修改如下代码

DATABASES = {
'default': {
'ENGINE': 'django.db.backends.mysql', # 连接数据库的类型
'NAME': 'mysite', # 数据库名
'HOST': '127.0.0.1', # 数据库主机地址
'PORT': 3306, # 数据库的端口
'USER': 'root', # 登录数据库的用户名
'PASSWORD': '', # 登录数据库的密码
}
}

3.用什么连接数据库

上面我们已经告诉了django连接哪个数据库,那用什么连?利用第三方的包,比如第三方包:pymysql和MySQLdb,因为MySQLdb不支持python3,所以我们使用pymysql来连接数据库,之前也写过pymysql连接mysql的文章

去和setting.py同级的__init__.py里告诉Django用pymysql模块代替默认的MySQLdb去连接MySQL数据库,写上如下代码

import pymysql

pymysql.install_as_MySQLdb()

4.创建数据表

数据库已经配置好了,也告诉了用什么连,然后我们使用ORM去创建一个数据表。

在appTest01/models.py的文件中创建类(只能在这里面创建),类必须继承models.Model

from django.db import models

# Create your models here.

class User(models.Model):
id = models.AutoField(primary_key=True) # 创建一个自增的id作为主键
email = models.CharField(max_length=32) # varchar(32)
pwd = models.CharField(max_length=32) # varchar(32)

代码解释:

我们创建了一个User的类,上面也说过,类名对应的数据库表,所以会给我们创建一个User的数据表。类下面的就是ORM的语法,创建了三个字段,分别是id(主键)和长度为varchar(32)的email和pwd字段

5.生成数据表

现在我们已经万事具备,只欠东风了,只要生成数据表就可以了,ORM提供了我们两条命令来生成数据表

1.

python manage.py makemigrations  #根据app下的migrations目录中的记录,检测当前model层代码是否发生变化

结果:

Migrations for 'appTest01':
appTest01\migrations\0001_initial.py
- Create model User

2.执行完下面的代码如果都显示OK就表示数据表创建成功了

python manage.py migrate  #把orm代码转换成sql语句去数据库执行

使用pycharm连接mysql数据库

点击右边的DataBase

使用ORM查询数据

上面的apptest01_user是我们创建的表,其他的都是django默认帮我们创建的。我们往数据表里插几条数据

这样,数据我们有了,那我们怎么获取到数据库里的数据和用户输入的数据对比呢?ORM提供了我们一种User.objects.filter(email='', pwd='') 的方法来查询数据

注意:前面的Uer是我们的数据表名,email和pwd是我们数据表里的字段,那我们是不是可以修改一下登录函数了呢

from django.shortcuts import render,HttpResponse,redirect
from appTest01.models import User
def login(request):
error_msg=''
if request.method == 'POST': #如果是post,表示提交数据
ema = request.POST.get('email')
password = request.POST.get('pwd')
res = User.objects.filter(email=ema,pwd=password)
print(res)
if res:
#登录成功跳转到index页面
return redirect('/index/')
# return HttpResponse('ok')
else:
#登录失败,提示用户名密码错误
error_msg = '邮箱或密码错误'
#如果是GET,表示要获取这个页面
return render(request,'login.html',{"error_msg":error_msg}) def index(request):
return render(request,"index.html")

如果查询到res的值就是

<QuerySet [<User: User object>]>

查询不到res的值就是

<QuerySet []>

如果要获取对应的值,可以用下面的方法

print(res[0].id,res[0].email,res[0].pwd)  # 获取到数据库里对应的字段

对象.属性《-----》数据表里具体字段的值

总结:

1. form表单提交数据的三个要素
  1.1. form标签必须要有action和method属性
  1.2. 所有获取用户输入的标签必须放在form表单中,必须要有name属性
  1.3. 必须要有submit按钮

2. Django 基础必会三件套
from django.shortcuts import HttpResponse, render, redirect
  2.1. HttpResponse      返回一个指定的字符串时
  2.2. render        返回一个HTML文件
  2.3. redirect      跳转

3. request相关的属性
  3.1. request.method --> 返回的是请求的方法(全大写):GET/POST ...
  3.2. request.GET --> 取得是URL里面的参数,类似于字典的数据结构
  3.3. request.POST --> post提交的数据,类似于字典的数据结构

4. Django的模板语言
{{ 变量名 }}

5. Django项目app --> 项目中又分了一级Python包,不同的功能放到不同的包里面
  5.1. 创建app
    python manage.py startapp app01
  5.2. 告诉Django创建了一个app
    在settings.py找那个的INSTALLED_APPS中添加新创建的app
6. Django中ORM的使用
  6.1. 用处
    6.1.1. 操作数据表
    6.2.2. 操作数据行
  6.2. 使用
    6.2.1. 手动创建一个数据库
      -> create database mysite;
    6.2.2. 告诉Django连哪个数据库

      DATABASES = {
        'default': {
          'ENGINE': 'django.db.backends.mysql', # 连接数据库的类型
          'NAME': 'mysite', # 数据库名
          'HOST': '127.0.0.1', # 数据库主机地址
          'PORT': 3306, # 数据库的端口
          'USER': 'root',
          'PASSWORD': '',
          }
         }

  6.3. 用什么连数据库?
    利用第三方的包,比如第三方包:pymysql和MySQLdb
    告诉Django用pymysql模块代替默认的MySQLdb去连接MySQL数据库
    和settings.py同级的__init__.py文件,写上:

import pymysql
pymysql.install_as_MySQLdb()

  6.4. 在app/models.py的文件中创建类,只能在这里面创建
    类必须继承models.Model

  6.5. 两个命令
    6.5.1. python manage.py makemigrations --> 把models.py的变更记录一下,注意要保证数据库里的和ORM变更记录一样,否则会报错
    6.5.2. python manage.py migrate --> 把上面的变更记录翻译成SQL语句,去数据库执行
    6.5.3. ORM查询
      User.objects.filter(email='', pwd='')

    6.5.4.数据表名或结构变了都要重新执行一下6.5.1和6.5.2

django -- 实现ORM登录的更多相关文章

  1. ORM以及Django使用ORM创建表

    day61 2018-04-28 1. 内容回顾 1. HTTP协议消息的格式: 1. 请求(request) 请求方法 路径 HTTP/1.1\r\n k1:v1\r\n ...\r\n \r\n ...

  2. Django之ORM初始

    上一篇写了一个静态的登录验证. 实景情况网页的登录验证都是动态验证的,过程其实是从后端拿到储存的账户与密码来和前端的输入信息进行匹配校验的. 一.把项目拆分,来一个单独登录的包,放在Django项目下 ...

  3. Django+bootstrap+注册登录系统

    转自:https://www.cnblogs.com/robindong/p/9610057.html Robin_D 博客园 首页 新随笔 联系 订阅 管理 随笔 - 10  文章 - 0  评论 ...

  4. Django流程-以登录功能为例

    Django流程-以登录功能为例 一.注意点 1.新创建的app一定要先去settings.py注册 简写:'app01' 完整:'app01.apps.App01Config' 2.启动Django ...

  5. python——Django(ORM连表操作)

    千呼万唤始出来~~~当当当,终于系统讲了django的ORM操作啦!!!这里记录的是django操作数据库表一对多.多对多的表创建及操作.对于操作,我们只记录连表相关的内容,介绍增加数据和查找数据,因 ...

  6. Python’s SQLAlchemy vs Other ORMs[转发 3]Django's ORM

    Django's ORM Django is a free and open source web application framework whose ORM is built tightly i ...

  7. 将SALT_STACK的JOB-CACHE放到数据库中,而建库用DJANGO的ORM完成

    下面包括了SALT_MASTER的配置,及DJANGO的ORM里更改默认表名称,更改默认字段名称(里面有个RETURN),更改默认ID索引... 一个下午有和它磨来磨去... 感谢鹏龙,感谢高远..: ...

  8. Django:之ORM、CMS和二维码生成

    Django ORM Django 的数据库接口非常好用,我们甚至不需要知道SQL语句如何书写,就可以轻松地查询,创建一些内容,所以有时候想,在其它的地方使用Django的 ORM呢?它有这么丰富的 ...

  9. Django的ORM实现数据库事务操作

    在Django中实现数据库的事务操作 在学习MySQL数据库时,MySQL数据库是支持原子操作的. 什么是数据库的原子操作呢??打个比方,一个消费者在一个商户里刷信用卡消费. 交易正常时,银行在消费者 ...

随机推荐

  1. 使用STS加入controller注解后编写程序无法自动提示

    1.加入@Controller注解后编写程序无法自动提示,去掉了@Controller注解后就可以了! ​ ​ 2.解决方案:将@Controller替换为@RestController后,可以完美的 ...

  2. HTML+css基础 p段落标签 a 超链接标签 Src和href有什么区别和关联? target属性 Meta标签

    p段落标签: <p></p> 1.他是唯一一个可以不写结束标签的双标签. a 超链接标签: 从一个页面链接到另一个页面.靠的是href属性.  Src和href有什么区别和关联 ...

  3. Ceph更换OSD磁盘

    目录 简介 更换OSD操作步骤 1. 故障磁盘定位 2. 摘除故障磁盘 3. 重建raid0 4. 重建osd 控制数据恢复及回填速度 简介 首先需要说明的是,ceph的osd是不建议做成raid10 ...

  4. 【More Effective C++ 条款2】最好使用C++转型操作符

    C的转型方式存在以下两个缺点: 1)几乎允许你将任何类型转化为任何类型,不能精确的指明转型意图,这样很不安全 如将一个pointer-to-base-class-object转型为一个pointer- ...

  5. Xamarin vs React Native vs Ionic vs NativeScript: Cross-platform Mobile Frameworks Comparison

    CONTENTS Reading time: 14 minutes Cross-platform mobile development has long been a viable alternati ...

  6. kvm虚拟机vnc配置

    通过vnc方式访问虚拟主机上的KVM虚拟机 通过虚拟主机的IP地址与端口进行访问 1.  修改qemu.conf # vi /etc/libvirt/qemu.conf vnc_listen = &q ...

  7. golang学习笔记---string && strconv

    1.字符串的组成?Golang的字符串都是由单个字节连接起来的,每个字节都是UTF8编码标识的Unicode文本.(不需要在考虑中文不兼容问题) 2.如何遍历字符串?先看一个例子: package m ...

  8. 解密“CDO-首席数据官”的价值、挑战及发展

    数据,不论形态.格式和类型,已经迅速成为企业最有战略意义的资产:数据资产已经成为了可以形成业务洞察及优势的战略资源,数据的体量.多样性和复杂性也正以指数级增长.就像其他重要的企业资产,数据需要适当的管 ...

  9. ASP.NET Core In Process Hosting on IIS with ASP.NET Core 2.2(转载)

    ASP.NET Core 2.2 has been out for a while now and with it come some significant improvements to the ...

  10. TCP 协议 精解

    http://www.cnblogs.com/sunev/archive/2012/06/23/2559389.html