Contents
Django学习
为什么使用Django
Django诞生于新闻网站的环境中,它所提供的特性非常适合开发内容类的网站(例如:博客,交流社区,图片分享站等等……)。因为Django是在快节奏的新闻编辑环境中开发的,它的设计目的是使常见的Web开发任务变得快速而简单。
Django是开源的,不是商业项目或者科研项目,它集中力量解决Web开发中所遇到的一系列问题。因此,Django每天都在现有的基础上进步,以适应不断更迭的开发需求。这样即节省了开发时间,也提高了后期维护的效率。
请求接受处理的过程
- django加载ROOT_URLCONF指定的模块,并且寻找可以使用的urlpatterns,它为django.conf.urls.url()实例的一个Python列表
-
Django依次匹配每一个URL,在与请求的URL匹配的第一个URL地方停下
-一旦其中的一个正则表达式匹配上,Django将导入并且调用给视图,它是一个简单的Python函数(或者是一个基于类的视图)
- 如果没有匹配到正则表达式,或者如果过程中抛出一个异常,Djang将会调用一个适当的错误处理视图:handler404,handler500,handler403,handler400
参数一 -> 一个HttpRequest实例
参数二 -> 如果匹配的正则表达式返回了没有命名的组,那么正则表达式匹配的内容将作为位置参数提供给视图使用
参数三 -> 关键子参数由正则表达式匹配的命名组组成,但是可以被djan.conf.urls.url()的可选参数Kwargs覆盖
**安装相关PIP**
```centos
pip3 install django mysqlclient ConfigParser MySQL-python MySQLdb pymysql
sudo apt-get install libmysqlclient-dev libmysqld-dev python-dev python-setuptools
vim __init__.py
import pymysql
pymysql.install_as_MySQLdb()
python开启虚拟环境
/usr/local/python36/bin/virtualenv ./python36env
source python36env/bin/activate
- 最外层的opsweb目录只是你的项目的一个容器
-
manage.py一个实用的命令工具,可以让你以各种的方式与该Django项目进行交互
-
内层的opsweb目录是你项目中的实际Python包,通过它你可以导入它里面的任何东西
-
opsweb/init.py 一个空文件,告诉Python该目录是一个Python包
-
opsweb/settings.py 该Django项目的配置文件
-
opsweb/urls.py 该Django项目的配置文件
-
opsweb/wsgi.py 一个WSGI兼容的WEB服务的入口
启动服务
python manage.py runserver [IP:PORT] #可以指定指定ip和端口
配置Djingo的数据库
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.mysql',
'NAME': 'django',
'USER': 'root',
'PASSWORD': '123456',
'HOST': '127.0.0.1',
'PORT': '3306',
}
}
28 ALLOWED_HOSTS = ["*"] #运行任何人访问
新建Django app实现自己的Hello world
1.新建一个名字为dashboard的app
python manage.py startapp dashboard
2.配置django的入口url设置路由
vim /opsweb/opsweb/urls.py
from django.conf.urls import include,url
urlpatterns = [
path('admin/', admin.site.urls),
url(r'^dashboard/',include("dashboard.urls")), #如果当有以dashboard开头的都以dashboard.urls这个模块去处理
]
3.激活配置
vim /ops web/opsweb/settings.py
INSTALLED_APPS = [
dashboard,
]
4.编写Hello world
vim ./dashboard/views.py
from django.http import HttpResponse
def index(request): #接受一个HTTP的请求返回一个HttpResponse对象
return HttpResponse("Hello world!!! 你好!!")
5.创建dashboard的urls
vim ./dashboard/urls.py
from django.conf.urls import include,url
from . import views
urlpatterns = [
url(r'^',views.index,name='index'), #如果以为^就是为空,则views.index去处理
]
6.展示图
HttpRequest对象
传递一个字符串作为页面的内容到HttpResponse构造函数
- 属性常用的
名称 | 作用 |
---|---|
HttpRequest.scheme | 请求的方式 |
HttpRequest.body | |
HttpRequest.path | 请求访问主机的什么路径 |
HttpRequest.method | |
HttpRequest.encoding | |
HttpRequest.GET | |
HttpRequest.POST | |
HttpRequest.META | |
HttpResponse.content | |
HttpResponse.charset | |
HttpResponse.status_code | |
HttpResponse.reason_phrase |
- 方法
HttpRequest.get_hos()
HttpRequest.get_port()
HttpRequest.get_full_path()
HttpRequest.is_secure()
HttpRequest.ajax()
JsonResponse对象
from django.shortcuts import render
# Create your views here.
from django.http import HttpResponse,JsonResponse
def index(request):
d={"这是一个字典":"好的我知道了"}
c=["json","python","golang","reboot"]
return JsonResponse(c,safe=False)
第一步:urls.py
from django.contrib import admin
from django.conf.urls import url,include #加上include
urlpatterns = [
url('admin/', admin.site.urls),
url(r'^dashboard/',include("dashboard.urls")), #标准写法
]
第二步:settings
INSTALLED_APPS = [
'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
'dashboard.apps.DashboardConfig', #加上这句
]
编写视图
编写初始化 -> views
from django.http import HttpResponse
def index(request): #和普通函数的区别是它接收一个request参数
return HttpResponse("This is dashboard") #无论函数多么复杂必须返回一个这样的参数参数否则报错
配置URL
from django.conf.urls import url
from .views import index
urlpatterns = [
url(r'^hello',index,name='index')
]
- 请求方式: 请求路径: 方法:
如何返回JSON字符串
from django.http import HttpResponse,JsonResponse
import json
def index(request):
data = {
"name": "rock",
"age": 25,
}
data_1 = ["devops","python"]
#通过指定转化的类型实现
return HttpResponse(json.dumps(data_1),content_type="application/json")
#通过调用Json模块,默认接受Dir,传输列表必须safe=False
return JsonResponse(data)
return JsonResponse(data_1,safe=False)
加载模板
模板就是要让数据看起来更加的美观
- djang.template.loader这个模块提供了两种方式加载模板
get_template(template_name,using=None)
- 加载制定模板并且返回Template对象
select_template(template_name_list,using=None) #与get_template类似,它尝试每一个名称并且返回第一个存在的模板
- 从文件加载内容
1-> views.py
from django.template import Context,loader,Template
def index.template(request):
t = loader.get_template("test.html")
context = {"name":"hello 123"}
return HttpResponse(t.render(context,request)) #render读取变量的Key值去html文件中逐行读取替换变量
----------------------方式二封装代码简洁-----------------------------
from django.shortcuts import render
def index.template(request):
context = {"name": "hello 1111!!"}
return render(request,"test.html",context)
2-> create a directory -> templates -> test.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
你好欢迎回来
{{ name }}
</body>
</html>
QueryDict对象
- 在HttpRequest对象中,Get和Post属性是django.http.QueryDict的实例,它是一个自定义的类似字典的类,用来处理同一个健带有多个值,这个类的需求来自某些HTML表单元素传递多个值给同一个健
-
request.POST和request.GET的QueryDict在一个正常的请求响应循环中是不可变的,若要获得可变的版本就需要使用.copy()
from django.http import HttpResponse,JsonResponse
from django.template import Context,loader,Template
from django.shortcuts import render
def index(request):
if request.method == "GET":
name = request.GET.get("name")
print(request.GET)
print(name)
elif request.method == "POST":
print(request.POST)
return HttpResponse("123")
问题
- 明明传入的参数是两个但是显示的是最后一个,为什么?
因为默认获取回来K/V值中的value是列表,get方法只获取最后一个会丢失数据,但是使用Getlist就不会丢失数据
def index(request):
if request.method == "GET":
name = request.GET.get("name")
print(request.GET,"-->",name)
print(request.GET,"-->",request.GET.getlist("name"))
return HttpResponse("123")
实例化
QueryDict.__init__(query_string=None, mutable=False, encoding=None)
- 通过fromkeys实例化QueryDict (1.11新增)
classmethod QueryDict.fromkeys(iterable, value=”, mutable=False, encoding=None)
ueryDict方法
QueryDict.get(key, default=None)
QueryDict.setdefault(key, default=None)[source]
QueryDict.update(other_dict)
QueryDict.items()
QueryDict.values()
QueryDict.copy()
QueryDict.getlist(key, default=None)
QueryDict.setlist(key, list_)[source]
QueryDict.appendlist(key, item)
QueryDict.setlistdefault(key, default_list=None)
QueryDict.lists()
QueryDict.pop(key)
QueryDict.popitem()
QueryDict.dict()
QueryDict.urlencode(safe=None)
创建用户
方式一
->python3 manage.py shell #进入ipython模式
In [1]: from django.contrib.auth.models import User
In [2]: ?User.objects.create_user
Signature: User.objects.create_user(username, email=None, password=None, **extra_fields)
Docstring: <no docstring>
File: /opsweb/python3env/lib/python3.6/site-packages/django/contrib/auth/models.py
Type: method
In [3]: User.objects.create_user("ddy","ddy@qq.com","123456")
Out[3]: <User: ddy>
方式二
- python3 manage.py createsuperuser
修改密码
Django不会在user模型上存储原始密码(明文密码)而是一个哈希,因为这个原因不要去尝试直接操作user的password密码,这也是为什么创建一个user时候要使用辅助函数
>from django. contrib. auth. models import User
>u=User. objects. get(username='ddy')
>u. set_password('123456')
>u. save()
- 查询用户信息
python3 manage.py dbshell #进入数据库
show tables;
select * from auth_userG; #格式化输出字段
用户的检测
- 错误示范正常是不会这么去写的
-> 1.urls.py
urlpatterns = [
url(r'^user_login/',user_login), #加上转发这句
]
__________________________________________________________________________
-> 2.template/user_login.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>用户登入</title>
</head>
<body>
<ul>
<form method="get" action="#"> #post
<li>用户名:<input type="text" name="username"></li>
<li>密码: <input type="password" name="password"></li>
<li><input type="submit"></li>
</form>
</ul>
</body>
</html>
__________________________________________________________________________
-> 3.views.py
from django.contrib.auth.models import User
from django.contrib.auth import login,logout
def index_template(request):
# t = loader.get_template("test.html")
# context = {"name":"hello 1111!!"}
# return HttpResponse(t.render(context,request))
context = {"name": "hello 1111!!"}
return render(request,"test.html",context)
def user_login(request):
print(request.GET)
#1 -> 获取用户提交过来的用户名
username = request.GET.get("username")
#2 -> 根据用户名从数据库中取出这条记录是否存在,出现的异常错误捕获异常,否则异常导致崩溃
try:
p = User.objects.get(username=username)
except User.DoesNotExist:
pass
except User.MultipleObjectsReturned:
pass
except Exception as e:
print(e.args)
#3 -> 不存在/存在
#4 -> 存在判断密码是否一至
p.check_password()
正确示范
-> 3.views.py
def user_login(request):
print(request.GET)
#1 -> 获取用户提交过来的用户名
username = request.GET.get("username")
password = request.GET.get("password")
#2 -> 根据用户名从数据库中取出这条记录是否存在
user_obj = authenticate(username=username,password=password)
if user_obj:
login(request,user_obj)
print("登入成功")
else:
print("登入失败")
return render(request,"user_login.html")
- session和数据库中的比对一致
如何处理其他请求
- 例如DELETE请求
-> user_login.html
<form method="DELETE" action="#">
--------------------------------------------
-> views.py
elif request.method == "DELETE":
print(request.GET)
print(request.POST)
print(QueryDict(request.body))
print("delete request")
--------------------------------------------
-> curl -XDELETE http://127.0.0.1:8080/dashboard/user_login/ -d username=root -d password=123456
URL路由
对于高质量的WEB应用来说,使用简洁、优雅的URL路由是一个非常重视的细节Django可以随心所欲的设计你的URL,不收到框架的约束
只需要创建一个Python模块,URLconf,这个模块是PY编写包含简单的正则表达式到Python函数的简单映射
Url函数
- url(regex,view,lwargs=None,name=None)
- regex -> 一个字符串(原始字符串)或者简单的正则表达式
-
view -> 该参数是一个视图函数或者as_view()结果<基于类的视图>
-
kwargs -> 传递额外的参数给视图
-
name -> url名称
位置参数
想要从Get上来的URL中捕获一个数值,只需要在它的周围方式一对圆括号就可以从位置变量中获取相应的值
-> views.py
def articles(request,*args,**kwargs):
return HttpResponse(args)
-----------------------------------------
-> urls.py
urlpatterns = [
url(r'^articles/(2018)/$',articles)
]
写法例子
from django.conf.urls import url
from . import views
urlpatterns = [
url(r'^xxx/2018/$',视图),
url(r'^xxx/([0-9]{4})/$',视图),
url(r'^xxx/([0-9]{4})/([0-9]{2})/$',视图),
url(r'^xxx/([0-9]{4})/([0-9]{2}/[0-9]+)/$',视图),
]
视图函数不变的写法
def view(request,*args,**kwargs):
return HttpResponse("123")
- *args 位置参数
-
**kwargs 环境参数
关键字参数
特殊的参数需要传一个变量名到url里面去
语法: (?ppattern)
- name -> 是传给视图参数的名字
-
pattern是一个正则表达式,也是关键字参数的值
from django.conf.urls import url
from . import views
urlpatterns = [
url(r'^xxx/(?p<year>[0-9]{4})/$',视图),
url(r'^xxx/(?p<year>[0-9]{4})'/(?p<month>[0-12]{1}),视图),
url(r'^xxx/(?p<year>[0-9]{4})'/(?p<month>[0-12]{1})/(?p<day>[0-9]{2}),视图),
]
--> client
--> 请求地址: /bolg/2018/11/22
--> 调用函数: views.year_archive(request,year='2018',month='11',day='22',foo=bar)
include函数
include(module, namespace=None, app_name=None)
include(pattern_list)
include((pattern_list, app_namespace), namespace=None)
include((pattern_list, app_namespace, instance_namespace))
-
module:URLconf模块
-
namespace:URL命名空间项目大的时候才会使用上
-
app_name:app的命名空间
-
pattern_list:可以迭代的django.conf.urls.url()实例对象
-
instance_namespace:实例的命名空间
使用方式一
urlpatterns = [
url( r'^$', RedirectView.as_view(url="/dashboard/")),
url(r'^dashboard/', include("dashboard.urls")),
url(r'^accounts/', include("accounts.urls")),
url(r'^admin/', admin.site.urls),
]
使用方式二
urlpatterns = [
url(r"^user/", include([
url(r'^list/$', view.userlist, name="user_list"),
url(r'^info/$', view.userinfo, name="userer_inf),
url(r'^modify/', include([
url(r'status/$',view.modifystatus, name="user_modify_status"),
]))
]))
]
视图
View
- 属性:
- http_method_names
- 方法:
- as_view()
-
dipatch()
-
http_method_not_allowed()
基于类的视图
- 简单说视图就是python的函数
-
视图是一个可调用的对象,它接受一个请求然后返回一个响应,这个可调用的对象可以不只是函数,Django提供一些可用做视图的类
-
基于类的视图使用Python对象实现视图,它提供除了函数视图之外的另外一种方式
简单的实现
-> view.py
from django.views import View
class MyView(View):
def get(request,*args,**kwargs):
return HttpResponse("123")
---------------------------------------
-> urls.py
from . view import MyView
urlpatterns = [
url(r'^test/',MyView.as_view()),
]
类视图的登入验证写法
from django.contrib.auth.decorators import login_required
from django.utils.decorators import method_decorator
class FooView(View):
@method_decorator(login_required)
def get(request, *args, **kwargs):
return HttpResponse("hello world")
数据的分页
举例子:当前有user => 1000条
每10个信息是一个页面对于数据库是如何操作的?
select * from user limit 0,10 -> 第一页
select * from user limit 11,20 -> 第二页
select * from user limit 21,30 -> 第三页
对于代码上我们使用:
User.objects.all()[0:10] -> 依次类推
实验前期准备
- 谷歌浏览安装Jsonview:https://blog.csdn.net/keketrtr/article/details/77837185
-
创建1000用户
-
每十人分片一次
-
取相应的值
-
网页打印Json
-> urls.py
urlpatterns = [
url(r'^test/',MyView.as_view()),
]
-----------------------------------------------------
-> views.py
class MyView(View):
def get(request,*args,**kwargs):
try:
page = int(request.GET.get("page"))
except:
page = 2
end = page * 10
start = end -10
queryset = User.objects.all()[start:end]
data = list(queryset.values("id","username","email","password"))
return JsonResponse(data,safe=False)
django分页用法
- Paginator对象 、Page对象常用在分页中
Pageinator
- Required arguments
- object_list
-
per_page
-
Optional arguments
- orphans
-
allow_empty_frist_page
class Paginator(object_list,per_page,orphans=(),allow_empty_first_page=True)
属性:
-> Pageinator.count 所有页面的objects总数
-> Pageinator.num_pages 页面总数
-> Pageinator.page_range 页码的范围,从1开始[1,2,3,4]
方法:
- paginator.page(number)返回一个page对象,number当前显示的是第几页
- Page class Page(object_list,number,paginator)
属性
-Page.object_list当前页面的对象列表
-Page.number当前页的序号,从1开始
-Page.paginator Paginator对象
方法
-> Page.has_next() 如果有下一页,返回True
-> Page.has_previous() 如果有上一页,返回True
-> Page.has_other_pages() 如果有上一面或下一页,返回True
-> Page.next page_number() 返回下一页的页码。如果不存在,抛出InvalidPage异常
-> Page.previous_page_number() 返回上一页的页码。如果不存在,抛出InvalidPage异常
-> Page.start_index() 返回当前页上的第一个对象,相对于分页列表的所有对象的序号
-> Page.end_index() 返回当前页上的最后一个对象,相对于分页列表的所有对象的序号
#urls.py
urlpatterns = [
url(r'^test/',MyView.as_view()),
]
#view.py
from django.views import View
class MyView(View):
def get(request,*args,**kwargs):
page = 10
try:
page = int(request.request.GET.get("page"))
except:
page = 1
end = page * 10
start = end - 10
queryset = User.objects.all()[start:end]
data = list(queryset.values("id","username","email","password"))
return JsonResponse(data,safe=False)
Django日志
Django使用的python内建的logging模块打印日志,Python的logging由4个部分组成
- 记录器 – logger
-
处理程序 – handler
-
过滤器 – Filter
-
格式化 – Formatter
记录器
Logger为日志系统的入口,每一个Logger命名都是bucket,可以向这个bucket写入需要处理的消息,每一个logger都有一个日志级别,日志级别表示该logger将要处理的消息的严重性
- DEBUG:用于调试目的的底层系统信息
-
INFO:普通的系统信息
-
WARNING:表示出现一个较小的问题。
-
ERROR:表示出现一个较大的问题。
-
CRITICAL:表示出现一个致命的问题。
写入logger的每条消息都是一条日志。每条日志也具有一个日志级别,它表示对应的消息的严重性。每个日志记录还可以包含描述正在打印的事件的元信息。当一条消息传递给logger 时,消息的日志级别将与logger的日志级别进行比较。如果消息的日志级别大于等于logger 的日志级别,该消息将会往下继续处理。如果小于,该消息将
被忽略。Logger 一旦决定消息需要处理,它将传递该消息给一个Handler
日志的级别
级别 | 数值 | 描述 |
---|---|---|
CRITICAL | 50 | 关键错误消息 |
ERROR | 40 | 错误消息 |
WARNING | 30 | 警告消息 |
INFO | 20 | 通知消息 |
DEBUG | 10 | 调试消息 |
NOTSET | 0 | 无级别消息 |
Logger配置
logger 对应的值是个字典,其每一个键都是logger的名字,每一个值又是个字典,描述了如何配置对应的Logger实例。
- level (可选的)。logger的级别。
-
propagate (可选的)。logger的传播设置。
-
lters(可选的)。logger的lter的标识符的列表。
-
handlers (可选的)。logger的handler的标识符的列表。
推荐深入网址
- https://yiyibooks.cn/xx/python_352/library/logging.html#logger-objects
例子实例:
LOGGING = {
'loggers': {
'reboot': {
'handlers': ['file_handler', 'console_handler'],
'level': 'DEBUG',
},
},
}
django的模型
什么是模型
django想拿到数据必须去找模型,模型是数据的唯一权威的信息源,它包含所有存储数据的必要字段和行为,每一个模型对应的数据库中的唯一的一张表
如何编写模型
- 模型 -> 每一个模型都是用一个类表示,该继承自django.db.models.Model,每一个模型都有多个类的属性变量,而且每一个类的属性变量又代表了数据库表中的一个字段
-
字段 -> 每一个字段通过Field实例来表示,如字符字段CharField和日期字段DateTimeField,这样的方法告诉Django,每一个字段中保存的是什么类型的数据
-
字段名 -> 每一个Field实例的名字,就是字段的名字并且是机器可以去读取格式,Python代码中可以使用它并且数据库将会把它作用表的列名
-
https://docs.djangoproject.com/en/1.11/ref/models/fields/#field-types
自增主键字段
- 默认情况下Django会自动给每一个模型添加字段
id = models.AutoField(primary_key=True)
- 如果Django发现设置了Filed.primary_key,就不会自动加ID列
-
每一个模型只能有一个字段指定primary_key=True
字段的选项
每一个字段都有一些特定的参数CharField这种需要max_length指定varchar数据库的字段大小
- null -> 如果为True,Django将会用Null来在数据库中存储空值,defaults=False
-
blank -> 如果为Ture该字段运行不填写,defaults=False -> null是纯数据库范畴,而blank是数据库验证范畴
-
choices
由二元组组成的一个可以迭代对象(元祖或列表),用来给字段提供选项,如果设置了choices,默认的表单就会是一个选择框,选择框的选择就是choices中的选项
school_choces = (
{'BJ','diwu'},
{'SH','diliu'},
{'GZ','diqi'},
)
- default -> 字段的默认值,可以为一个值或者调用的对象
-
primary_key -> 如果为True,那这个字段就是模型的主键
-
unique -> 如果这个值为True,这个字段的值在整张表中必须是唯一的
-
更多参数项: https://docs.djangoproject.com/en/1.11/ref/models/fields/#field-options
模型meta
模型元数据是 -> 任何不是字段的数据
排序选项(ordering),数据库表名(db_table)
在模型中添加class Meta是完全可以选的,所有选项都不是必须的
使用内部的class Meta定义模型的元数据
from django.db import models
class User(models.Model):
username = models.IntegerField()
class Meta:
ordering = ["username"]
- bd_table
db_table是用于指定自定义数据库表名的,Django有一套默认的按照一定规则生成数据的模型对应的数据库的表名,如果需要使用自定义的表名,使用这个属性指定
如果不提供参数,Django会使用app_label + module_name作为表的名字
class Meta:
db_table = "server_name"
- Django会根据模型类的名称和包含它的应用的名称自动指定数据库表名称,由这个模型的应用名和模型类名称之间加上下划线组成
-
使用Meta类中的db_table参数来重写数据表的名称
-
当通过db_table覆写表名称时候,应该使用小写字母给表命名
Meta选择 -> oder
- oder字段 -> 让Django模型的对象返回的记录结果集按照哪个字段排序
class Meta:
ordering = ['-order_date']
字段参数 | 简述 |
---|---|
ordering=[‘order_date’] | 按订单升序排列 |
ordering=[‘-order_date’] | 按订单降序排列,-表示降序 |
ordering=[‘?order_date’] | 随机排序,?表示随机 |
ordering=[‘-pub_date,’author’] | 对pub_date降序,然后对author升序 |
django的迁移
迁移是Django用于同步已经发生改变的模型(添加一个字段,删除一个模型)写入到数据库的过程
- makemigrations:负责基于模型修改创建一个新的迁移
-
migrate:负责执行迁移以及撤销和列出迁移的状态
-
sqlmigrate:展示迁移的sql语句
生产迁移文件
python3 manage.py makemigrations <参数> #不加参数默认扫描所有的目录,解释:扫描和比较你当前迁移文件里面的版本,同时新的迁移文件会被创建
- python3 mange.py migrate dashboard <版本号> #不加版本号默认全部