有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>