Django之内置组件
Django组件介绍
1.分页器的使用
分页器在页面中非常常见,当数据库条数数据过多时,页面一次性显示不好看,我们就可以使用页面器,将数据分几次显示
一个简单的分页功能,可以导入用
page_num = request.GET.get('page','')
try:
page_num = int(page_num)
if page_num <=0:
page_num = 1
except Exception as e:
page_num =1
#总数量
all_count = len(userlist)
#每页显示为10 页
per_num = 10
#总页码数
total_page_num, more =divmod(all_count,per_num)
if more:
total_page_num += 1
#最多显示的页面数
max_show = 11
half_show = max_show//2
if total_page_num < max_show:
page_start = 1
page_end = total_page_num
elif page_num <= half_show:
page_start =1
page_end =max_show
elif page_num + half_show > total_page_num:
page_start = total_page_num-max_show +1
page_end = total_page_num
else:
#起始页面
page_start = page_num - half_show
#终止页面
page_end = page_num + half_show
start =(page_num-1) * per_num
end =page_num*per_num page_list = [] if page_num == 1:
page_list.append('<li class="disabled"><a>上一页</a></li>')
else:
page_list.append('<li ><a href="?page={}">上一页</a></li>'.format(page_num - 1)) for i in range(page_start, page_end + 1):
if i == page_num:
page_list.append('<li class="active" ><a href="?page={}">{}</a></li>'.format(i, i))
else:
page_list.append('<li><a href="?page={}">{}</a></li>'.format(i, i))
if page_num == total_page_num:
page_list.append('<li class="disabled"><a>下一页</a></li>')
else:
page_list.append('<li><a href="?page={}">下一页</a></li>'.format(page_num + 1)) page_html = ''.join(page_list) return render(request, 'user_list.html',
{'users': userlist[start:end], 'page_html': page_html})
分页
2.Form组件
django框架提供了一个form类,来处理web开发中的表单相关事项.form最常做的是对用户输入的内容进行验证,为此django的forms类提供了全面的内容验证和保留用户上次输入数据的支持
form组件的两大功能:
---对用户提交的内容进行验证(from表单/ajax)
---表留用户上次输入的内容
form组件的几大用处:
1.校验字段功能
1.首先先到导入forms这个模块
from django import forms
2.自己写一个类,并继承forms.Form
class Myform(forms.Form):
#这行代码的意思,name这字段最长为8,最短为3
name=forms.charField(max_length=8) def index(request):
dic={'name':'zh'}
#这里就是类的实例化,传的参数必须为一个字典
myform =Myform(dic)
#这是对象的绑定方式,它的返回值就是一个布尔值
# True表示你传的dic这个字典满足form里的条件,False就是不满足
# 我们可以通过判断它,再进行逻辑操作,比如该字段符合你的要求,再怎么操作
if myform.is_valid():
return HttpResponse('校验成功')
# 走到这一步,代表当中有字段不符合要求
# 它的返回值是一个对象,但是它继承了字典,所以你可以通过get取到错误提示
# 对了,你传的字典的key值必须要和创建的类(Myform)要对应,并且只能多,不能少
# name_error = myform.errors.get('name')
# 这样你可以取到name字段出错的原因了
name_error=myform.errors
return HttpResponse('校验失败')
## 总结下:1、Myform的实例化必须传字典
2、is_valid()返回值是布尔类型
3、errors 调用这个方法,返回值是对象,你可以通过get取值
例子
2.渲染标签功能
form组件可以在视图函数中使用,也可以在模板中使用
渲染方式一:
<form action='' method='post'>
用户名:{{myform:name}} <br>
<input type='submit' value = '提交'></input>
</form>
# 这里的{{myform:name}} 和你写input框是一样的效果,就是属性比input框多一点 渲染方式二(推荐使用):
<form action='' method='post'>
{% for foo in myform%}
{{ foo.lable }} : {{ foo }} <br>
<input type='submit' value = '提交'></input>
</form>
# 页面显示都是一样的,foo.lable不是用户名,是name,但是你可以在创建Myform类时
# 在CharFiel中添加lable='用户名',这样就行了。 渲染方式三:
<form action='' method='post'>
{{ myform.as_p }}
<input type='submit' value = '提交'></input>
</form>
# 对,方式三就是这么简单,但是拓展性太差了,对不对,所以不推荐使用它
例子
3.渲染错误信息功能
渲染错误信息,之前不是写了error这个方法嘛,他就是装着错误信息的对象,
其实就是让它渲染到页面上,这不就是很简单嘛
拿渲染方式二来举例子吧:
<form action='' method='post'>
{% for foo in myform%}
{{ foo.lable }} : {{ foo }} <span>{{foo.errors.0}}</span><br>
<input type='submit' value = '提交'></input>
</form> # 来讲下为什么不是用get去取错误信息,首先这个foo是什么?它就是你创建的字段
# 所以直接通过索引取值就好了,那么就应该知道foo.errors貌似就是一个列表对吧
# 模板渲染时我在后台渲染好了,再返回到前台的,那我可以不可以将错误信息传到前台
# 让前台执行DOM操作进行渲染呢?
# 我觉得太麻烦,况且前端我。。。(你懂的)
例子
4.组件的参数配置
其实在些Myform,下面的字段还有很多参数,我就写写大概有什么用
max_length # 代表该字段最长为多少
min_length # 代表该字段最短为多少
error_messages # 这是设置错误信息的属性
# 例子
error_messages=
{'max_length': '最长八位', 'min_length': '最短三位', 'required': '不能为空'}
required # 默认值为True,意思是你传来的字段必须有它,没有的话校验失败
widget=widgets.TextInput() # 你在模板渲染的时候,就会渲染成Input框,type为text
还有其他类型的input框,自己在看看吧
对了,在TextInput(),你可以为input添加属性,attrs={'class':'abc'} 写在括号里面
lable #这个是不是上面讲到了,lable='用户名'
例子
5.钩子
局部钩子
局部钩子说白了就是写一个函数,但是这个函数名必须为clean_name,这个name是可以改变的,
你定义的类里,你想对哪个字段写钩子函数,这个name就为那个字段的名字,比如我想为password这个
字段写钩子函数,那函数名就为clean_password,就这样。 那这个局部钩子有什么用了?
首先你的程序能走到局部钩子这一步,就说明你传的字典中的字段符合要求,这要记清楚,那么我们在
取值就从clean_data中取就好了,clean_data里装的是符合要求的数据,是一个字典。
我们可以从clean_data中取到相应的值再做一次逻辑处理,比如我写clean_name这个局部钩子,
我可以拿到name,对这个name进行一些操作,名字开头不能是数字,名字中不能有有什么字符,这
些等等,看你自己的需求,逻辑代码写好了,最后return name 就好了 全局钩子
全局钩子其实作用差不多的,每个字段你可以进行局部钩子进行逻辑书写,这些处理完成之后,有需要的话,
你再进行全局处理,举个例子就大概能明白,你在写注册用户的时候,是不是有密码,确认密码,你可以进行
布局钩子处理,处理完毕是不是在进行判断,判断他们是否相等,相等的话,就存到数据库中,不相等就抛个
异常,对了对了,上面局部钩子忘记写异常,下面讲讲。 -----1、局部钩子,全局钩子所抛出异常的类型为ValidationError,它是在下面这行代码导入
from django.core.exceptions import ValidationError
2、局部钩子抛出的异常会添加到该字段中的错误信息中,也就是myform.errors.get(字段名)中
3、而全局钩子抛出的异常会添加到__all__中,myform.errors.get('__all__')中可以取到
说明
3.ModelForm
作用:
1.手动对单表进行增,删,改,查,手动把orm操作获取的数据渲染到模块;(阶段1)
2.Form组件(类),自动生成标签(input,select),并对用户输入的数据做规则验证;(阶段2)
3.ModelForm顾名思义就Form和Django的Model数据库模型结合体,可以简单,方便地对数据库进行增加,编辑操作和验证标签的生成
使用ModelForm
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
{{ form_obj.as_p }}
{#<p>姓名:{{form_obj.name }}</p>#}
</body>
</html>
前端
class BSForm(forms.ModelForm):
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
for filed in self.fields.values():
if not isinstance(filed, forms.BooleanField):
filed.widget.attrs.update({'class': "form-control"}) class RegForm(BSForm):
re_pwd = forms.CharField(widget=forms.PasswordInput, label='确认密码')
class Meta:
model = models.UserProfile
fields='__all__' #获取全部的
exclude=['memo','is_active'] #删除不想要的
labels = {
'username': '用户名' #标签
}
widgets = {
'password': forms.PasswordInput(attrs={'class': "form-control", 'k1': 'v1'}),
}
error_messages = {
'password': {
'required': '必填的'
}
}
def clean(self):
pwd = self.cleaned_data.get('password', '')
re_pwd = self.cleaned_data.get('re_pwd', '')
if pwd == re_pwd:
return self.cleaned_data
self.add_error('re_pwd', '两次密码不一致') raise ValidationError('两次密码不一直') def reg(request):
form_obj=RegForm()
if request.method =="POST":
form_obj=RegForm(request.POST)
if form_obj.is_valid():
# print(form_obj.cleaned_data)
# form_obj.cleaned_data.pop('re_pwd')
# models.UserProfile.objects.create(**form_obj.cleaned_data)
form_obj.save()
return redirect(reverse('login'))
return render(request,'reg.html',{'form_obj':form_obj})
后端
4.orm
--MVC框架中包括一个重要的部分,就是ORM,它实现了数据模型与数据库的解耦,即数据模型的设计不需要依赖于特定的数据库,通过简单的配置就可以轻松更换数据库
--ORM是'对象-关系-映射'的简称 ,主要任务是:
*根据对象的类型生成表结构
*将对象,列表的操作,转换为sql语句
*将sql查询到的结果转换为对象,列表
--这极大地减轻了开发人员的工作量,不需要面对因数据库变更而导致的无效劳动
--Django中的模型包含存储数据的字段和约束,对应着数据库中唯一的表
1.在models.py中定义模型类,要求继承自models.Model
2.把应用加入settings.py文件的installed_app项
3.生成迁移文件
4.执行迁移生成表
5.使用模型类进行crud操作
开发流程
在模型中定义属性,会生成表中的字段
django根据属性的类型确定以下信息:
当前选择的数据库支持字段的类型
渲染管理表单时使用的默认html控件
在管理站点最低限度的验证
django会为表增加自动增长的主键列,每个模型只能有一个主键列,如果使用选项设置某属性为主键列后,则django不会再生成默认的主键列
属性命名限制
不能是python的保留关键字
由于django的查询方式,不允许使用连续的下划线
定义模型
定义属性时,需要字段类型
字段类型被定义在django.db.models.fields目录下,为了方便使用,被导入到django.db.models中
使用方式
导入from django.db import models
通过models.Field创建字段类型的对象,赋值给属性
对于重要数据都做逻辑删除,不做物理删除,实现方法是定义isDelete属性,类型为BooleanField,默认值为False
字段类型
AutoField:一个根据实际ID自动增长的IntegerField,通常不指定
如果不指定,一个主键字段将自动添加到模型中
BooleanField:true/false 字段,此字段的默认表单控制是CheckboxInput
NullBooleanField:支持null、true、false三种值
CharField(max_length=字符长度):字符串,默认的表单样式是 TextInput
TextField:大文本字段,一般超过4000使用,默认的表单控件是Textarea
IntegerField:整数
DecimalField(max_digits=None, decimal_places=None):使用python的Decimal实例表示的十进制浮点数
DecimalField.max_digits:位数总数
DecimalField.decimal_places:小数点后的数字位数
FloatField:用Python的float实例来表示的浮点数
DateField[auto_now=False, auto_now_add=False]):使用Python的datetime.date实例表示的日期
参数DateField.auto_now:每次保存对象时,自动设置该字段为当前时间,用于"最后一次修改"的时间戳,它总是使用当前日期,默认为false
参数DateField.auto_now_add:当对象第一次被创建时自动设置当前时间,用于创建的时间戳,它总是使用当前日期,默认为false
该字段默认对应的表单控件是一个TextInput. 在管理员站点添加了一个JavaScript写的日历控件,和一个“Today"的快捷按钮,包含了一个额外的invalid_date错误消息键
auto_now_add, auto_now, and default 这些设置是相互排斥的,他们之间的任何组合将会发生错误的结果
TimeField:使用Python的datetime.time实例表示的时间,参数同DateField
DateTimeField:使用Python的datetime.datetime实例表示的日期和时间,参数同DateField
FileField:一个上传文件的字段
ImageField:继承了FileField的所有属性和方法,但对上传的对象进行校验,确保它是个有效的image
字段选项
通过字段选项,可以实现对字段的约束
在字段对象时通过关键字参数指定
null:如果为True,Django 将空值以NULL 存储到数据库中,默认值是 False
blank:如果为True,则该字段允许为空白,默认值是 False
对比:null是数据库范畴的概念,blank是表单验证证范畴的
db_column:字段的名称,如果未指定,则使用属性的名称
db_index:若值为 True, 则在表中会为此字段创建索引
default:默认值
primary_key:若为 True, 则该字段会成为模型的主键字段
unique:如果为 True, 这个字段在表中必须有唯一值
关系
关系的类型包括
ForeignKey:一对多,将字段定义在多的端中
ManyToManyField:多对多,将字段定义在两端中
OneToOneField:一对一,将字段定义在任意一端中
可以维护递归的关联关系,使用'self'指定,详见“自关联”
用一访问多:对象.模型类小写_set
定义属性
增:
models.UserInfo.object.create(name=new_name)
删:
models.UserInfo.object.get(id=xxx,None)
models.delete()
改:
obj = models.UserInfo.object.get(id=xx,None)
obj = new_xxx
obj.save() #相当于修改后提交数据
查
querylist=models.Entry.objects.all()
print([e.title for e in querylist])
print([e.title for e in querylist]) entry = models.Entry.objects.get(id=?)
orm操作
5.cookie和session
cookies是浏览器为web服务器存储的一个信息,每次浏览器从某个服务器请求页面时,都会自动带上以前收到的cookie.cookie保存在客户端,安全性较差,注意不要保存没敢信息.
--网络登录
--购物车
def login(request):
if request.method == 'GET':
return render(request,'login2.html') if request.method == 'POST':
u = request.POST.get('username')
p = request.POST.get('pwd')
dic = user_info.get(u) if not dic:
return render(request,'login2.html') current_date = datetime.datetime.utcnow() current_date = current_date + datetime.timedelta(seconds=10)
if dic['pwd'] == p:
res = redirect('/myapp/index')
# res.set_cookie('username',u,max_age=10)
#对cookie设置了超时时间和安全设置
res.set_cookie('username',u,expires=current_date,httponly=True)
# res.set_signed_cookie('username',u,salt="121221")
return res
else:
return render(request,'login2.html')
登录页面
详情页面,如果cookie 验证通过则进入index页面,否则刷新进入登录页面
def auth(func):
def inner(request,*args,**kwargs):
v = request.COOKIES.get('username')
if not v:
return redirect('/myapp/login')
return func(request,*args,**kwargs) return inner
@auth
def index(request): v = request.COOKIES.get('username') return render(request,'index2.html',{'current_user':v})
验证
session就是保存在后台数据或者缓存中的一个键值对,同样的存储着用户信息,为更好的保护用户隐私,其实是对前端cookie的一个升级的保护措施
当登录成功后,会向后台数据库 与 前端 Cookie同时发放一段随机字符串,分别保存在后台的session中,前端 写到用户浏览器中,用户下次登录时候 拿着浏览器存着的sessionID当做KEY去后台数据库中匹配进行验证登录即可拿到用户相关信息,可以防止敏感信息直接暴露在浏览器上 作者:TianTianBaby223
链接:https://www.jianshu.com/p/a2d696364501
来源:简书
简书著作权归作者所有,任何形式的转载都请联系作者获得授权并注明出处。
实现原理
Django下用session实现登录验证
def sessionLogin(request):
if request.method == "GET":
return render(request,'sessionLogin.html') elif request.method == "POST":
user = request.POST.get('user')
pwd = request.POST.get('pwd')
if user == 'root' and pwd =="":
#生成随机字符串
#写到用户浏览器
#保存到session中
#在随机字符串对应的字典中设置相关内容...
request.session['username'] = user
request.session['is_login'] = True
if request.POST.get('rmb',None) == '':
request.session.set_expiry(10) return redirect('/myapp/sessionindex')
else:
return render(request, 'sessionLogin.html')
详情页逻辑
def sessionindex(request):
#获取当前用户的随机字符串
#根据随机字符串获取对应信息
if request.session.get('is_login',None):
return render(request,'sessionindex.html',{'username':request.session['username']})
else:
return HttpResponse('get out')
6.中间件
定义:介于request(请求)与response(响应)处理之间的一道处理过程,相对比较轻量级,位于web服务端与url路由层之间
MIDDLEWARE = [
'django.middleware.security.SecurityMiddleware', #一些安全设置,比如xss脚本过滤
'django.contrib.sessions.middleware.SessionMiddleware',#session支持中间件,加入这个中间件,会在数据库中生成一个django_session的表。
'django.middleware.common.CommonMiddleware', #通用中间件,会处理一些url
'django.middleware.csrf.CsrfViewMiddleware', #跨域请求伪造中间件,加入这个中间件,在提交表单的时候会必须加入csrf_token,cookie中也会生成一个名叫csrftoken的值,也会在header中加入一个HTTP_X_CSRFTOKEN的值来放置CSRF攻击。
'django.contrib.auth.middleware.AuthenticationMiddleware', #用户授权中间件。他会在每个HttpRequest对象到达view之前添加当前登录用户的user属性,也就是你可以在view中通过request访问user。
'django.contrib.messages.middleware.MessageMiddleware',#消息中间件。展示一些后台信息给前端页面。如果需要用到消息,还需要在INSTALLED_APPS中添加django.contrib.message才能有效。如果不需要,可以把这两个都删除。
'django.middleware.clickjacking.XFrameOptionsMiddleware',#防止通过浏览器页面跨Frame出现clickjacking(欺骗点击)攻击出现。
'A_orm.middlewares.auth.AuthenticationMiddleware',
]
内置中间件
请求进来是自上而下,通过反射找到类,用for循环来执行,可以自定义中间件,但也要写入MIDDLEWAR中
1、process_request(self,request)
#请求完执行 2、process_view(self, request, callback, callback_args, callback_kwargs)
#如果有返回值,跳转到最后一个中间件,执行最后一个中间件的response方法,逐步返回
3、process_template_response(self,request,response)
#默认不执行,只有在视图函数的返回对象中有render方法才会执行
4、process_exception(self, request, exception)
#默认啥也不执行,在视图函数出现错误是才执行,返回错误信息
5、process_response(self, request, response)
#响应执行
自定义中间件
1、做IP限制 放在 中间件类的列表中,阻止某些IP访问了; 2、URL访问过滤 如果用户访问的是login视图(放过) 如果访问其他视图(需要检测是不是有session已经有了放行,没有返回login),这样就省得在 多个视图函数上写装饰器了! 3、缓存(还记得CDN吗?) 客户端请求来了,中间件去缓存看看有没有数据,有直接返回给用户,没有再去逻辑层 执行视图函数
应用场景
执行顺序:
1.我们要在app01文件下创建一个文件(middlewares)文件,在下面创建一个.py文件写入自定义中间件
2.在setting里面添加中间件,文件路径+功能
3.在views.py你们调用即可.
def index(request):
print('')
7.信号
定义:用于框架执行操作时解耦,就是一些动作发生的时候,信号允许特定的发送者去提醒一些接受者
Model signals
pre_init # django的model执行其构造方法前,自动触发
post_init # django的model执行其构造方法后,自动触发
pre_save # django的model对象保存前,自动触发
post_save # django的model对象保存后,自动触发
pre_delete # django的model对象删除前,自动触发
post_delete # django的model对象删除后,自动触发
m2m_changed # django的model中使用m2m字段操作第三张表(add,remove,clear)前后,自动触发
class_prepared # 程序启动时,检测已注册的app中modal类,对于每一个类,自动触发
from django.db.models.signals import pre_init, post_init
from django.db.models.signals import pre_save, post_save
内置信号
Management signals
pre_migrate # 执行migrate命令前,自动触发
post_migrate # 执行migrate命令后,自动触发
数据库迁移的时候信号
Request/response signals
request_started # 请求到来前,自动触发
request_finished # 请求结束后,自动触发
got_request_exception # 请求异常后,自动触发
from django.core.signals import request_finished
from django.core.signals import request_started
请求和响应的信号
setting_changed # 使用test测试修改配置文件时,自动触发
template_rendered # 使用test测试渲染模板时,自动触发
from django.test.signals import setting_changed
from django.test.signals import template_rendered
Test signals
connection_created # 创建数据库连接时,自动触发
from django.db.backends.signals import connection_created
Database Wrappers
Django之内置组件的更多相关文章
- 76、django之内置Admin
本篇导航: 配置路由 定制Admin Django内置的Admin是对于model中对应的数据表进行增删改查提供的组件,使用方式有: 依赖APP: django.contrib.auth django ...
- django之内置Admin
本篇导航: 配置路由 定制Admin Django内置的Admin是对于model中对应的数据表进行增删改查提供的组件,使用方式有: 依赖APP: django.contrib.auth django ...
- Django:内置组件Content-Type
12.Django组件之Content_Type 1.帮助我们生成了一张表,里面有所有表名.这样不再自建表在表中填表名,用Foreignkey获取 2.为了让我们快速进入插入数据,填写一个字段Gene ...
- django内置组件——ContentTypes
一.什么是Django ContentTypes? Django ContentTypes是由Django框架提供的一个核心功能,它对当前项目中所有基于Django驱动的model提供了更高层次的抽象 ...
- Django之内置分页器(paginator)
django分页: from django.shortcutsimportrender from django.core.paginator import Paginator,EmptyPage, P ...
- Django 学习之内置Admin
一.Admin组件 Django内置的Admin是对于model中对应的数据表进行增删改查提供的组件,使用方式有: Django Admin内部依赖: 依赖APP: django.contrib.au ...
- Django之Form组件
Django之Form组件 本节内容 基本使用 form中字段和插件 自定义验证规则 动态加载数据到form中 1. 基本使用 django中的Form组件有以下几个功能: 生成HTML标签 验证用户 ...
- Python之路【第二十一篇】:Django之Form组件
Django之Form组件 Django的Form主要具有一下几大功能: 生成HTML标签 验证用户数据(显示错误信息) HTML Form提交保留上次提交数据 初始化页面显示内容 小试牛刀 1. ...
- 第十一篇:web之Django之Form组件
Django之Form组件 Django之Form组件 本节内容 基本使用 form中字段和插件 自定义验证规则 动态加载数据到form中 1. 基本使用 django中的Form组件有以下几个功 ...
随机推荐
- excel2013做数据透视表
excel2013做数据透视表 Excel最新版更新到2013,相比2003.2007和2010,2013的excel界面方面有一定变化,在操作方面也有一定的便捷性.那么如何使用excel20 ...
- CesiumLab V1.3 新功能 MAX场景处理(免费Cesium处理工具集)
每次到写文章的时候就很高兴,意味着又有重大功能更新了,也意味着10多天昏天黑地的闭关日子暂时结束了. 依照惯例,先放图 小范围精模型cesium加载效果 大范围白模cesium加载效果 ...
- js 百度地图和谷歌地图的选择
最近手上接到一个需求: 国外的域名访问,显示谷歌地图 国内的域名访问,显示百度地图 切换中英文的时候,中文->显示百度地图,英文->能显示谷歌地图就显示谷歌地图,不能显示(报错)就显示百度 ...
- vue前后端分离
axios前后端交互 安装 一定要安装到`项目目录下 cnpm install axios 配置 在main.js中配置 //配置axios import axios from 'axios' Vue ...
- fidder抓包使用(一)
fidder是会占用 jupyter 端口的,在fidder里边最上边找到tools--->options-->connections里边的8888改成别的重启jupyter就好了
- agc015D A or...or B Problem
题意:求用若干个(至少一个)[A,B]中的数进行or操作能得到多少本质不同的数 $1 \leq A \leq B < 2^{60}$ 一直在想数位dp,看了题解之后感觉自己就是个sb 我们先把$ ...
- web前端学习(二)html学习笔记部分(11)-- 没有标号记录的知识合集
这一部分内容相对比较简单,就不按规矩排序了.(主要是网站上也没有这一部分内容的排序) 1. html5的 非主体结构元素 学习笔记(1)里面记录过. 2. html5表单提交和PHP环境搭建 1. ...
- Sass @at-root (1)
在SassConf大会上,给我们传递了Sass3.3的新特性.这些新特性有很多意义,特别是@at-root指令,这让你的代码会得更佳清洁. 今天我们主要一起来了解Sass中的@at-root特性的使用 ...
- PHP队列类
/** * Created by PhpStorm. * User: LAMP-Q哥 * Date: 2017/8/3 * Time: 12:58 */ class Queue { private $ ...
- mysql5.7以上版本安装
首先下载mysql5.7zip版本 https://dev.mysql.com/downloads/mysql/5.7.html#downloads 然后放在本地解压 下载5.6版本 https:// ...