有ip无路由是404,ip也无是无法访问此网站。url中?前的是路由,?后是GET请求的各组参数。
子项目和子应用下的两类urls.py:[]内的各个路由函数url,其首参网址的开头无/,结尾有/。
views中的各函数、templates下的xxx.html,所出现的各相对路径:项目的根目录(即与manage.py同级的文件夹或文件)开头不加/,次级目录开头要加/;url若拼接ip则开头加/,拼接所在函数所响应的路由则开头不加/。
settings.py底的STATIC_URL = '/static/',前后都有/:
①开头有/:static文件夹在子应用下而非总项目的根下;拼接的是ip。②结尾有/:尾部要接受css等子文件(夹)的拼接。
设计个有远见的数据库=项目完成了一半=几千行代码。既让当前的代码活事半功倍,又减少日后修修补补的次数和面积。数据库的架构是机密,竞争对手看到后,或能山寨出相似的项目。
引入markdown:www.zhidaow.com/post/django-custom-template-tag-markdown。
**************************分割线**************************
三大web框架的请求:
请求的参数为input标签(type为text,password,checkbox等)的name属性,返回为value属性的值。
tornado用方法self.get_argument('name值'),另俩用{}:request.xx['name']或request.xx.get('name')。
①tornado:get和post都是self.get_argument('name属性的值',default=None)。
②flask:get请求用request.args['name'],post用request.form['name']。
③django:request.GET['name'],所求在网址的?后;request.POST['name'],request.FILES['type为file…'],所求都在postData;request.META['某个请求头如HTTP_REFERER']。
**************************分割线**************************
html模板:①{{变量}};
②{% 语法如if、for…in…、with…as…等;或函数如load static from staticfiles、csrf_token等 %}
django和flask的 html模板中的 循环或判断:
(tornado例外,结尾全是{% end %},属性用d['key']而非d.key)
{% for country in countries %}
{% for city in country.cities %}
国家#{{forloop.parentloop.counter}}:{{city}}
{% if not forloop.last %}
,
{% else %}
\n
{% endif %}
{% endfor %}
{% endfor %}
****************************************分割线****************************************
django做个电影网站:
①E盘下建个movie文件夹→PyCharm新建项目选Django→location改为E:\movie→More Settings的Application写个dy;
注:PyCharm新建好django项目后,启动项目是按绿方块dj+根目录(如本例的movie)右侧的绿三角,而非我习惯的Run context configuration。
**************************分割线**************************
②项目文件夹movie:
配置文件settings.py:
DEBUG = True在部署到Linux前要改为False。INSTALLED_APPS尾已自动添加了dy…,不理会;若新建应用,则模仿dy…添加。
LANGUAGE_CODE = 'zh-hans'
TIME_ZONE = 'Asia/Shanghai'
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.mysql',
#以下四项,和软件Navicat for MySQL的连接界面一样
'HOST': 'mysql.litianqiang.com', #潭州的远程mysql
'PORT': '7150', #mysql默认端口3306;在django是str,MySQLdb是int
'USER': 'movie',
'PASSWORD': '……()', #隐藏……处,用的院长的绰号
'NAME': 'movie', #潭州学院一远程数据库的名字
}
}
sessions禁用:注释此行'django.contrib.sessions.middleware.SessionMiddleware',
sessions的3种存储方式:
SESSION_ENGINE='django.contrib.sessions.backends.db' #默认存在数据库
SESSION_ENGINE='django.contrib.sessions.backends.cache' #存在缓存
SESSION_ENGINE='django.contrib.sessions.backends.cached_db' #优先缓存,次选库
***************分割线***************
路由文件urls.py:
url的2参有两种写法:url('正则',views.视图函数名)、大型的url('正则',include('应用名.urls'))。
from django.conf.urls import url,include
from django.contrib import admin
from dy import views
urlpatterns = [
url(r'^admin/', admin.site.urls),
url(r'^$',views.index), #首页是^$;2参是视图函数名,而非补个()的返回值
url(r'^cy/',views.chengy,name='xm'), #给路由起个别名,方便视图调用
url(r'^cy/', include('dy.urls')), #使dy下urls.py内的各url的首参,拼接ip/cy/,而非ip/
url(r'^cy(x)/(y)/',views.info), #def info(request,n,m):,x,y的值按位置传参给n,m
url(r'^cy(?P<id>\w+)/',views.stu), #def stu(request,id):,\w+的值按参数名传给id
]
**************************分割线**************************
③应用文件夹dy:
路由文件urls.py:本例的网址少,不必牛刀杀鸡建此文件,只是举个例子
from django.conf.urls import url
from dy import views
urlpatterns = [
url(r'^$',views.indexDY),
url(r'^666/',views.留空),
]
和数据库交互(俗称ORM:Object Relational Mapping)的models.py:
在E:\movie路径下进入cmd:python manage.py inspectdb > dy/models.py
执行后settings中所配数据库movie中的各表,以class的形式(表名删_,首字母大写)自动写入dy/models.py。
各类字段:
参数null默认False不许为空,参数unique若设为True则该字段列无重复。
自增主键models.AutoField(primary_key=True),布尔BooleanField,整数IntegerField,浮点数FloatField,指定总位数和小数位数的models.DecimalField(max_digits=7, decimal_places=3)。
字串字段,限制字数的短文本用models.CharField(max_length=9),一般超4000字符的大文本用TextField。
时间字段DateField或TimeField或DateTimeField,加参数auto_now=True则各行记录的该字段时间值为最后1次修改的,auto_now_add=True则为固定的创建时间。
外键字段classID=models.ForeignKey('类名如Classes'),在Classes-Students(两张数据表classes和students)的Students类一方定义。
Egの外键使用,html中遍历各个班里的学生:
{% for stu in students %}
{{ stu.studentName }}∈{{ stu.classID.className }}
{% endfor %}
<br><hr><br> //空行br、横线hr、无序列表ul
{% for c in classes %}
班级{{ c.className }}有以下学生:
<ul>
{% for stu in c.students_set.all %} //班级外键.学生表名后加_set.all,.py内all后有()
<li>{{ stu.studentName }}</li>
{% endfor %}
</ul>
{% endfor %}
***************分割线***************
各路由网址呈现什么内容的文件views.py:
from django.shortcuts import render #return render(request,'index.html',context=context)
from django.shortcuts import redirect #return redirect('/login/')
from django.http import HttpResponse #return HttpResponse('<h1>hello,world</h1>')
from django.http import JsonResponse #return JsonResponse({'x':'hello','y':'world'})
from dy.models import DyDy #导入movie库中电影数据源所在的那张表
def chengy(request):
#.get()取键值,若无不报错;多个name为x(如type="checkbox"的各标签),则用.getlist('x')
words=request.POST.get('keywords')
#视图中session的使用:
request.session.get('a','') #获取session中session_key为a的session_data
request.session['a']=1 #设置键a的值
request.session.set_expiry(600) #过期单位秒,默认2周,0在关浏览器时,None永不过期
del request.session['a'] #删除session中的键a
request.session.clear() #各session_key的session_data置为''
request.session.flush() #删除session
#请求的:request.COOKIES、参数获取.GET及.POST、方式.method、编码.encoding
response=HttpResponse(f'请求的路径:{request.path}')
response.set_cookie('name','jack',expires=60*60*24) #设置coocie的键、值、有效期24h
return response
def index(request):
kw=request.POST.get('kw')
if kw:
#增=DyDy();增.title='2012';增.link='http://…';增.save()
#DyDy.objects.all().order_by('-title')[:50].delete() #按title降序后,删前50行记录
#改=DyDy.objects.get(id=1);改.title='乱';改.save() #改这条记录(若无则抛出异常)的title
查=DyDy.objects.filter(title__icontains=kw)[:9] #标题含关键词的前9条,若无则返回空[]
context={'movies':查}
return render(request,'index.html',context=context)
***************分割线***************
应用文件夹dy下新建个templates文件夹,其内新建个index.html:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>电影下载-首页</title>
</head>
<body>
<form action="/" method="post">
{% csrf_token %} <!--跨域攻击;新浪上写博客不支持半角<符和autocomplete单词-->
<input type="text" name="kw" style="width: 500px" auto¥complete="off">
<input type="submit" value="搜索电影">
</form><br>
{% if movies %}
{% for movie in movies %}
<li><a href="{{ movie.link }}">{{ movie.title }}</a></li>
{% endfor %}
{% endif %}
</body>
</html>
****************************************分割线****************************************
开发网盘:
①E盘下建个wangpan文件夹→……Application写个disk;
***************分割线***************
②项目文件夹wangpan:
__init__.py:
import pymysql
pymysql.install_as_MySQLdb()
settings.py:
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.mysql',
'HOST':'localhost','PORT':'3306','USER':'chengy','PASSWORD':'',
'NAME': '网盘'
}
}
urls.py:
from django.conf.urls import url
from django.contrib import admin
from disk import views
urlpatterns = [
url(r'^admin/', admin.site.urls),
url(r'^$', views.index,name='index'),
url(r'^upload/$', views.upload,name='upload'),
url(r'^s/(\w{32})/$', views.content), #路由网址中的()(),是content函数的2参、3参等
url(r'^file/.*?$', views.download,name='download'),
]
***************分割线***************
③应用文件夹disk:
models.py:
from django.db import models
class FileInfo(models.Model):
# id=models.AutoField(primary_key=True) #默认创建主键自增字段id
user=models.CharField(max_length=20,null=False)
fileName=models.CharField(max_length=30,null=False)
fileSize=models.IntegerField(null=False)
fileMd5=models.CharField(max_length=32,null=False)
在E:\wangpan进入cmd,依次执行如下两句,用models.py的各类,生成mysql的网盘库的各表:
python manage.py makemigrations
python manage.py migrate
******分割线******
views.py:
from django.shortcuts import render
from django.http import HttpResponse,HttpResponseRedirect
import hashlib
from disk.models import FileInfo
def index(request):
return render(request,'index.html')
def upload(request):
#在用户电脑上读取文件并计算MD5值,而非上传到网盘服务器后才计算
myFile=request.FILES.get('upfile')
if not myFile: #print(myFile)
return HttpResponse('没上传文件')
file=myFile.read()
if not file:
return HttpResponse('不能上传空文件')
fileName=myFile.name
fileSize=myFile.size
fileMd5=hashlib.md5(file).hexdigest()
existed=FileInfo.objects.filter(fileMd5=fileMd5)
if existed:
FileInfo(fileName=fileName, fileSize=fileSize, fileMd5=fileMd5).save()
# return HttpResponse('文件成功秒传') #AttributeError 'tuple' no attribute 'get'
return HttpResponseRedirect('/s/{}'.format(fileMd5)) #拼接的是域名,s前有/
with open('file/{}'.format(fileMd5),'wb') as f: #file,是和manage.py同级的文件夹,前无/
f.write(file)
FileInfo(fileName=fileName, fileSize=fileSize, fileMd5=fileMd5).save()
# return HttpResponse('文件上传完成')
return HttpResponseRedirect('/s/{}'.format(fileMd5))
def content(request,fileMd5):
fileInfo=FileInfo.objects.filter(fileMd5=fileMd5) #类似正则的findall,提取某行记录要加[0]
if not fileInfo:
return HttpResponse('该文件不存在或已被删除')
context={
'fileName':fileInfo[0].fileName,
'fileSize':fileInfo[0].fileSize,
'fileUrl':'/file/{}'.format(fileInfo[0].fileName)} #下载时默认的文件名,取末/后的字串
return render(request,'content.html',context=context)
def download(request):
referer=request.META.get('HTTP_REFERER') #获取来路,只在部署到Linux前用
if not referer:
return HttpResponse('该文件不存在或已被删除') #防止复制下载网址来直接下载
fileMd5=referer[-33:-1]
fileInfo=FileInfo.objects.filter(fileMd5=fileMd5)
if not fileInfo:
return HttpResponse('该文件不存在或已被删除')
file=open('file/{}'.format(fileMd5),'rb').read()
response=HttpResponse(file) #HttpResponse的一个最大用处:下载流数据
response["Content-type"]="application/octet-stream"
return response
***************分割线***************
④index.html:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>文件上传</title>
</head>
<body>
<form action="/upload/" method="post" enctype="multipart/form-data">
{% csrf_token %} <!--跨域攻击-->
<input type="file" name="upfile">
<input type="submit" value="上传">
</form>
</body>
</html>
content.html:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>文件下载</title>
</head>
<body>
<li>文件名:{{ fileName }}</li>
<br> <!--换行符-->
<li>文件大小:{{ fileSize }}</li>
<br>
<li><a href="{{ fileUrl }}">点击下载</a></li>
</body>
</html>
****************************************分割线****************************************
小说网站:
①E盘下建个novel文件夹→……Application写个xs;
***************分割线***************
②settings.py:
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.mysql',
'HOST': 'mysql.litianqiang.com','PORT': '7150',
'USER': 'novel','PASSWORD': '……()', #隐藏……处,李院长用的他的绰号
'NAME': 'novel',
}
}
urls.py:
from django.conf.urls import url
from django.contrib import admin
from xs import views
urlpatterns = [
url(r'^admin/', admin.site.urls),
url(r'^$', views.index,name='index'),
]
***************分割线***************
③models.py:
在E:\novel路径下进入cmd:python manage.py inspectdb > xs/models.py
views.py:
from django.shortcuts import render
from xs.models import NovelCopy
def index(request):
novelsHot=NovelCopy.objects.filter().order_by('?')[:4] #ORM模型,用?表示随机排序
novelsXH=NovelCopy.objects.filter(sort='玄幻').order_by('?')[:4]
novelsWX=NovelCopy.objects.filter(sort='武侠').order_by('?')[:5]
context = {'novelsHot':novelsHot,'novelsXH':novelsXH,'novelsWX':novelsWX}
return render(request,'index.html',context=context)
***************分割线***************
④index.html:
{% load staticfiles %} <!--若static文件夹及settings.py末尾均改了名,html中只需改这1处-->
<!doctype html>
<html>
<head><meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<meta name="Keywords" content=""/><meta name="description" content=""/>
<title>Python探索馆 - Slice</title>
<link rel="stylesheet" href="{% static 'css/style.css' %}" /></head>
<body>
<div class="full-pic"></div> <!--===== Full Screen BG =====-->
<header class="header"> <!--===== Begin Header =====-->
<div class="fixed-head" style="position: fixed; width: 100%;">
<div class="wrap1000 head-wrap">
<div class="logo"><a href="detail.html">Python学院图书馆</a></div>
<div class="nav"><ul class="nav-list">
<li><a href="detail.html"><span>首页</span></a></li>
<li><a href="detail.html"><span>玄幻</span></a></li>
<li><a href="detail.html"><span>修仙</span></a></li></ul></div>
<div class="search"><form action="search.html" method="get" target="_blank">
<input name="kw" placeholder="搜索书名" type="text" maxlength="10" />
<input id="search-submit-btn" type="submit"/>
<label for="search-submit-btn"><i class="iconfont icon-search"></i></label>
</form></div>
</div></div>
</header>
<!--===== Begin Main =====-->
<section class="main"><div class="main-wrap wrap1000"><div class="hot-section"><div class="hot-content">
<div class="hot-shadow"><div class="hot-title">最热</div></div>
<div class="banner"> <!-- 1、banner -->
<ul class="banner-imgs"> <!--static/img文件夹下放了几张图片,就写几个li标签-->
<li><a href="detail.html"><img src="{% static 'img/1.jpg' %}"/></a></li>
</ul>
<div class="control-page">
<a class="iconfont icon-bannerzuo" href=";"></a>
<a class="iconfont icon-banneryou" href=";"></a>
</div>
</div>
<div class="hot-recommend"><ul class="hot-list"> <!-- 2、hot -->
{% for novel in novelsHot %}
<li><a href="detail.html"><div><img src="{{ novel.novelimg }}"/></div>
<p>{{novel.novelname}}<span class="author">{{novel.author}} 著</span>
<span class="book-description">
<!--|safe把空格、换行等标点转为正常字符;|chuncatechars:'数字',把超出的字数以仨点替之-->
{{ novel.description|safe|truncatechars:'90' }}
</span></p></a></li>
{% endfor %}</ul></div>
<div class="xuanhuan"> <!-- 3、Xuanhuan -->
<div class="xuanhuan-title">
<span>玄幻</span><p class="txt">Fantasy</p><p>Novel</p>
<span class="more"><a href="more.html">更多>></a></span>
</div>
<div class="wrap890 xuanhuan-wrap"><ul class="book-list">
{% for novel in novelsXH %}
<li class="book"><div class="book-wrap">
<a class="cover" href="detail.html"><img src="{{ novel.novelimg }}" width="136" height="180" /></a>
<div class="book-presentation"><h2><a href="detail.html">{{ novel.novelname }}</a></h2>
<p class="book-info"><span>{{ novel.sort }}</span><span>{{ novel.state }}</span></p>
<p class="book-author"><a href=";">作者:<span>{{ novel.author }}</span></a></p>
<p class="desc">{{ novel.description|safe|truncatechars:'90' }}</p>
</div></div></li>
{% endfor %}</ul></div>
</div>
<!-- 4、WuXia 仿照第3条的玄幻-->
</div></div></div></section> <!--=====End Main=====-->
<footer class="footer"> <!--=====Begin Footer=====-->
<div class="wrap1000 footer-wrap">
<div class="logo-footer"><a href="detail.html">
<img src="{% static 'img/footer_logo.png' %}" alt="" width="50"/>
<span class="footer-txt">世界你好</span></a>
<span class="footer-font">TAN ZHOU PYTHON COLLEGE</span></div>
<div class="copy-right"><p>本站仅供技术学习使用,勿用商业</p>
<p>Copyright © 2017 All Rights Reserved 世界你好</p></div>
</div></footer> <!--=====End Footer=====-->
<script src="{% static 'js/index.js' %}"></script> <!-- Main Plugin -->
</body></html>