今天开始学习Django,再此记录一下学习过程以便过后复习查看
一、部署Django
1.安装
pip install django
2.生成Django
首先尽量没有中文路径的Django
"D:\Ananconda3\Anaconda\Scripts\django-admin.exe" startproject 项目名称
# 如果"D:\Ananconda3\Anaconda\Scripts\"已经加入环境变量
django-admin.exe startporject 项目名称
创建成功截图:
3.文件说明
WMS
│─manage.py [项目的管理、启动、创建APP][无需修改,经常使用]
│
└─WMS [项目名同名文件夹]
│─asgi.py [接受网络请求][无需修改]
│─settings.py [配置文件][数据库配置,时区,安装的APP,中间件,日志配置,以及一些基本的目录配置]
│─urls.py [包含一个urlpatterns变量,其实它就是一个URLDispacher(URL分派器),用于在URL和实际的view之间建立一个映射]
│─wsgi.py [接受网络请求][无需修改]
└─__init__.py [说明内部的WMS目录是一个python模块]
二、APP概念
1、作用
APP相当于一个相对独立的功能模块,其遵循的设计理念是MVT(类似MVC);在一个大型的Project中,可以包含很多APP,而且每个APP可以在不同的Project中复用,这也符合Django的编程理念,即:不要做重复的事情。
并且每个APP都有独立的表结构、函数、HTML模板、CSS
2、创建
python manage.py startapp app名称
3、APP目录结构
wmsapp
│ admin.py [无需修改][默认提供的admin后台]
│ apps.py [无需修改]
│ models.py [操作数据库,ORM]
│ tests.py [无需修改][单元测试]
│ views.py [URL Dispacher即将URL请求映射到这个文件中的函数或类方法上]
│ __init__.py [说明polls目录是一个python模块]
│
└─migrations [记录数据库变更]
__init__.py
三、项目部署
1.注册APP
# /WMS/settings.py
INSTALLED_APPS = [
"django.contrib.admin",
"django.contrib.auth",
"django.contrib.contenttypes",
"django.contrib.sessions",
"django.contrib.messages",
"django.contrib.staticfiles",
"wmsapp.apps.appconfig", <---插入,即注册成功
]
2.编写url与视图函数的关系
# /WMS/urls.py
from wmsapp import views
urlpatterns = [
# path("admin/", admin.site.urls),
# www.xxx.com/index/
path("index/", views.index),
]
3.编写视图函数
# wmsapp/views.py
from django.shortcuts import render,HttpResponse
def index(request):
return HttpResponse("欢迎使用Django!")
4.启动Django
1、代码启动
python manage.py runserver
2、项目启动
运行成功
5、创建页面
wmsapp/ 新建templates文件夹
根据app的注册顺序,注意搜索他们templates下的文件
6、静态文件
wasapp/ 新建static文件夹,下存放CSS、js、图片
引入:
7.模板语法
基本模板语法
# wmsapp/views.py
def user_list(request):
n1 = "lisi"
n2 = ["zhangsan","wangwu","xiaoming"]
n3 = {"mingzi":"lizhi","nianling":30,"zhiwei":"laoban"}
return render(request,"user_list.html",{"n1":n1,"n2":n2,"n3":n3})
user_list.html
<span>{ { n3 } }</span>
<span>{ { n3.mingzi } }</span>
<span>{ { n3.nianling } }</span>
<span>{ { n3.zhiwei } }</span>
<div>
{ % for item in n3.keys % }
<span>{ { item } }</span>
{ % endfor % }
</div>
<div>
{ % for item in n3.values % }
<span>{ { item } }</span>
{ % endfor % }
</div>
<div>
{ % for k,v in n3.items % }
<span>{ { k } } = { { v } }</span>
{ % endfor % }
</div>
<hr>
<div>
{ % if n1 == "lisi" % }
<span>n1是lisi</span>
{ % else % }
<span>n1不是lisi</span>
{ % endif % }
</div>
四、ORM数据库操作
1.安装mysqlclient
pip install mysqlclient
windows系统安装错误的可以进入mysqlclient下载安装包安装
2.ORM
- 无需写sql语句
- 可以增删改查数据表
- 无法创建数据库(需要手动创建)
3.连接数据库
WMS/settings.py 将databases修改为下面的代码
DATABASES = {
"default": {
"ENGINE": "django.db.backends.mysql",
"NAME": "wmsdb",
"USER": "root",
"PASSWORD": "root",
"HOST": "127.0.0.1",
"POST": 3306,
}
}
4.ORM编辑表
1.创建表
wmsapp/Models.py
class UserInfo(models.Model):
name = models.CharField(max_length=32)
password=models.CharField(max_length=64)
age=models.IntegerField()
如上代码等同于在数据库里执行:
create table app01 userinfo(
id bigint auto_increment primary key,
name varchar(32),
password varchar(64),
age int,
)
python manage.py makemigrations
python manage.py migrate
2.删除表
注释不需要的字段或表,并执行> python manage.py makemigrations > python manage.py migrate 命令,即删除表
3.修改表
在<现有的>表中添加新的字段,执行命令会提示:
在没有指定默认值的情况下,不可能向goodsinfo添加不可为空的字段“size”。这是因为数据库需要一些东西来填充现有的行。 请选择一个修复:
1)现在提供一次性默认值(将在所有现有行上设置,并且此列为空值)
2)退出并在models.py中手动定义一个默认值。
选择一个选项:
- 选择1:
会有求>>>输入一个值,作为默认值(这里我输入的是0)
- 选择2:
会直接退出,可以手动为其添加一个默认值
size = models.IntegerField(default=0)
log = models.IntegerField(null=True,blank=True) # 默认为空
5.ORM字段介绍
Djan提供了很多字段类型,比如URL/Email/IP/ 但是mysql数据没有这些类型,这类型存储到数据库上本质是字符串数据类型,其主要目的是为了封装底层SQL语句;
字符串类(以下都是在数据库中本质都是字符串数据类型,此类字段只是在Django自带的admin中生效)
EmailField(CharField): IPAddressField(Field) URLField(CharField) SlugField(CharField) UUIDField(Field) FilePathField(Field) FileField(Field) ImageField(FileField) CommaSeparatedIntegerField(CharField)
提示:models.CharField 对应的是MySQL的varchar数据类型
char 和 varchar的区别 :
char和varchar的共同点是存储数据的长度,不能 超过max_length限制,
不同点是varchar根据数据实际长度存储,char按指定max_length()存储数据;所有前者更节省硬盘空间;
时间字段
models.DateTimeField(null=True) date=models.DateField()
数字字段
(max_digits=30,decimal_places=10)总长度30小数位 10位) num = models.IntegerField() num = models.FloatField() 浮点 price=models.DecimalField(max_digits=8,decimal_places=3) 精确浮点
枚举字段
choice=( (1,'男人'), (2,'女人'), (3,'其他') ) lover=models.IntegerField(choices=choice) #枚举类型
扩展
在数据库存储枚举类型,比外键有什么优势?
1、无需连表查询性能低,省硬盘空间(选项不固定时用外键)
2、在modle文件里不能动态增加(选项一成不变用Django的choice)其他字段
db_index = True 表示设置索引 unique(唯一的意思) = True 设置唯一索引
6.ORM编辑字段
首先导入类
# wmsapp/views.py
from wmsapp import models
def index(request):
# 添加字段
models.UserInfo.objects.create(
name='wangwu',
mobile='19927343821',
password='82737373',
authority='manager'
)
# 删除字段
models.UserInfo.objects.filter(id=2).delete() # 筛选指定行数据删除
models.UserInfo.objects.all().delete() # 删除表内全部数据
# 获取字段信息
db_list = models.UserInfo.objects.all() # 无论筛选一行还是获取全部,得到的都是queryset类型
for obj in db_list:
print(obj.name,obj.mobile,obj.password,obj.authority,obj.sign_time) # 必须要通过循环的形式输出字段信息
row_obj = models.UserInfo.objects.all().first()
print(obj.name,obj.mobile,obj.password,obj.authority,obj.sign_time) # 因为只有第一行,可以直接打印第一行的字段信息
#更新字段
models.UserInfo.objects.all().update(password='123012398')
# 添加外键约束
manager = models.ForeignKey(to="UserInfo", to_field="id") # 将货物和管理员绑定,其列名会生成manager_id,字段只能填写绑定的表UserInfo里的ID值
# 级联删除
manager = models.ForeignKey(to="UserInfo", to_field="id", on_delete=models.CASCADE) # 如果管理员被删除,其所在表GoodsInfo里绑定的货物一并被删除
# 置空
manager = models.ForeignKey(to="UserInfo", to_field="id", null=True, blank=True, on_delete=models.SET_NULL)# 如果管理员被删除,其所在表GoodsInfo里绑定的货物会被为空,前提要设置可为空
return HttpResponse("欢迎使用Django!")
ModelForm组件
admin后台
1.在admin中注册模型
# wms/admin.py
from django.contrib import admin
from . import models
admin.site.register(models.User)
2.创建超级管理员
python manage.py createsuperuser
顺序填写用户名、邮箱、密码
图形验证码
验证码(CAPTCHA)是“Completely Automated Public Turing test to tell Computers and Humans Apart”(全自动区分计算机和人类的图灵测试)的缩写,是一种区分用户是计算机还是人的公共全自动程序。可以防止恶意破解密码、刷票、论坛灌水,有效防止某个黑客对某一个特定注册用户用特定程序暴力破解方式进行不断的登陆尝试。
图形验证码的历史比较悠久,到现在已经有点英雄末路的味道了。因为机器学习、图像识别的存在,机器人已经可以比较正确的识别图像内的字符了。但不管怎么说,作为一种防御手段,至少还是可以抵挡一些低级入门的攻击手段,抬高了攻击者的门槛。
采用python的第三方库,pip install django-simple-captcha,Django自动帮我们安装了相关的依赖库six
、olefile
和Pillow
,其中的Pillow是大名鼎鼎的绘图模块
1.注册captcha
INSTALLED_APPS = [
'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
'captcha',
]
2.设置图形验证码的样式
# wms/settings.py
#字母验证码
CAPTCHA_IMAGE_SIZE = (80, 45) # 设置 captcha 图片大小
CAPTCHA_LENGTH = 4 # 字符个数
CAPTCHA_TIMEOUT = 1 # 超时(minutes)
#加减乘除验证码
CAPTCHA_OUTPUT_FORMAT = '%(image)s %(text_field)s %(hidden_field)s '
CAPTCHA_NOISE_FUNCTIONS = ('captcha.helpers.noise_null',
'captcha.helpers.noise_arcs', # 线
'captcha.helpers.noise_dots', # 点
)
CAPTCHA_CHALLENGE_FUNCT = 'captcha.helpers.random_char_challenge'
CAPTCHA_CHALLENGE_FUNCT = 'captcha.helpers.math_challenge'
CAPTCHA_TIMEOUT = 1
captcha需要在数据库中建立自己的数据表,所以需要执行migrate命令生成数据表:
python manage.py migrate
2.添加url路由
url(r'^captcha', include('captcha.urls')) # 增加这一行
在前端添加captcha内容
<div class="form-group">
{ { login_form.captcha.errors } } # 用于提示验证码错误
{ { login_form.captcha.label_tag } }
{ { login_form.captcha } }
</div>
其中验证图形码是否正确的工作都是在后台自动完成的,只需要使用is_valid()
这个forms内置的验证方法就一起进行了,完全不需要在视图函数中添加任何的验证代码,非常方便快捷!
Session会话
因为因特网HTTP协议的特性,每一次来自于用户浏览器的请求(request)都是无状态的、独立的。通俗地说,就是无法保存用户状态,后台服务器根本就不知道当前请求和以前及以后请求是否来自同一用户。对于静态网站,这可能不是个问题,而对于动态网站,尤其是京东、天猫、银行等购物或金融网站,无法识别用户并保持用户状态是致命的,根本就无法提供服务。你可以尝试将浏览器的cookie功能关闭,你会发现将无法在京东登录和购物。
为了实现连接状态的保持功能,网站会通过用户的浏览器在用户机器内被限定的硬盘位置中写入一些数据,也就是所谓的Cookie。通过Cookie可以保存一些诸如用户名、浏览记录、表单记录、登录和注销等各种数据。但是这种方式非常不安全,因为Cookie保存在用户的机器上,如果Cookie被伪造、篡改或删除,就会造成极大的安全威胁,因此,现代网站设计通常将Cookie用来保存一些不重要的内容,实际的用户数据和状态还是以Session会话的方式保存在服务器端。
Session依赖Cookie!但与Cookie不同的地方在于Session将所有的数据都放在服务器端,用户浏览器的Cookie中只会保存一个非明文的识别信息,比如哈希值。
Django提供了一个通用的Session框架,并且可以使用多种session数据的保存方式:
- 保存在数据库内
- 保存到缓存
- 保存到文件内
- 保存到cookie内
通常情况,没有特别需求的话,请使用保存在数据库内的方式,尽量不要保存到Cookie内。
Django的session框架默认启用,并已经注册在app设置内,如果真的没有启用,那么参考下面的内容添加有说明的那两行,再执行migrate命令创建数据表,就可以使用session了。
# Application definition
INSTALLED_APPS = [
'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions', # 这一行
'django.contrib.messages',
'django.contrib.staticfiles',
]
MIDDLEWARE = [
'django.middleware.security.SecurityMiddleware',
'django.contrib.sessions.middleware.SessionMiddleware', # 这一行
'django.middleware.common.CommonMiddleware',
'django.middleware.csrf.CsrfViewMiddleware',
'django.contrib.auth.middleware.AuthenticationMiddleware',
'django.contrib.messages.middleware.MessageMiddleware',
'django.middleware.clickjacking.XFrameOptionsMiddleware',
]
当session启用后,传递给视图request参数的HttpRequest对象将包含一个session属性,就像一个字典对象一样。你可以在Django的任何地方读写request.session
属性,或者多次编辑使用它。
下面是session使用参考:
class backends.base.SessionBase
# 这是所有会话对象的基类,包含标准的字典方法:
__getitem__(key)
Example: fav_color = request.session['fav_color']
__setitem__(key, value)
Example: request.session['fav_color'] = 'blue'
__delitem__(key)
Example: del request.session['fav_color'] # 如果不存在会抛出异常
__contains__(key)
Example: 'fav_color' in request.session
get(key, default=None)
Example: fav_color = request.session.get('fav_color', 'red')
pop(key, default=__not_given)
Example: fav_color = request.session.pop('fav_color', 'blue')
# 类似字典数据类型的内置方法
keys()
items()
setdefault()
clear()
# 它还有下面的方法:
flush()
# 删除当前的会话数据和会话cookie。经常用在用户退出后,删除会话。
set_test_cookie()
# 设置一个测试cookie,用于探测用户浏览器是否支持cookies。由于cookie的工作机制,你只有在下次用户请求的时候才可以测试。
test_cookie_worked()
# 返回True或者False,取决于用户的浏览器是否接受测试cookie。你必须在之前先调用set_test_cookie()方法。
delete_test_cookie()
# 删除测试cookie。
set_expiry(value)
# 设置cookie的有效期。可以传递不同类型的参数值:
• 如果值是一个整数,session将在对应的秒数后失效。例如request.session.set_expiry(300) 将在300秒后失效.
• 如果值是一个datetime或者timedelta对象, 会话将在指定的日期失效
• 如果为0,在用户关闭浏览器后失效
• 如果为None,则将使用全局会话失效策略
失效时间从上一次会话被修改的时刻开始计时。
get_expiry_age()
# 返回多少秒后失效的秒数。对于没有自定义失效时间的会话,这等同于SESSION_COOKIE_AGE.
# 这个方法接受2个可选的关键字参数
• modification:会话的最后修改时间(datetime对象)。默认是当前时间。
•expiry: 会话失效信息,可以是datetime对象,也可以是int或None
get_expiry_date()
# 和上面的方法类似,只是返回的是日期
get_expire_at_browser_close()
# 返回True或False,根据用户会话是否是浏览器关闭后就结束。
clear_expired()
# 删除已经失效的会话数据。
cycle_key()
# 创建一个新的会话秘钥用于保持当前的会话数据。django.contrib.auth.login() 会调用这个方法。
使用session
首先,修改login/views.py
中的login()视图函数:
def login(request):
if request.session.get('is_login',None):
return redirect('/index')
if request.method == "POST":
login_form = UserForm(request.POST)
message = "请检查填写的内容!"
if login_form.is_valid():
username = login_form.cleaned_data['username']
password = login_form.cleaned_data['password']
try:
user = models.User.objects.get(name=username)
if user.password == password:
request.session['is_login'] = True
request.session['user_id'] = user.id
request.session['user_name'] = user.name
return redirect('/index/')
else:
message = "密码不正确!"
except:
message = "用户不存在!"
return render(request, 'login/login.html', locals())
login_form = UserForm()
return render(request, 'login/login.html', locals())
通过下面的if语句,我们不允许重复登录:
if request.session.get('is_login',None):
return redirect("/index/")
通过下面的语句,我们往session字典内写入用户状态和数据:
request.session['is_login'] = True
request.session['user_id'] = user.id
request.session['user_name'] = user.name
你完全可以往里面写任何数据,不仅仅限于用户相关!
既然有了session记录用户登录状态,那么就可以完善我们的登出视图函数了:
def logout(request):
if not request.session.get('is_login', None):
# 如果本来就未登录,也就没有登出一说
return redirect("/index/")
request.session.flush()
# 或者使用下面的方法
# del request.session['is_login']
# del request.session['user_id']
# del request.session['user_name']
return redirect("/index/")
flush()方法是比较安全的一种做法,而且一次性将session中的所有内容全部清空,确保不留后患。但也有不好的地方,那就是如果你在session中夹带了一点‘私货’,会被一并删除,这一点一定要注意。
完善页面
有了用户状态,就可以根据用户登录与否,展示不同的页面,比如导航条内容:
首先,修改base.html
文件:
<div class="collapse navbar-collapse" id="my-nav">
<ul class="nav navbar-nav">
<li class="active"><a href="/index/">主页</a></li>
</ul>
<ul class="nav navbar-nav navbar-right">
{ % if request.session.is_login % }
<li><a href="#">当前在线:{ { request.session.user_name } }</a></li>
<li><a href="/logout/">登出</a></li>
{ % else % }
<li><a href="/login/">登录</a></li>
<li><a href="/register/">注册</a></li>
{ % endif % }
</ul>
</div><!-- /.navbar-collapse -->
</div><!-- /.container-fluid -->
通过if判断,当登录时,显示当前用户名和登出按钮。未登录时,显示登录和注册按钮。
注意其中的模板语言,{ { request } }
这个变量会被默认传入模板中,可以通过圆点的调用方式,获取它内部的{ { request.session } }
,再进一步的获取session中的内容。其实{ { request } }
中的数据远不止此,例如{ { request.path } }
就可以获取先前的url地址。
再修改一下index.html
页面,根据登录与否的不同,显示不同的内容:
{ % extends 'base.html' % }
{ % block title % }主页{ % endblock % }
{ % block content % }
{ % if request.session.is_login % }
<h1>你好,{ { request.session.user_name } }!欢迎回来!</h1>
{ % else % }
<h1>你尚未登录,只能访问公开内容!</h1>
{ % endif % }
{ % endblock % }
密码加密
用户注册的密码应该加密才对
对于如何加密密码,有很多不同的途径,其安全程度也高低不等。这里我们使用Python内置的hashlib库,使用哈希值的方式加密密码,可能安全等级不够高,但足够简单,方便使用,不是么?
首先在login/views.py
中编写一个hash函数:
import hashlib
def hash_code(s, salt='mysite'):# 加点盐
h = hashlib.sha256()
s += salt
h.update(s.encode()) # update方法只接收bytes类型
return h.hexdigest()
然后,我们还要对login()和register()视图进行一下修改:
#login.html
if user.password == hash_code(password): # 哈希值和数据库内的值进行比对
#register.html
new_user.password = hash_code(password1) # 使用加密密码
# login/views.py
from django.shortcuts import render,redirect
from . import models
from .forms import UserForm,RegisterForm
import hashlib
def index(request):
pass
return render(request,'login/index.html')
def login(request):
if request.session.get('is_login', None):
return redirect("/index/")
if request.method == "POST":
login_form = UserForm(request.POST)
message = "请检查填写的内容!"
if login_form.is_valid():
username = login_form.cleaned_data['username']
password = login_form.cleaned_data['password']
try:
user = models.User.objects.get(name=username)
if user.password == hash_code(password): # 哈希值和数据库内的值进行比对
request.session['is_login'] = True
request.session['user_id'] = user.id
request.session['user_name'] = user.name
return redirect('/index/')
else:
message = "密码不正确!"
except:
message = "用户不存在!"
return render(request, 'login/login.html', locals())
login_form = UserForm()
return render(request, 'login/login.html', locals())
def register(request):
if request.session.get('is_login', None):
# 登录状态不允许注册。你可以修改这条原则!
return redirect("/index/")
if request.method == "POST":
register_form = RegisterForm(request.POST)
message = "请检查填写的内容!"
if register_form.is_valid(): # 获取数据
username = register_form.cleaned_data['username']
password1 = register_form.cleaned_data['password1']
password2 = register_form.cleaned_data['password2']
email = register_form.cleaned_data['email']
sex = register_form.cleaned_data['sex']
if password1 != password2: # 判断两次密码是否相同
message = "两次输入的密码不同!"
return render(request, 'login/register.html', locals())
else:
same_name_user = models.User.objects.filter(name=username)
if same_name_user: # 用户名唯一
message = '用户已经存在,请重新选择用户名!'
return render(request, 'login/register.html', locals())
same_email_user = models.User.objects.filter(email=email)
if same_email_user: # 邮箱地址唯一
message = '该邮箱地址已被注册,请使用别的邮箱!'
return render(request, 'login/register.html', locals())
# 当一切都OK的情况下,创建新用户
new_user = models.User.objects.create()
new_user.name = username
new_user.password = hash_code(password1) # 使用加密密码
new_user.email = email
new_user.sex = sex
new_user.save()
return redirect('/login/') # 自动跳转到登录页面
register_form = RegisterForm()
return render(request, 'login/register.html', locals())
def logout(request):
if not request.session.get('is_login',None):
return redirect('/index/')
request.session.flush()
return redirect('/index/')
def hash_code(s, salt='mysite_login'):
h = hashlib.sha256()
s += salt
h.update(s.encode()) # update方法只接收bytes类型
return h.hexdigest()
重启服务器,进入注册页面,新建一个用户,然后进入admin后台,查看用户的密码情况:
再使用该用户登录一下,大功告成!
可以看到密码长度根据你哈希算法的不同,已经变得很长了,所以前面model中设置password字段时,不要想当然的将max_length
设置为16这么小的数字。
模板继承
模板:
<title>
<!-- 以后可以随时更换title -->
{ % block title % }{ % endblock % }
</title>
<!-- 可以根据页面引入需要的css -->
{ % block css % }{ % endblock % }
<body>
{ % block content % }{ % endblock % }
</body>
<!-- 可以根据页面引入需要的js -->
{ % block js % }{ % endblock % }
页面:
{ % extends "模板名.html" % }
{ % block title % }
添加用户
{ % endblock % }
{ % block css % }...{ % endblock % }
{ % block content % }
...
{ % endblock % }
{ % block js% }...{ % endblock % }
ModelForm组件
modelform: 针对数据库的某张表
form:登录
Ajax
图表
highcharts:国外,开发时常用
echart:国内,初学时常用
通过ajax向后台获取数据
文件上传
混合数据
form/modelfrom
有两个特殊的文件夹:
static
:项目文件css、js、项目图片
media
:用户上传的数据
启用media目录:
urls.py中加入
urlpatterns = [
re_path(r'^media/(?P<path>.*)$',serve,{'document_root':settings.MEDIA_ROOT},name='media'),
]
setting.py中加入
import os
MEDIA_ROOT = os.path.join(BASE_DIR, "media")
MEDIA_URL = "/media/"
位置就在根目录下
Bootstrap样式父类
views.py视图函数的拆分
时间选择器插件
下载插件GitHub - uxsolutions/bootstrap-datepicker: a datepicker for twitter bootstrap (@twbs)
找到之中的dist取出改名为bootstrap-datepicker文件夹里就完成了,保存到项目的plugins里即可
在母版文件引入(在此之前需要同时引入bootstrap的css和js,和jquery)
{ % block css% }
<link rel="stylesheet" href="{ % static "plugins/bootstrap-datepicker/css/bootstrap-datepicker.css" % }">
{ % endblock % }
<input type="text" id="dt" class="form-control" placeholder="入职时间">
{ % block js% }
<script src="{ % static "plugins/bootstrap-datepicker/js/bootstrap-datepicker.js" % }"></script>
<script src="{ % static "plugins/bootstrap-datepicker/locales/bootstrap-datepicker.zh-CN.min.js" % }"></script>
{ % endblock % }
<script>
$(function (){
$('#dt').datepicker({
format: 'yyyy-mm-dd',
startDate: '0',
language: 'zh-CN',
autoclose: true,
});
})
</script>
其他
form表单安全机制
只要有form表单就要先写一个{ % csrf_token % },没有就会引起django安全机制报错,无法运行
时间过滤器
<td>{ { obj.updatetime|date:"Y-m-d H:i:s” } }</td>
上线注意
上线前要把所有引入的文件都改为.min.的版本
学习总结
- 掌握django基础知识点后,练习一些项目案例
- 了解进阶的django知识点、组件,对原先每个模块的增删改查(复用率低,浪费资源)的代码优化
- 前后端分离项目 django + drf框架 + vue.js(现在企业常用的开发结构)
- git版本控制和协同开发
- 微信小程序 + django + drf框架
学习DRF(Django-rest-framework)
drf简介
- 提供了定义序列化器Serializer的方法,可以快速根据 Django ORM 或者其它库自动序列化/反序列化;
- 提供了丰富的类视图、Mixin扩展类,简化视图的编写;
- 丰富的定制层级:函数视图、类视图、视图集合到自动生成 API,满足各种需要;
- 多种身份认证和权限认证方式的支持;
- 内置了限流系统;
- 直观的 API web 界面;
- 可扩展性,插件丰富
1.安装DRF
pip install djangorestframework
pip install markdown # Markdown support for the browsable API.
pip install django-filter # Filtering support