##创建一个django项目的具体步骤:
1.首先创建project:
PS D:\pythonProject_云笔记> django-admin startproject tudu_note
PS D:\pythonProject_云笔记>
django-admin startproject xxxxxx具体项目名称
2. 创建应用(分块处理)
PS D:\pythonProject_云笔记> cd D:\pythonProject_云笔记\tudu_note
PS D:\pythonProject_云笔记\tudu_note>
PS D:\pythonProject_云笔记\tudu_note>
py manage.py startapp xxxxxxxx具体应用
3.setting相关设置:
(1)增加应用
(2)关闭CsfviewMiddleware
(3)数据库配置
(4)数据库的创建
(5)时区配置
(6)templates相关设置
在项目目录的外层建立templates文件夹
在setting.py中添加模板层templates
'DIRS': [os.path.join(BASE_DIR,"templates")], #存放html
建议将功能分化 ,直接在app应用中创建templates。
但要注意尽量不要同名!!!!!!!
##from表单post请求
发出post请求传到原有页面url
url可以动态获取 path中的name项即可
{% url 'movie_login' %}
发送到视图层获取到post请求
<form method="post",action="{% url 'movie_login' %}">
<div class="row">
<div class="col-12"> <input type="text" name="First Name" placeholder="姓名/称呼"></div>
<div class="col-12"> <input type="email" name="电子邮件" placeholder="电子邮件"> </div>
<div class="col-12"> <input type="password" name="密码" placeholder="密码"> </div>
<div class="col-12"> <input type="password" name="确认密码" placeholder="确认密码"> </div>
</form>
path中的情况如下:
path('Film/recommendation/login',views.movie_login,name='movie_login'),
## django的模板层
html页面的统一格式设置:
base层 模板层:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
{% block title %}
<title>首页</title>
{% endblock %}
</head>
<body>
{% block end %}
<p> 电影推荐系统 </p>
{% endblock %}
</body>
</html>
继承层:
首先继承自模板层{% extends "模板层名称XXXX.html" %}
{% block xxx内容 %}
想要复写的内容
{% endblock %}
{% extends 'movie_base.html' %}
{% block title %}
<title>喜剧页面</title>
{% endblock %}
{% block end %}
<p> 电影推荐系统 喜剧页面</p>
{% endblock %}
## url反向解析(url自匹配)
为避免访问网址过于复杂,及其一系列的问题例如:绝对地址,相对地址,带不带"/",总之非常的麻烦。
url主要有两类需要修改:
①html中的内容修改:
{% url "访问的页面在urls.py中的别名name" "GET方式也可传参" %}
<a href="{% url 'xiju' %}">喜剧</a>
<a href="{% url 'action' %}">动作</a>
<a href="{% url 'base' %}">返回首页</a>
<a href="{% url 'if_for' '60' %}">if for的测试页面</a>
urls.py中的格式如下:
设置相应的name别名,以便于后续的开发
path('html/movie_base',views.movie_base,name='base'),
path('html/movie_xiju',views.movie_xiju,name='xiju'),
path('html/movie_action',views.movie_action,name='action'),
②视图层的url动态解析:
在views.py中如果需要实现跳转操作:
万事先导包:from diango.urls import reverse
url=reverse("url别名")
return HttpResponseRedirect(url) # 跳转到对应的网址
def request_test(request):
print("path_info", request.path_info)
print("method is", request.method)
print("GET is", request.GET)
from django.urls import reverse
url=reverse('base')
return HttpResponseRedirect(url) # 跳转到电影推荐系统首页
##静态文件
静态文件 顾名思义 页面发请求时 不必从视图层传数据 直接将数据输出到页面上去
首先在setting中创建一个STATICFILES_DIRS:
STATIC_URL = '/static/'
# 静态文件文件夹
STATICFILES_DIRS=(
os.path.join(BASE_DIR,"static"),
)
具体的嵌入实现方式如下:
#html声明一次即可
{% load static %}
#css代码段静态注入
<link href= "{% static 'css/socicon.css' %}" rel="stylesheet" type="text/css" media="all" />
#图片等静态注入
<div class="background-image-holder"> <img alt="image" src="{% static 'image/注册封面.jpg' %}"> </div>
##Django应用及其分布式路由
一 应用层的创建:
1.大项目中执行py manage.py startapp XXX
2.setting中写入应用名:
INSTALLED_APPS = [
'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
'Film', #添加app(Film)
]
二 路由(分布式路由) :
在主url中导入include包
写入path(‘应用名/’,include(应用下的urls))
注意!!!! 应用下的urls需要自行创建
templates的查找顺序:
应用下的templates文件夹
但是优先找外层的templates!!!!!!!!!
尽量不要希望重名的html!!!
其次一定要在setting.py中的APP_DIRS ="TRUE"
------------------------------------------------------------分割线------------------------------------------------------------
##关于mysql报错小技巧:
没错直接上究极办法:格式化!!!!!
首先关闭MySQL服务,输入命令:
mysql> net stop MySQL
第一步:
我们需要删除data,也就是前面自动生成的data文件夹。
第二步:
删除成功后重新进行初始化:管理员身份进入cmd输入mysqld --initialize --console
框内最后就是随机密码
启用服务:mysql> net start MySQL
输入mysql -u root -p
enter:输入随机密码
第三步:改密码
进入mysql后,执行:
ALTER USER 'root'@'localhost' IDENTIFIED WITH mysql_native_password BY '输入自己的密码';
ALTER USER 'root'@'localhost' IDENTIFIED BY '自己的密码'
ok圆满了 成功连接
遇到凡事不要慌 啊哈哈哈哈!
##模型层及其所独有的ORM
基本前期准备;
在setting层的设置:
接下就是在应用层的model里开始写内容:
大抵是下面这个样子:
基本对应关系:
小结:
注意创建的过程,先改到mysql,然后在应用的models.py文件中写创建数据库的各个字段,再去命令窗口生成一个迁移文件,使用的命令是:
python manage.py makemigrations
迁移文件创建成功之后,使用命令在数据库中创建相关的表格,使用的命令是:
python manage.py migrate
模型层---字段选项:
1、models.AutoField 自增列 = int(11)
如果没有的话,默认会生成一个名称为 id 的列,如果要显示的自定义一个自增列,必须将给列设置为主键 primary_key=True。
2、models.CharField 字符串字段
必须 max_length 参数
3、models.BooleanField 布尔类型=tinyint(1)
不能为空,Blank=True
4、models.ComaSeparatedIntegerField 用逗号分割的数字=varchar
继承CharField,所以必须 max_lenght 参数
5、models.DateField 日期类型 date
对于参数,auto_now = True 则每次更新都会更新这个时间;auto_now_add 则只是第一次创建添加,之后的更新不再改变。
6、models.DateTimeField 日期类型 datetime
同DateField的参数
7、models.Decimal 十进制小数类型 = decimal
必须指定整数位max_digits和小数位decimal_places
8、models.EmailField 字符串类型(正则表达式邮箱) =varchar
对字符串进行正则表达式
9、models.FloatField 浮点类型 = double
10、models.IntegerField 整形
11、models.BigIntegerField 长整形
integer_field_ranges = {
'SmallIntegerField': (-32768, 32767),
'IntegerField': (-2147483648, 2147483647),
'BigIntegerField': (-9223372036854775808, 9223372036854775807),
'PositiveSmallIntegerField': (0, 32767),
'PositiveIntegerField': (0, 2147483647),
}
12、models.IPAddressField 字符串类型(ip4正则表达式)
13、models.GenericIPAddressField 字符串类型(ip4和ip6是可选的)
参数protocol可以是:both、ipv4、ipv6
验证时,会根据设置报错
14、models.NullBooleanField 允许为空的布尔类型
15、models.PositiveIntegerFiel 正Integer
16、models.PositiveSmallIntegerField 正smallInteger
17、models.SlugField 减号、下划线、字母、数字
18、models.SmallIntegerField 数字
数据库中的字段有:tinyint、smallint、int、bigint
19、models.TextField 字符串=longtext
20、models.TimeField 时间 HH:MM[:ss[.uuuuuu]]
21、models.URLField 字符串,地址正则表达式
22、models.BinaryField 二进制
23、models.ImageField 图片
24、models.FilePathField 文件
null非常不建议使用!!!!!
在新增字段里default一定需要给!!!!!否则会报错!!
说明一点: 在类的内部定义
class Meta:
de_table='xxx'
可以将表名改成想要改变的名字,
class Books(models.Model):
# CharField
book_name = models.CharField('书名', max_length=50, default='',unique=True)
book_price = models.DecimalField('进价', max_digits='7', decimal_places=2, default=0.0)
book_markprice=models.DecimalField('售价',max_digits=7,decimal_places=2,default=0.0)
book_actor = models.CharField('作者', max_length=20, default='')
book_size = models.CharField('大小', max_length=20, default='',)
book_pub = models.CharField('出版社', max_length=20, default='')
class Meta:
db_table='books'
class Authors(models.Model):
Author_name = models.CharField('姓名', max_length=20, default='')
Author_sex = models.CharField('性别', max_length=10, default='')
Author_age = models.DecimalField('年龄', max_digits='8', decimal_places=3, default='')
Author_email=models.CharField('邮箱',null='TRUE',max_length=20,default='')
class Meta:
db_table='Authors'
##django数据库迁移错误解决方式:
## ORM管理器对象
b1 = Book.objects.create(title=‘Python’,pub=‘清华大学出版社’,price=20,market_price=25)
需要写入数据是使用 py manage.py shell
##ORM查询操作
首先导包
from bookstore.models import Books;
1. all()操作:
#bookall属性名
bookall=Books.objects.all()
之后执行bookall即可获取所有表信息:
但是输出后的格式不好看,改进方法:
定义一个__str__(value):
return xxxx
class Books(models.Model):
# CharField
book_name = models.CharField('书名', max_length=50, default='',unique=True)
book_price = models.DecimalField('进价', max_digits='7', decimal_places=2, default=0.0)
book_markprice=models.DecimalField('售价',max_digits=7,decimal_places=2,default=0.0)
book_actor = models.CharField('作者', max_length=20, default='')
book_size = models.CharField('大小', max_length=20, default='',)
book_pub = models.CharField('出版社', max_length=20, default='')
# 重新命名:
class Meta:
db_table='books'
# 定义一个调试输出所有属性的方法:
def __str__(self):
return "书名=%s\n进价=%s\n售价=%s\n作者=%s\n出版社=%s\n"%(self.book_name,self.book_price,self.book_markprice,self.book_actor,self.book_pub)
修改后的结构:
2.value()查询:
另外一种查询方式:
bookss=Books.objects.values('book_name','book_actor')
可以直接查询几个数据
3.value_list()查询:
4.order_by()排序:
>>> a5 = Book.objects.values('title').order_by('-price')
>>> a5
<QuerySet [{'title': 'JQuery'}, {'title': 'HTML5'}, {'title': 'Linux'}, {'title': 'Djang
o'}, {'title': 'Python'}]>
>>> print(a5.query)
SELECT `book`.`title` FROM `book` ORDER BY `book`.`price` DESC
##ORM查询操作二:
filter查询:(查询属性)
filter查询的结果是一个集合 不能直接拿去 需要用便利遍历出来
所以只有一条数据尽量可以使用get方式获取!!
例如:
from bookstore.models import Books;
>>> b1=Books.objects.filter(book_pub="高等教育出版社")
>>> b1
<QuerySet [<Books: 书名=java开发
进价=32.00
售价=48.00
作者=野野
出版社=高等教育出版社
>, <Books: 书名=需求工程
进价=100.00
售价=112.00
作者=骆斌
出版社=高等教育出版社
>]>
>>>
get查询:(只能查到一条数据 多于或少于都会报错)
查询谓词:(模糊查询 __xxx)
大于小于:
IN查询与range查询:
b3=Books.objects.filter(book_price__gt=50)
b4=Books.objects.filter(book_ator__contains="华")
##orm数据更新
单个更新:
>>> b2 = Book.objects.get(id=1)
>>> b2.price = 22
>>> b2.save()
>>> b2 = Book.objects.get(id=1)
>>> b2
<Book: Python_清华大学出版社_22.00_25.00>
>>>
批量更新:
##orm数据删除
伪删除:
##增添-删除-更新操作实例
目标是通过页面向数据库进行基本操作
1.增加操作:(最为简单)
直接在新页面产生form表单,post请求传回视图层,在views.py 中通过request.post["xxx"]
获取到页面输入的数据:
之后通过xxx对象=xxx表 .objects.create(属性=‘xxxx’)
增加属性
之后在视图层 return HTTPREDICRETE(目标页面) 跳转到目标页面;
2.更新操作:(也很简单)
其实最主要的难点就在于如何获取单条数据的相关参数到另一个页面
这时候就要复习前面学到的知识了
方法一:通过点击链接时在后面匹配对应的属性值 例如
<a href="/bookstore/updatebook?bookname={{ books.book_name }}">更新</a></td>
这样动态传入的bookname可以在视图层内进行查询
之后便可以查询到是哪个数据
随后在新页面中创建相应的表单
更新后便继续提交到了视图层下的post请求处理
只需要将获取到的值传给数据即可
之后地址重定向到展示图书页面
book.book_markprice = request.POST['markprice']
book.book_price = request.POST['price']
book.save()
# book.update(book_markprice=int(request.POST['markprice']))
# book.update(book_price=int(request.POST['price']))
url = reverse("book_show")
return HttpResponseRedirect(url)
方式二:直接在后面添加下层地址
<a href="/bookstore/updatebook/{{ books.book_name }}"> 更改</a>/
看着区别不是很大 但是本质上是完全不同的!!!!
这样的的方式也很好 直接将对应的数据中获取甚至都不需要requet.GET['XXX']获取数据了
但是相应的在路由层面和视图层就得多传递一个参数
之后的方法与方法一相同
3.delete操作:
delete操作其实没有特别需要说的
传递参数的方式和更新相同两种方式都可以
操作的关键时伪删除 而不是真正的删除数据
具体操作也是获取到数据的某个属性值
在视图层找出对应的数据后删除
使用 :
彻底删除
对象名=库表.objectes.filter(属性名=“xxxx”)
对象名.delete()
伪删除
对象名=库表.objectes.filter(属性名=“xxxx”)
对象.is_active='False
对象.save()
之后返回视图即可
但千万注意在展示数据库
表时查询条件要加上 is_active='True'!!!!!!!!!!!!
##F对象和Q对象:
解决查询操作中的一系列问题
使用时要先导入包:
from django.db.models import F
from django.db.models import Q
F操作:
数据库展示:
Q对象:
##聚合查询和原生数据库操作:
整表:
原生操作:
##admin后台
在终端输入:
py manage.py createsuperuser
即可创建超级用户
在bookstore的admin中绑定models里的数据即可
具体的操作如下:
from django.contrib import admin
from .models import Books
# Register your models here.
class BookManage(admin.ModelAdmin):
list_display = ['book_name', 'book_actor', 'book_pub', 'book_price', 'book_markprice', 'book_size']
admin.site.register(Books, BookManage)
class BookManage(admin.ModelAdmin):
# 页面可以展示那些数据
list_display = ['book_name', 'book_actor', 'book_pub', 'book_price', 'book_markprice', 'book_size']
# 链接跳转到修改的值
# list_display_links = ['xxx']
# 页面过滤器
list_filter = ['book_pub']
# 搜索框
search_fields = ['book_name']
# 可以直接修改内容
list_editable = ['book_price', 'book_markprice']
admin.site.register(Books, BookManage)
Meta类在models.py中 其实就是更换别名 将数据库表名换为好听些的名字
class Meta:
db_table='books'
verbose_name='图书内容'
verbose_name_plural=verbose_name
##关系映射
一对一:
class Authorwife(models.Model):
name=models.CharField('姓名',default='',max_length=20)
author=models.OneToOneField(Authors,on_delete=models.CASCADE)
一对多:
反向查询
多对多
##会话技术
1.cookies
#cookie会话技术
def set_cookies(request):
resc=HttpResponse("cookies!!!!!!!!!!!!!")
resc.set_cookie('name','ZYL',max_age=200)
return resc
在视图里获取定义一个函数
request.COOKIES.GET("COOKIES名字“,默认值)
之后输出即可
2.session
初始配置:
session 的数据删除:
Cookies与Session
##云笔记项目的搭建
1.登录与注册:
# Create your views here.
import hashlib
from django.http import HttpResponse, HttpResponseRedirect
from django.shortcuts import render
from django.urls import reverse
from .models import User
# 退出登录功能 (其实就是清除cookie与session)
def user_del_informations(request):
url = reverse('index')
if request.session.get('username'):
print('有session')
del request.session['username']
del request.session['uid']
if request.COOKIES.get('username'):
resc = HttpResponseRedirect(url)
resc.delete_cookie('username')
resc.delete_cookie('uid')
return resc
return HttpResponseRedirect(url)
# 用户登录页面
def user_login(request):
if request.method == 'GET':
# 检查有无session和cookies 有的话直接登录 无需输入密码:
if request.session.get('username') and request.session.get('uid'):
return HttpResponse("存在session,您已经登陆了噢。")
c_username = request.COOKIES.get('username')
c_uid = request.COOKIES.get('uid')
if c_uid and c_username:
request.session['username'] = c_username
request.session['uid'] = c_uid
return HttpResponse("存在cookies 您已经登陆。")
# 如果既没有cookies也没有session 那就正常登录
return render(request, 'user_login.html', locals())
elif request.method == 'POST':
url = reverse('index')
username = request.POST['username']
password = request.POST['password']
remenberuser = request.POST['remenberuser']
try:
user = User.objects.get(username=username)
except Exception as e:
print("username is not exit%s" % (e))
return HttpResponse("(用户名)或密码错误")
m = hashlib.md5()
m.update(password.encode())
password_m = m.hexdigest()
if password_m != user.password:
return HttpResponse("用户名或(密码)错误")
else:
request.session['username'] = username
request.session['uid'] = user.id
resc = HttpResponseRedirect(url)
# 勾选存放三天
if remenberuser:
resc.set_cookie('username', username, max_age=3600 * 24 * 3)
resc.set_cookie('uid', user.id, max_age=3600 * 24 * 3)
return resc
# 注册页面
def user_register(request):
url = reverse('index')
if request.method == 'GET':
return render(request, "user_register.html", locals())
elif request.method == 'POST':
username = request.POST['username']
password1 = request.POST['password1']
password2 = request.POST['password2']
old_username = User.objects.filter(username=username)
if old_username:
return HttpResponse("该用户名已被注册!")
else:
m = hashlib.md5()
m.update(password1.encode())
password_m = m.hexdigest()
if password2 == password1:
try:
user = User.objects.create(username=username, password=password_m)
except Exception as e:
print('creat is worning%s' % (e))
return HttpResponse("用户被注册")
request.session['username'] = username
request.session['uid'] = user.id
return HttpResponseRedirect(url)
else:
return HttpResponse('两次密码不一致')
# 用户首页
def user_index(request):
if request.method == 'GET':
c_username = request.COOKIES.get('username')
print(c_username)
# notes = models.note.objects.get(user=c_username)
# print(notes)
return render(request, 'user_index.html',locals())
##缓存机制
创建一个缓存的表:
class my_cache_table(models.Model):
cache_key = models.CharField("cachekey", max_length=255, default='')
value = models.TextField("value", default='')
expires = models.DateTimeField("expires", auto_now=True)
#整体缓存
#局部缓存
方式1.多个cache项时
方式2.只有一个default项时
cache的使用:
##中间件1
工作原理 :
以下五种中间件的实现方式:
1.process_request(self,request) 进入路由之前进行拦截 主要是对某些IP的拦截
2.process_view(self,request,callback,callback_args,callback_kwargs)可以拿到视图的参数的
3.process_view(self,request,response)返回到网页的前一步进行过滤
4.process_exception(self,requset,exception) 企业开发抛出异常错误
创建middleware的文件夹 注意与整个大的项目在同一个目录:
from django.utils.deprecation import MiddlewareMixin
class MyMW(MiddlewareMixin):
# 请求到达之前
def process_request(self, request):
print('MyMW process_request do ---')
# 请求到达视图
def process_view(self, request, callback, callback_args, callback_kwargs):
print('MyMW process_view do ---')
# 请求输出给浏览器之前
def process_response(self, request, response):
print('MyMW prcoess_response do ---')
return response
在setting中注册middleware:
'middleware.mymiddleware.MyMW',
会先进入中间件执行过滤条件:
如有多个中间件 先进后出!!!
##中间件2
访问次数的限制:
class Timeslimite(MiddlewareMixin):
vist_time = {}
def process_request(self, request):
ip_address = request.META['REMOTE_ADDR']
path_url = request.path_info
if not re.match('^/test', path_url):
return None
times = self.vist_time.get(ip_address, 0)
print('ip', ip_address, '已访问', times)
self.vist_time[ip_address] = times + 1
if times < 5:
return
return HttpResponse('您已经访问过' + str(times) + '次,不能继续访问')
##csrf攻击
打开csrf:
当表单中没有开启{% csrf_token %}时候:
当表单中开启{% csrf_token %}之后:
##分页
Paginator对象
page对象
具体功能的实现:
def book_pagecut(request):
# 获取所有图书
books = Books.objects.all()
# 获取具体的页面
page_num = request.GET.get('page', 1)
# 将图书进行分页处理 得到paginator对象 (可以获取到所有页面的数量)
paginator = Paginator(books, 2)
# 获取具体页面的对象 里面有具体页面的各种信息 (包括是否有前一页后一页)
c_page = paginator.page(int(page_num))
return render(request, 'book_pagecut.html', locals())
<table border="2">
<tr><th>书名</th>
<th>作者</th>
<th>出版社</th>
<th>卖出价格</th>
<th>进价</th>
</tr>
{% for books in c_page %}
<tr>
<td>{{ books.book_name }}</td>
<td>{{books.book_actor}}</td>
<td>{{books.book_pub}}</td>
<td>{{books.book_markprice}}</td>
<td>{{books.book_price}}</td>
</tr>
{% endfor %}
</table>
{% if c_page.has_previous %}
<a href="{% url 'page_cut' %}?page={{ c_page.previous_page_number }}">上一页</a>
{% else %}
上一页
{% endif %}
{% for p_num in paginator.page_range %}
{% if p_num == c_page.number %}
{{ p_num }}
{% else %}
<a href="{% url 'page_cut' %}?page={{ p_num }}">{{ p_num }}</a>
{% endif %}
{% endfor %}
{% if c_page.has_next %}
<a href="{% url 'page_cut' %}?page={{ c_page.next_page_number }}">下一页</a>
{% else %}
下一页
{% endif %}