Django后续
环境准备
创建一个Django项目,可以使用前面使用命令行创建,在这里我是使用pycharm创建的。
记得选择左边的Django,Location创建项目的目录最后一级为项目的名称。在这里我们可以创建一个app,如上如我创建了app01。
创建好后我们可以看见一个目录为:
我们需要在这个目录的manager.py同级目录创建一个static的静态目录,用来放置css,和js。
再往后我们需要在setting.py的配置文件做以下配置:
- 找到 'django.middleware.csrf.CsrfViewMiddleware'并把它注释掉
- 找到TEMPLATES部分,如果没有如下代码,则需要添加:'DIRS': [os.path.join(BASE_DIR, 'templates')]
- 在文件的最后添加静态文件目录,这里需要注意这里面是一个元组,所以注意要有逗号(,)。
到这里我们的一些基本的配置就配好了。最后我们得到的目录为
上面就是我们开始Django项目前的一些环境准备。
下面是一个简单的登录验证的页面
大致可以写如下3步:
- 在myobj下的urls.py里面写下相应的路有关系
- 在app01目录下面我们写相关的业务代码,也就是写相应的视图函数
- 在写相应的html
上面在我们写相应的路由关系的时候,我们需要把把路由关系和视图函数联系起来
写法如图:加上红色的那一句
第一步就是写相关的路由关系
from django.contrib import admin from django.urls import path from django.conf.urls import url,include from app01 import views urlpatterns = [ path('admin/', admin.site.urls), url(r'^login/', views.login), url(r'^index/', views.index), ]
写好后我们在写对应的视图函数、视图函数在app01下面的views里面写代码如下
from django.shortcuts import render,redirect # Create your views here. def login(request): if request.method == "GET": return render(request,'login.html') elif request.method == "POST": user = request.POST.get('user') pwd = request.POST.get('pwd') if user == 'admin' and pwd == 'admin': return redirect('/index/') else: return render(request,'login.html') else: return render(request,'login.html') def index(request): return render(request,'index.html')
在接下来写index和login相关的代码
login.html
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> </head> <body> <form action="/login/" method="post" enctype="multipart/form-data"> <p><input type="text" name="user" placeholder="请输入用户名"/></p> <p><input type="password" name="pwd" placeholder="请输入密码"/></p> <p><input type="submit" value="登陆"></p> </form> </div> </body> </html>
index.html代码
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> </head> <body> <div>登陆成功</div> </body> </html>
记住上面的这些HTML代码都是放在templates目录下面的。而static目录里面放的是一些js和css文件
上面我们可以看到
这个就是登录界面,当我们输入的用户名和密码正确的时候就会跳转到我们成功的页面,当我们失败的时候还会停留在这个页面。
获取数据和文件上传
在视图里面(/app01/views.py) 1、获取用户请求数据 request.GET.get(标签里面的name属性值) request.POST.get(标签里面的name属性值) request.FILES.get(标签里面的name属性值) PS: GET:获取数据 POST:获取用户提交数据 2、获取checkbox等多选的内容 request.POST.getlist(标签里面的name属性值) 3 、上传文件 # 上传文件,form标签做特殊设置 obj = request.FILES.get('fafafa') obj.name f = open(obj.name, mode='wb') for item in obj.chunks(): f.write(item) f.close()
上面使用标签里面的name属性值获取到的是标签里面value属性值。
关于获取checkbox等多选的内容实验
视图里面的代码(/app01/views.py)
from django.shortcuts import render,redirect,HttpResponse from django.views import View import os # Create your views here. def login(request): if request.method == "GET": return render(request,'login.html') elif request.method == "POST": user = request.POST.get('user') pwd = request.POST.get('pwd') gender = request.POST.get('gender') favor = request.POST.getlist('favor') city = request.POST.getlist('city') print(user,pwd,gender,favor,city) obj = request.FILES.get('upload') print(obj,type(obj),obj.name) file_path = os.path.join('upload_dir',obj.name) with open(file_path, 'wb') as f: for i in obj.chunks(): f.write(i) return HttpResponse('ok') # 打印的结果 #admin admin 1 ['1', '2', '3'] ['sh', 'bj', 'tj'] #2018-07-04日22:00 巡检记录.txt <class 'django.core.files.uploadedfile.InMemoryUploadedFile'> 2018-07-04日22:00 巡检记录.txt
login.html代码
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> </head> <body> <form action="/login/" method="post" enctype="multipart/form-data"> <p> <input type="text" name="user" placeholder="用户名"> </p> <p> <input type="password" name="pwd" placeholder="密码"> </p> <p> 男:<input type="radio" name="gender" value="1"> 女:<input type="radio" name="gender" value="2"> </p> <p> 乒乓球:<input type="checkbox" name = "favor" value="1"> 篮球:<input type="checkbox" name = "favor" value="2"> 羽毛球:<input type="checkbox" name = "favor" value="3"> </p> <p> <select name="city" multiple> <option value="sh">上海</option> <option value="bj">北京</option> <option value="tj">天津</option> </select> </p> <p> <input type="file" name="upload"> </p> <input type="submit" value="提交"> </form> </body> </html>
从上面我们可以知道我们通过标签里面的name属性值获取到的是标签的value,当时多选的时候会得到一个列表。
同时上传文件我们得到的是一个obj我们打印出这个obj看到的是一个上传文件的名字,但是通过type可以知道这个并不只是一个文件名。
要想获取里面文件里面的数据我们使用obj.chunks()的方法获取里面数据,通过和操作文件句柄一样的操作一行行的读取里面的数据再把这个数据写入到文件中,记住使用'wb'的方式,这个上传的可能是图像
通过obj.name获取到我们真正想知道的文件名。上面上传文件我们需要提前创建一个upload_dir目录要不就会报错。
写视图的方式有FBV和CBV
1、FBV
FBV --> function base view
这个写视图用的是函数的方式。
如:
def 函数名(request):
同时写路由关系就是上面的方式:
from app01 import views
url(r'^login/', views.login)
2、CBV
CBV --> class base view
使用类的方式写视图。
这里的类需要继承View类,所以我们在视图函数里面需要导入
from django.views import View
class 类名(View):
写路由关系我们需要在路由关系中写:
记住在视图类的后面要加上.as_view(),下面黄色部分使我们可以变化的路由关系
url(r'^login/', views.Login.as_view())
我们上面就是使用的FBV写的,现在我们使用CBV实现下登录页面的验证
先在myobj/urls.py里面代码
from django.contrib import admin from django.urls import path from django.conf.urls import url from app01 import views urlpatterns = [ path('admin/', admin.site.urls), url(r'^index/', views.Index.as_view()), url(r'^login/', views.Login.as_view()), ]
视图里面的代码
from django.shortcuts import render,redirect from django.views import View class Index(View): def get(self,request): return render(request,'index.html') class Login(View): def get(self,request): return render(request,'login.html') def post(self,request): user = request.POST.get('user') pwd = request.POST.get('pwd') if user == 'admin' and pwd == 'admin': return redirect('/index/') else: return render(request,'login.html')
html代码和上面的第一个登录界面的html代码是一样的没什么区别。这个实现后的效果也是一样的。只是不同形式的实现方式这个是CBV的方式实现的。
简单分析CBV的运行的流程
我们直接访问页面的时候一般都是使用get的方式提交的
当我们输入url他会在路由关系里面找到相应的视图类,我们使用继承的类的里面使用了反射函数。
我们可以通过看继承的父类里面的代码可以知道它里面是帮我们做了相应的处理,反射到我们在类里面绑定的函数。
直接执行我们在内中绑定的函数。就实现了整个流程。
视图中传入模板的字典数据的循环取值
卸载app01/views.py中的代码
from django.shortcuts import render USER_DICT = { "k1":"root1", "k2":"root2", "k3":"root3", "k4":"root4", "k5":"root5", } def index(request): return render(request,"index.html",{"user_dict":USER_DICT})
index.html代码
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> </head> <body> <ul> {% for k,row in user_dict.items %} <li>{{ k }}-{{ row }}</li> {% endfor %} {% for k in user_dict %} <li>{{ k }}</li> {% endfor %} {% for v in user_dict.values %} <li>{{ v }}</li> {% endfor %} </ul> </body> </html>
上面我们可以看到我么你可以通过for循环dict.items取字典的键值对
也可以通过for循环dict.values取字典的每一个值,也可以直接循环字典得到字典的键。
Django的路由系统
多级路由
上面写的都是通过主urls文件通过导入app的views来实现关于路由到视图的关联,也可以称主usrl文件为一级路由
当我们外部访问的时候,会在一级路由中查找,如果想要多级路由就要在以及路由里面导入下一级路由。
代码为:
from django.conf.urls import url, include urlpatterns = [ url(r'^cmdb/', include("app01.urls")), ]
上面的urls我们需要在app01下面自己创建。
先说一下当我们输入url的时候在路由系统里面我们匹配的去除掉前面域名的
如:http://127.0.0.1/cmdb/django/,我们只会匹配后面/cmdb/django
在一级路由的时候我们会正则匹配/cmdb/同时也去除掉前面正则匹配的这时只有/django/那会拿着这个url到app01里面的urls里面正则匹配相应的路由。这样就实现了多级路由。我们可以认为只要前面是/cmdb/我们就会把剩下的路由传递给include的下一级路由。这个就是多级路由
url()方法
url()方法可以接受4个参数(regex, view, kwargs=None, name=None)可以看出2个是必须的
regex:这个就是正则表达式的缩写,这个就是匹配字符串或这url地址的语法。
view:指的是处理当前url请求的试图函数。
kwargs:任意数量的关键字参数可以作为一个字典传递给目标视图
name:对你的URL进行命名,让你能够在Django的任意处,尤其是模板内显式地引用它。这是一个非常强大的功能,相当于给URL取了个全局变量名,不会将url匹配地址写死。
这里只是简单的介绍一下这四个参数。
regex
关于regex的写法,当一个网站的url地址太多的时候我们就会写的太多。我们可以把一些有相同特性的url写成同意格式:
如:url(r'^index-(\d+).html', views.index),这个就是一个正则表达式,可以匹配这一类型的url
或者url(r'^index-(\d+)-(\d+).html', views.index),这个可以更好的匹配相应的url
上面的这个匹配会把分组的匹配到的按位置传送到view试图函数。相当于他会把第一个分组匹配的当作视图函数的一个参数传给试图函数,
这个如果参数的位置写错了就会造成后面的一系列数据错误,所以不推荐使用这个。
我们可以使用:url(r'^index-(?P<nid>\d+)-(?P<uid>\d+).html', views.index)
这个就是正则的给分组起一个名字,这样我们就会得到一个字典我们就可以把这个字典传到视图函数里面。
这样我们就可以根据我们起的名字来取到我们想要的数据。
视图函数可以是:def 函数名(request,*args,**kwargs):pass
这样不管我们url里面的分组是否起名字我们都能够传到后面。不过建议使用后一种方式这样不容易出错。
name
name是对URL路由关系进行命名,以后可以根据此名称生成自己想要的URL
url(r'^asdf/', views.index, name='i1'),
url(r'^qwe/(\d+)/(\d+)/', views.index, name='i2'),
url(r'^asd/(?P<pid>\d+)/(?P<nid>\d+)/', views.index, name='i3'),
这个样我们在视图函数里面可以:
from django.urls import reverse
def func(request,*args,**kwargs):
url1 = reverse('i1') # 得到的是 asdf/
url2 = reverse(‘i2',args(1,2)) # 得到 /qwe/1/2
url3 = reverse('i3',kwargs{pid:1,nid:3}) # asd/1/3
在模板语言中:
{% url "i1" %} ---生成/asdf/
{% url "i2" 1 2 %} --生成qwe/1/2/
{% url "i3" pid=1 uid=3 %} ---生成asd/1/3/
这个的用处比如我们原本有一个网址我们现在改为一个新的网址,但是因为旧的网址,用的人比较多我们就可以利用跳转
如:
原来的:
url(r'^qwe/(\d+)/(\d+)/', views.index),
改成
url(r'^new_qwe(\d+)/(\d+)/', views.new_index,name='i1'),
我们只需要在view里面增加
from django.http import HttpResponseRedirect
from django.urls import reverse
def inde(requsrt,a,b):
return HttpResponseRedirect(reverse('i1',args=(a,b)))
Django的ORM
1、数据库的安装
再说ORM的时候,我们先说一下数据库的安装。
我们打开项目的setting.py的配置文件,这个是整个个Django项目的设置中心。Django默认使用SQLite数据库,因为Python源生支持SQLite数据库,所以你无须安装任何程序,就可以直接使用它。当然,如果你是在创建一个实际的项目,可以使用类似PostgreSQL的数据库,避免以后数据库迁移的相关问题。
在这个配置文件中我们可以找到如下的代码,这个就是默认的数据库配置,这个默认为SQLite数据库。
# Database # https://docs.djangoproject.com/en/1.10/ref/settings/#databases DATABASES = { 'default': { 'ENGINE': 'django.db.backends.sqlite3', 'NAME': os.path.join(BASE_DIR, 'db.sqlite3'), } }
如果我们想要其他的数据库的时候我们可以在上面的key为default对应的值进行配置。来连接你的数据库。上面的一些参数的解释
ENGINE(引擎):可以是django.db.backends.sqlite3
、django.db.backends.postgresql
、django.db.backends.mysql
、django.db.backends.oracle等其他的
NAME(名称):类似Mysql数据库管理系统中用于保存项目内容的数据库的名字。如果你使用的是默认的SQLite,那么数据库将作为一个文件将存放在你的本地机器内,此时的NAME应该是这个文件的完整绝对路径包括文件名,默认值os.path.join(BASE_DIR, ’db.sqlite3’)
,将把该文件储存在你的项目目录下。
下面就是一个使用mysql数据库的,因为python不支持mysql所以只能借助pymysql来实现操作mysql
import pymysql # 一定要添加这两行 # 这个pymysql不属于python内置的需要我们自己安装 pymysql.install_as_MySQLdb() DATABASES = { 'default': { 'ENGINE': 'django.db.backends.mysql', 'NAME': 'mysite', 'HOST': '192.168.244.1', 'USER': 'root', 'PASSWORD': '123456', 'PORT': '3306', } }
我们在操作数据库的时候,我们必须现在mysql中创建相应的数据库才能操作。
还有在我自己创建的app时我们需要把这个app加入到setting中,如果是用pycharm创建Django项目是就穿件的就不需要
使用命令创建的就需要加入:
INSTALLED_APPS = [ 'django.contrib.admin', 'django.contrib.auth', 'django.contrib.contenttypes', 'django.contrib.sessions', 'django.contrib.messages', 'django.contrib.staticfiles', 'app01', # 把我们创建的app01加入 ]
2、创建类
我们在相应的app中的models.py里面创建我们想要的模型,在这里面我们全是用python代码实现的不接触任何的SQL语句
app01/models.py
from django.db import models class UserInfo(models.Model): # Django会默认创建一个id列,并且是自增,主键 # 用户名列,字符串类型,指定长度 username = models.CharField(max_length=32) # 密码列,字符类型,指定长度 password = models.CharField(max_length=64)
这样创建模型后,我们需要执行相应的代码才能把这些写到相应的数据库中,也就是启动模型。
Django会做2件事。
1、创建app对应的数据库表结构
2、为我们模型里面的对象创建基于python的数据库访问API
这个执行的目录就是manage.py同目录下面。
在命令行:python3 manage.py makemigrations
通过运行makemigrations
命令,相当于告诉Django你对模型有改动,并且你想把这些改动保存为一个“迁移(migration)”。
migrations
是Django保存模型修改记录的文件,这些文件保存在磁盘上。在例子中,它就是app01/migrations/0001_initial.py
,你可以打开它看看,里面保存的都是人类可读并且可编辑的内容,方便你随时手动修改。
这里还需要我们把数据迁移到数据库里面就还需要执行
python3 manage.py migrate
这里面因为默认为SQLite,要想查看里面的数据我们可以使用Navicat Premium 12这个软件连接到SQLite
也可以直接在pycharm上查看。
点击pycharm右面的有一个database然后就有上面的画面,再把我们和manage.py同目录上面的db.sqlite3拖到这个框框里面
从上面可以看出我们能够对数据库进行相应的操作了。
上面就是在django里面模型的创建以及把模型迁移到数据库上的操作,以及查看的一些方式。
3、添加数据
使用python语句添加数据的几种方式
一、
models.UserInfo.objects.create()
from django.shortcuts import HttpResponse from app01 import models def orm(request): models.UserInfo.objects.create(username='root', password='1234') return HttpResponse('ok')
当我们访问http://127.0.0.1:8000/orm/的时候我们就会在数据库里面创建该数据
注意这里我们在urls的路由系统里面加了相应的路由配置
二、
obj = models.UserInfo()
obj.save()
from django.shortcuts import HttpResponse from cmdb import models def orm(request): obj = models.UserInfo(username='admin', password='1234') obj.save() return HttpResponse('ok')
当我们访问http://127.0.0.1:8000/orm/的时候我们就会在数据库里面创建该数据
三、
这种方式就是第一种的差不多只是我们传进去的是一个字典
from django.shortcuts import HttpResponse dic = { 'username':'qwer', 'password':'1234' } # Create your views here. from cmdb import models def orm(request): models.UserInfo.objects.create(**dic) return HttpResponse('ok')
上面的字典中的key就是我们数据库中的列,值就是列中对应的数据。
4、数据库数据的查询
查询所有:ret = models.UserInfo.objects.all()
这里得到的返回值为:<QuerySet [<UserInfo: UserInfo object (1)>, <UserInfo: UserInfo object (2)>, <UserInfo: UserInfo object (3)>]>
上面可以知道我们得到一个QuerySet数据这个和列表有点类似,我们可以通过循环获取它的数据
from django.shortcuts import render from django.shortcuts import HttpResponse # Create your views here. from cmdb import models def orm(request): ret = models.UserInfo.objects.all() print(ret) for row in ret: print(row) print(row.id,row.username,row.password) return HttpResponse('ok') ## 结果 <QuerySet [<UserInfo: UserInfo object (1)>, <UserInfo: UserInfo object (2)>, <UserInfo: UserInfo object (3)>]> UserInfo object (1) 1 root 1234 UserInfo object (2) 2 admin 1234 UserInfo object (3) 3 qwer 1234
可以看出ret是一个QuerySet数据类型,循环我们得到的是一个object对象,我们可以通过object对象获取相应的数据。
条件语句查询:result =models.UserInfo.objects.filter(username="root")
查询username为root的用户所有信息相当于数据库的where username = 'root'
这个查询出来的也是QuerySet类型的
from django.shortcuts import HttpResponse # Create your views here. from cmdb import models def orm(request): ret = models.UserInfo.objects.filter(username='root') print(ret) print(ret[0].username) return HttpResponse('ok') #结果为 <QuerySet [<UserInfo: UserInfo object (1)>]> root
上面我们可以看出查询出来的还是QuerySet数据类型,
5、删除数据
models.UserInfo.objects.delete() 删除所有数据
models.UserInfo.objects.filter(id=2).delete() 通过条件删除
6、更新数据
models.UserInfo.objects.all().update(password=222) #将所有的的密码都更改,
models.UserInfo.objects.filter(id=2).update(password=888) # 根据条件更新
ORM的一些补充
创建数据库表的有哪些字符类型中的字段的参数的意思
null -> db是否可以为空
default -> 默认值
primary_key -> 主键
db_column -> 列名
db_index -> 索引
unique -> 唯一索引
unique_for_date ->
unique_for_month
unique_for_year
auto_now -> 创建时,自动生成时间
auto_now_add -> 更新时,自动更新为当前时间
choices -> django admin中显示下拉框,避免连表查询
blank -> django admin是否可以为空
verbose_name -> django admin显示字段中文
editable -> django admin是否可以被编辑
help_text -> django admin提示
...