创建 django 项目
-
创建
- cmd
django-admin startproject s28(s28为项目名称)
- pycharm
…人家是专业版
File-》new project-》 左侧选择django-》输入项目的目录-》选择解释器 -
运行
cd s28
python manage.py runserver -
换端口
python manage.py runserver 80
-
换ip(不要使用被占用的)
python manage.py runserver 0.0.0.1:80
-
使用(urls.py)返回字符串
from django.contrib import admin
from django.urls import path
from django.shortcuts import HttpResponse
def index(request):
#逻辑
#返回结果
#导入from django.shortcuts import HttpResponse
return HttpResponse('index')
urlpatterns = [
path('admin/', admin.site.urls),
path('index/',index),#index为函数
]
from django.contrib import admin
from django.urls import path
from django.shortcuts import HttpResponse, render
def index(request):
# 逻辑
# 返回结果
# 导入from django.shortcuts import HttpResponse
return render(request,'index.html')
urlpatterns = [
path('admin/', admin.site.urls),
path('index/', index), # index为函数
]
注意:如果使用命令行创建的文件 ,则需要自行创建一个templates文件夹 ,然后再setting.py 添加templates的路径
TEMPLATES = [
{
‘BACKEND’: ‘django.template.backends.django.DjangoTemplates’,
‘DIRS’: [BASE_DIR / ‘templates’]
,
‘APP_DIRS’: True,
‘OPTIONS’: {
‘context_processors’: [
‘django.template.context_processors.debug’,
‘django.template.context_processors.request’,
‘django.contrib.auth.context_processors.auth’,
‘django.contrib.messages.context_processors.messages’,
],
},
},
]
登录界面设计(使用bootstrap)
静态文件导入
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-DKF6yPCf-1630375338784)(pic/静态文件结构.png)]
然后在setting.py文件中添加设置
STATICFILES_DIRS=[
BASE_DIR / 'static'
]
在官网登录界面中检查->资源->css->复制 得到signin.css,然后加入/static/css文件中
样式导入
<link rel="stylesheet" href="/static/plugins/bootstrap-3.4.1-dist/css/bootstrap.css">
<link rel="stylesheet" href="/static/css/signin.css">
注意:这里的文件夹可以改为任何名字,并不是static ,可以为static1 static2 static3 但是link的时候是/static/… 而不是/static1/… /static2…
在静态文件下,不要重名文件 否则只能按照seeting.py设置的顺序
酷炫登录界面
搜索
jq22.com
然后ctrl+s 复制 得到一个html文件+登录界面files(文件夹存放样式)
然后分别导入进静态文件夹
修改原文件
使用ctrl+r 然后使用正则替换,如
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-1vliFzL9-1630375338786)(pic/使用正则替换.png)]
实现登录
form表单注意的点:
1.form标签的属性 action 指定提交的地址(不写默认当前的地址),method请求方式(默认get)
2.input标签要有name属性,有的需要value
3.有一个button按钮 或者是type=“submit”的input
目前提交post请求的必要操作:
在setting.py中需要注释一个中间件:
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',
]
login.html
<form class="form-signin" action="" method="post">
<h2 class="form-signin-heading">Please sign in</h2>
<label for="inputEmail" class="sr-only">Email address</label>
<input type="email" name="user" id="inputEmail" class="form-control" placeholder="Email address" required="" autofocus="">
<label for="inputPassword" class="sr-only">Password</label>
<input type="password" name="pwd" id="inputPassword" class="form-control" placeholder="Password" required="">
<div class="checkbox">
<label>
<input type="checkbox" value="remember-me"> Remember me
</label>
</div>
<button class="btn btn-lg btn-primary btn-block" type="submit">Sign in</button>
</form>
urls.py
def login(request):
if request.method=='POST':
#处理post逻辑
print(request.POST['user'])
#获取用户提交的用户名和密码 这里使用get获取键值更好
user=request.POST.get('user')
pwd=request.POST.get('pwd')
#进行校验
if user=="208633445@qq.com" and pwd=='123':
#校验成功 告知登录成功
return HttpResponse("登录成功")
#校验失败 返回登录页面
return render(request,'login.html')
request:
request.method 请求方式 GET POST
request.POST form 表单提交post请求的数据
request.GET URL 上窗体参数(查询参数)
重定向
from django.shortcuts import HttpResponse, render,redirect
return return redirect('/index/') #跳转到index页面
重定向可以更改上面的跳转后浏览器的url不改变的情况
app的创建和注册
cd 项目后
python manage.py startapp app01(app名字)
进入setting.py 中,使用推荐写法
INSTALLED_APPS = [
'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
# 'app01', # 直接写app名字
'app01.apps.App01Config',#推荐写法
]
然后在app01-> views.py 中写函数 在原来的urls.py 中导入views 即可实现函数和列表分离
数据库表结构的创建和ORM的使用
ORM
对应关系:
类 -> 表
对象-> 数据行
属性-> 字段
使用ORM
1.配置setting.py中配置数据库的连接:
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.sqlite3',
'NAME': BASE_DIR / 'db.sqlite3',
}
}
2.在app下的models.py中写类:
class User(models.Model):
username=models.CharField(max_length=32) #varchar(32)
password=models.CharField(max_length=32)
3.执行数据库迁移
#检测所有app中的models.py文件有什么变化 将变更记录制作成迁移文件
python manage.py makemigrations
python manage.py migrate #数据库迁移
添加数据(手动)
点击右边数据库的表 点击id可以看到中间的表,然后点击加号添加
4.查询
from app01 import models
def index(request):
ret=models.User.objects.all()#对象列表
for i in ret:
print(i,i.username,i.password)
#获取对象
#ret=models.User.objects.get(username='208633445@qq.com',password="666666")
#ret = models.User.objects.get(password="666666")
#当获取的字段重复,会获取到一个以上的对象,就会报错
#获取满足数据的对象
ret = models.User.objects.filter(password="666666")
print(ret)
return render(request, 'index.html')
def login(request):
if request.method=='POST':
#处理post逻辑
print(request.POST['user'])
#获取用户提交的用户名和密码 这里使用get获取键值更好
user=request.POST.get('user')#字符串
pwd=request.POST.get('pwd') #字符串
#进行校验
if models.User.objects.filter(username=user,password=pwd):
#校验成功 告知登录成功
#return HttpResponse("登录成功")
return redirect('/index/') #跳转到index页面
#校验失败 返回登录页面
return render(request,'login.html')
查询
#对象列表
ret=models.User.objects.all()
#获取满足数据的对象列表(查询)
ret = models.User.objects.filter(password=“666666”)
#查询一条对象
ret=models.User.objects.get(username=‘208633445@qq.com’,password=“666666”)
mysql
启动遵循菜鸟教程
mysql -uroot -pXiaoming250
密码:Xiaoming250
1.创建数据库
2.然后在seeting.py中配置
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.mysql',
'NAME': 'login',
'HOST':'127.0.0.1',
'PORT':3306,
'USER':'root',
'PASSWORD':'Xiaoming250'
}
}
3.使用pymysql连接数据库,在setting.py中插入
习惯写入与项目同名的文件夹下的__init__.py中(二者都可以)
import pymysql
pymysql.install_as_MySQLdb()
4.在app01中写moudles
class User(models.Model):
username=models.CharField(max_length=32) #varchar(32)
password=models.CharField(max_length=32)
5.执行数据库迁移命令
python manage.py makemigrations
python manage.py makemigrate
在database中添加可视化
书籍出版社小项目
html 表格
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-PPrGZf3w-1630375338787)(pic/pub.png)]
<body>
<table border="1">
<thead>
<tr>
<th>序号</th>
<th>id</th>
<th>出版社名称</th>
</tr>
</thead>
<tbody>
<tr>
<td>1</td>
<td>1</td>
<td>商务印刷</td>
</tr>
</tbody>
</table>
</body>
实现返回页面数据
1.后端 返回字典,html的返回数据就是key
def publisher_list(request):
#逻辑
#获取出版数据
all_pusher=models.Publisher.objects.all()
for i in all_pusher:
print(i,i.name)
#返回页面,页面中包含出版信息
return render(request,'publisher_list.html',{'all_publishers':all_pusher})
2.html
其中 forloop.counter为循环的当前次数
<body>
<table border="1">
<thead>
<tr>
<th>序号</th>
<th>id</th>
<th>出版社名称</th>
</tr>
</thead>
<tbody>
{% for i in all_publishers %}
<tr>
<td>{{ forloop.counter }}</td>
<td>{{ i.id }}</td>
<td>{{ i.name }}</td>
</tr>
{% endfor %}
</tbody>
</table>
</body>
增加数据
<form action="" method="post">
出版社名称:<input type="text" name="pub_name">
<button type="submit">提交</button>
def publisher_add(request):
#如果是post请求
if request.method=='POST':
#获取提交数据
pub_name=request.POST.get('pub_name')
#将数据新增到数据库中
models.Publisher.objects.create(name=pub_name)
#返回一个重定向到展示出版社的页面
#get请求返回一个页面,页面包含form表单
return render(request,'publisher_add.html')
显示的顺序
all_pusher=models.Publisher.objects.all().order_by(‘id’)#升序
all_pusher=models.Publisher.objects.all().order_by(’-id)#降序
如果是已经存在的出版社
#若果数据库中有重复的名字
if models.Publisher.objects.filter(name=pub_name):
return render(request,'publisher_add.html',{'error':'出版社名字已经存在'})
删除
<td><a href="/publisher_del/?pk={{ i.id }}">删除</a></td>
def publisher_del(request):
#获取要删除的数据id
pk=request.GET.get('pk')
#根据id到数据库进行删除
models.Publisher.objects.get(pk=pk).delete()#查询到一个对象删除
#返回重定向到出版社页面
return redirect('/publisher_list/')
修改
<form action="" method="post">
出版社名称:<input type="text" name="pub_name" value="{{ pub_obj.name }}">
<span>{{ error }}</span>
<button type="submit">提交</button>
</form>
def publisher_edit(request):
#get 返回一个页面 页面包含form 表单 input有原始数据
pk=request.GET.get('pk')
pub_obj=models.Publisher.objects.get(pk=pk)
if request.method=='GET':
return render(request,'publisher_edit.html',{'pub_obj':pub_obj})
#post
else:
#获取用户提交的数据
pub_name=request.POST.get('pub_name')
#修改数据库中对应的数据
pub_obj.name=pub_name
#将修改操作提交到数据库
pub_obj.save()
#返回重定向展示出版社信息
return redirect('/publisher_list/')
外键
class Book(models.Model):
name=models.CharField(max_length=32)
publisher=models.ForeignKey(Publisher,on_delete=models.CASCADE)#默认是级联删除
#on_delete = models.CASCADE 级联删除
#on_delete=models.PROTECT 保护
#on_delete=models.SET() 删除后设置为某个值
#on_delete=models.SETDEFAULT ,default=1 删除后设置为一个默认值
#on_delete=models.SET_NULL 删除后设置为NULL
之后进行两条迁移指令
图书展示
同上
书籍增加
- option
<form action="" method="post">
书名:<input type="text" name="book_name">
出版社:
<select name="pub" id="">
{% for pulisher in pulishers %}
<option value="{{ pulisher.id }}">{{ pulisher.name }}</option>
{% endfor %}
</select>
<button >提交</button>
</form>
def book_add(request):
#post
if request.method=='POST':
#获取用户提交数据
book_name=request.POST.get('book_name')
pub_id = request.POST.get('pub')
print(pub_id)
#将数据插入到数据库中
models.Book.objects.create(name=book_name,publisher_id=pub_id)
#定向返回到展示书籍的页面
return redirect('/book_list/')
# 获取出版社
pub = models.Publisher.objects.all()
return render(request, 'book_add.html', {'pulishers': pub})
书籍删除
<td> <a href="/book_del/?id={{book.pk }}">删除</a></td>
#删除书籍
def book_del(request):
# 获取用户提交的信息
pk=request.GET.get('id')
#获取删除的对象
models.Book.objects.filter(pk=pk).delete()
#回复一个重定向的页面
return redirect('/book_list/')
编辑书籍
<form action="" method="post">
书名:<input type="text" name="book_name" value="{{ book_obj.name }}">
出版社:
<select name="pub" id="">
{% for pulisher in pulishers %}
{% if pulisher == book_obj.publisher %}
<option selected value="{{ pulisher.id }}">{{ pulisher.name }}</option>
{% else %}
<option value="{{ pulisher.id }}">{{ pulisher.name }}</option>
{% endif %}
<option value="{{ pulisher.id }}">{{ pulisher.name }}</option>
{% endfor %}
</select>
<button>提交</button>
</form>
新增更新方法
models.Book.objects.filter(pk=pk).update(name=book_name, publisher_id=publisher)
def book_edit(request):
pk = request.GET.get('id')
book_obj = models.Book.objects.get(pk=pk)
# post请求
if request.method == 'POST':
# 获取要编辑的对象
book_name = request.POST.get('book_name')
# 获取用户提交的数据
publisher = request.POST.get('pub')
# 编辑的对象的修改
# 方式一:
# book_obj.name=book_name
# book_obj.publisher_id=publisher
# book_obj.save()
# 方式二
models.Book.objects.filter(pk=pk).update(name=book_name, publisher_id=publisher)
# 重定向到展示页面
return redirect('/book_list/')
# get 请求
# 查询要编辑的id
all_publishers = models.Publisher.objects.all()
# 返回一个原始页面
return render(request, 'book_edit.html', {"book_obj": book_obj, 'pulishers': all_publishers})
# 根据id编辑对象
创建多对多的表
- models.ManyToManyField()
class Book(models.Model):
....................
class Author(models.Model):
name=models.CharField(max_length=32)
books=models.ManyToManyField('Book')#增加第三张表 将book和author关联 这句话可以写在Book里面也一样
书籍列表
<table>
<thead>
<tr>
<th>序号</th>
<th>id</th>
<th>姓名</th>
<th>代表作</th>
<th>操作</th>
</tr>
</thead>
<tbody>
{% for i in all_author %}
<tr>
<td>{{ forloop.counter }}</td>
<td>{{ i.id }}</td>
<td>{{ i.name }}</td>
<td>
{% for book in i.books.all %}
《{{ book.name }}》
{% endfor %}
</td>
<td><a class="btn btn-danger btn-sm" href="/author_del/?id={{ i.pk }}">删除</a>
<a class="btn btn-primary btn-sm" href="/author_edit/?id={{ i.pk }}">编辑</a>
</td>
</tr>
{% endfor %}
</tbody>
</table>
注意: #print(i.books.all())#所关联的列表
#作者列表
def author_list(request):
# 查询所有的作者
all_author=models.Author.objects.all()
# for i in all_author:
# print(i)
#print(i.id)
#print(i.name)
#print(i.books)#对象关系
#print(i.books.all())#所关联的列表
# print('*'*20)
# 返回一个作者的页面
return render(request,'author_list.html',{"all_author":all_author})
增加书籍
<form action="" method="post" >
<p>
作者姓名:<input type="text" name="author_name">
</p>
<p>
代表作:
<select name="book_id" id="" multiple>
{% for all_book in all_books %}
<option value="{{ all_book.id }}">{{ all_book.name }}</option>
{% endfor %}
</select>
</p>
<button>提交</button>
</form>
def author_add(request):
#post
if request.method=='POST':
#获取数据
author_name=request.POST.get('author_name')
book_id=request.POST.getlist('book_id')#获取多个返回数据列表
#插入
author_obj=models.Author.objects.create(name=author_name)
author_obj.books.set(book_id)#设置多对多关系
#返回重定向到作者页面
return redirect('/author_list/')
#get
#查询所有的书籍
all_book=models.Book.objects.all()
#返回一个页面
return render(request,'author_add.html',{'all_books':all_book})
删除书籍
#删除作者
def author_del(request):
#获取要删除的对象
pk=request.GET.get('id')
#根据id查到对象删除
models.Author.objects.filter(pk=pk).delete()
#返回重定向页面展示
return redirect('/author_list/')
编辑书籍
<form action="" method="post" >
<p>
作者姓名:<input type="text" name="author_name" value="{{ all_author.name }}">
</p>
<p>
代表作:
<select name="book_id" id="" multiple>
{% for all_book in all_books %}
{% if all_book in all_author.books.all %}
<option selected value="{{ all_book.pk }}">{{ all_book.name }}</option>
{% else %}
<option value="{{ all_book.id }}">{{ all_book.name }}</option>
{% endif %}
{% endfor %}
</select>
</p>
<button>提交</button>
</form>
- 修改多对多的关系
author_obj.books.set(book_id)#修改多对多的关系
#编辑
def author_edit(request):
# 获取要编辑的对象
pk = request.GET.get('id')
# 根据id查到对象
author_obj = models.Author.objects.get(pk=pk)
#post
if request.method=='POST':
author_name=request.POST.get('author_name')
book_id=request.POST.getlist('book_id')
#修改作者
author_obj.name=author_name
author_obj.save()
#修改作者代表作
author_obj.books.set(book_id)#修改多对多的关系
#返回重定向
return redirect('/author_list/')
#get
#获取所有书籍
all_book=models.Book.objects.all()
#返回重定向页面展示
return render(request,'author_edit.html',{"all_author":author_obj,"all_books":all_book})
MVC 和 MTV框架
MVC :
1.模型(moudles)操作数据库
2.视图(view)展示html
3.控制器(Controller)逻辑业务
Django借鉴了MVC的思想
MTV:
1.模型 ORM
2.模板(Template)
3.视图(View)负责逻辑
模板中的变量
{{变量名 }}和{% 逻辑 %}
python中可变的数据类型:
元组 数字 字符
<body>
<br>
{{ num }}
<br>
{{ string}}
<br>
{{ name_list.1 }}
<br>
{{ dic.name }}
<br>
{{ tup }}
<br>
{{ alex.name }}
</body>
.属性 .key .索引 .方法
过滤器
语法
{{value|filter_name:参数}}
如果没有传递参数过来可使用过滤器,加上默认值
注意不要空格:左边
{{ laobai|default:‘laobai’ }}
default:
变量为空或者没有数据时使用
{{value|filesizeformat}}
加法:
{{1|add:2}}
{{‘1’|add:’-2’}}
字符串相加
{‘1’|add:‘xxx’}
长度
{{ name_list|length }}
切片
{{ name_list|slice:‘0:2:1’ }}
取第一个元素
{{ value|first }}
拼接
join
截断 取前九个字符进行截断
{{ str|truncatechars:‘9’ }}
截断 按照单词进行截断
{{ str|truncatewords:‘9’ }}
{{ now|date:‘Y-m-d’ }}
日期
import datetime
{{now|date:‘Y-m-d H:i:s’}}
setting.py中修改
USE_I18N = True
USE_L10N = False
USE_TZ = True
DATETIME_FORMAT='Y-m-d H:i:s'
TIME_FORMAT='H:i:s'
DATE_FORMAT='Y-m-d'
safe
防止html进行转义
自定义过滤器
1.在app01下创建python包(templatetags 名字不能错)
2.创建mytags.py
3.在其中写:
from django import template
register=template.Library()
4.写函数+装饰器
@register.filter()
def add_arg(value,args):
#功能
return '{}_{}'.format(value,args)
5.使用自定义过滤器
{% load mytags %}
{{ alex.name|add_arg:'asd' }}
if、for、with、cstf_taken 标签
- for
forloop.counter 当前循环的序号 从1开始
forloop.counter0 当前循环的序号 从0开始
forloop.revcounter 当前循环的序号倒序 到1结束
forloop.revcounter0 当前循环的序号倒叙 到0结束
forloop.first 是否是第一次循环
forloop.last 是否是最后一次次循环
% for foo in kong %}
{{ foo }}
{% empty %}
空空如也
{% endfor %}
- if 支持过滤器,不支持±*/ 支持and
{% if alex.age < 73 %}
alexxxxxxx
{% elif alex.age == 73 %}
alexxxxxxx
{% endif %}
- with
作用:取别名
{% with dic as dic1 %}
{{ dic1 }}
{% endwith %}
- crsf_taken
from表单可以通过这里提交而不需要注释掉原来setting.py里的设置
<form action="" method="post">
{% csrf_token %}
<input type="text">
<button>提交</button>
</form>
母版和继承
- 母板
需要替换的部分使用block,其余的为模板
{% block main0%}
......
{% endblock %}
- 继承
相同的block可自由编写,这部分替换原来的block
{% extends 'publisher_list.html' %}
{% block main0%}
<li ><a href="/publisher_list/">出版社地址</a></li>
<li class="active"><a href="/book_list/">书籍列表</a></li>
<li><a href="/author_list/">作者</a></li>
<li><a href="#">Export</a></li>
{% endblock %}
组件和静态文件
1.把一段公用的html单独写进一个html
2.在需要组件的时候在该组件的模板中写入
{% include ‘nav.html’ %}
静态文件引入:
{%load static %}
<link rel="stylesheet" href="{%static '...子目录'%}">
获取静态文件的前缀 如/static/
{% get_static_prefix%}
simple_tag的定义和使用
解决之前过滤器参数太少的问题,但是不能用于if语句中
@register.simple_tag
def str_join(*args,**kwargs):
return '{}_{}'.format('_'.join(args),'*'.join(kwargs.values()))
{% str_join 'a' 'b' 'c' k1='d' k2='e' k3='f' %}
include_tag的使用
例子:分页
在mytags.py中写
@register.inclusion_tag('page.html')
def pagination(num):
return {'num':range(1,num+1)}
然后在将bootstrap中的分页效果加到page.html中
<nav aria-label="Page navigation">
<ul class="pagination">
<li>
<a href="#" aria-label="Previous">
<span aria-hidden="true">«</span>
</a>
</li>
{% for li in num %}
<li><a href="">{{ li }}</a></li>
{% endfor %}
<li>
<a href="#" aria-label="Next">
<span aria-hidden="true">»</span>
</a>
</li>
</ul>
</nav>
然后在需要分页的地方引入
{% load mytags %}
{% pagination 3 %}
视图
- CBV 和FBV
CBV: class based view
FBV:function based view
CBV视图
from django.views import view
class xxx(view):
def get(self,request):
#专门处理get请求
return response
def post(self,request):
#专门处理get请求
return response
url(r'xx/',xxx.as_view())
如果有公共的部分,那么
class PublisherAdd(View):
#共用的方法
def dispatch(self, request, *args, **kwargs):
#判断get post之前的操作
ret=super().dispatch(self,request,*args,**kwargs)#执行view中的dispath
return ret
def get(self,request):
print('get')
print(self.request is request)
return render(request,'publisher_add.html')
def post(self,request):
print('get')
print(self.request is request)
return render(request,'publisher_add.html')
给FBV加装饰器
import time
#统计时间的装饰器
def timer(func):
def inner(*args,**kwargs):
start=time.time()
ret=func(*args,**kwargs)
print('执行时间是{}'.format(time.time()-start))
return ret
return inner
@timer
def publisher_list(request):
..........
CBV加装饰器
导入包
from django.utils.decorators import method_decorator
- 方法1:
加在方法上面
@method_decorator(timer)
def get(self,request):
print('get')
print(self.request is request)
return render(request,'publisher_add.html')
- 方法2:
加在dispatch上面,相当于get和post上都有
@method_decorator(timer)
def dispatch(self, request, *args, **kwargs):
#判断get post之前的操作
ret=super().dispatch(self,request,*args,**kwargs)#执行view中的dispath
return ret
- 方法3:
加在类上面
@method_decorator(timer,name='get')
@method_decorator(timer,name='post')
class PublisherAdd(View):
......
request 对象
-
属性
request.method 请求方法 GET POST
request.GET url上携带的参数 ?k1=xxx&k2=xxx
requset.POST post请求提交的数据 编码方式是urlencode
request.path_info 路径信息 不包含ip和端口也不包含参数
request.body 返回请求体 byte类型
request.schema 返回是http 还是https
request.FILES 上传的文件
request.META 返回头的信息 小写-》大写 HTTP_开头
request.session
request.cookie -
方法
request.get_full_path() 完整的路径信息包含返回后面的参数
request.is_ajax() 判断是否是ajax请求
response对象
from django.short import render,HttpResponse,rediret
HttpResponse(‘xxx’)实例化一个对象,并且返回字符串
render(request,‘模板文件名’,{‘k1’:k1})函数
redirect(‘地址’)#重定向 响应头的内容 location+地址 301 302 的状态码
JsonResponse
字典转字符串叫做序列化
from django.http.response import JsonResponse
return JsonResponse({‘ka’:‘ka’})
如果是传的列表,那么需要加参数,safe=False
文件上传
<form action="" method="post" enctype="multipart/form-data">
{% csrf_token %}
<input type="file" name="f1">
<button>上传</button>
</form>
class upload(View):
def get(self,request):
return render(request,'upload.html')
def post(self,request):
file=request.FILES.get('f1')
with open(file.name,'wb') as f:
for i in file:
f.write(i)
return HttpResponse('OK')
url使用分组和命名分组
通过re在路由时使用
分组
url(r’^blog/([0-9]{4})/\d(2)/$’,views.blog)
url地址上捕获的参数会按照位置传参 方式传递给视图函数
def blog(request,year)
命名分组
url(r'^blog/(?<year>[0-9]{4})/(?<month>)\d(2)/$',views.blog)
url地址上捕获的参数会按照位置传参 方式传递给视图函数
def blog(request,year)
视图函数的默认参数
def page(request,name=‘xiaohua’)
include路由分发
在每一个app下面新建urls.py文件中
然后在外面的urls中
from django.contrib import admin
from django.urls import path,include
from app01 import views
urlpatterns = [
path('admin/', admin.site.urls),
path('app01/',include('app01.urls')),
path('app02/', include('app02.urls')),
]
url的命名和反向解析
静态路由
命名:
url(r’^blog/$’,views.blog,name=‘blog’) #/app01/blog/ =>blog
反向解析:
模板
{% url ‘blog’ %} ->/app01/blog
在py中:
url=reverse(‘blog’)#可获得路径
动态路由
命名
url(r’^blog/([0-9]{4})/(\d{2})/$’,views.blog,name=‘blog’)
反向解析
{% url ‘blog’ ‘2020’ ‘20’%} # url=app01/blog/2020/20
在py中获取url
url=reverse(‘blogs’,args=(‘2018’,‘08’)) #url=app01/blogs/2018/08
namespace
解决不同app下相同name的问题
urlpatterns = [
path('admin/', admin.site.urls),
path('app01/',include('app01.urls',namespace='app01')),
path('app02/', include('app02.urls',namespace='app02')),
]
py
reverse(‘app01:blogs’,args=(‘2018’,‘08’))
反向解析
{% url ‘app01:blog’ ‘2020’ ‘20’%}
常用数据库字段
class Person(models.Model):
pid=models.AutoField()#自增
name=models.CharField(max_length=32)
age=models.IntegerField()#-2147483648~+2........
birth=models.DateTimeField(auto_now_add=True)#每新增数据时自动保存当前时间
#auto_now 每次修改后都保存时间
Boolean 布尔型
TextField 文件型
FloatField浮点型
自定义字段
作者太懒了,参考网上
字段参数
null=True #可以为空
db_column字段的名字
unique=True
choice=((True,'男'),(False,'女'))
使用django的admin
1.创建一个超级用户
python manage.py createsuperuser
2.注册moudles
在app下的admin下
from app01 import models
admin.site.register(models.Publisher)
然后在moudles中 返回
class Publisher(models.Model):
name =models.CharField(max_length=32)
def __str__(self):
return self.name
3.登录
后续懒得写了
(https://developer.mozilla.org/zh-CN/docs/Learn/Server-side/Django/Testing)
查询语句
- 查询所有数据
models.Person.objects.all()
- 获取唯一的数据
models.Person.objects.get()
- 获取满足条件的数据
models.Person.objects.filter()
- 按照条件排序(默认升序)字段前加‘-’为降序
models.Person.objects.all().order_by(‘age’)
- reverse对已经排序的对象序列反转
models.Person.objects.all().reverse()
- 获取数据所有的字段和值QuerySet [{ },{ },{ }]
models.Person.onjects.all().values(‘pid’,‘name’)
- 不指定字段获取所有的值
models.Person.onjects.all().values_list(‘pid’,‘name’)
- 去重
models.Person.onjects.all().destinct()
models.Person.onjects.values(‘age’).destinct()
- 计数
models.Person.onjects.all().count()
- 获取第一个/最后一个数据
models.Person.onjects.all().first()
models.Person.onjects.all().last()
- 查询是否有结果
models.Person.onjects.filter().exists()
- 排除
models.Person.onjects.all().exclude(pk=1)
单表的下划线
- 小于
models.Person.onjects.filter(pid__lt=6)#小于6
- 大于
models.Person.onjects.filter(pid__gt=6)#大于6
- 小于等于
models.Person.onjects.filter(pid__lte=6)
- 大于等于
models.Person.onjects.filter(pid__gte=6)
- 范围(左右都包含)
models.Person.onjects.filter(pid__range=[1,6])
- 属于范围
models.Person.onjects.filter(pid__in=[1,5,6,3])
- 包含
models.Person.onjects.filter(name__contains=‘alex’)#sql like
- 包含(忽略大小写)
models.Person.onjects.filter(name__icontains=‘alex’)#sql like
- 以什么开头
models.Person.onjects.filter(name__startwith=‘alex’)
- 以什么开头(忽略大小写)
models.Person.onjects.filter(name__startwith=‘alex’)
- 以什么结尾
models.Person.onjects.filter(name__endtwith=‘alex’)
- 以什么结尾(忽略大小写)
models.Person.onjects.filter(name__iendwith=‘alex’)
- 查找日期
models.Person.onjects.filter(birth__year=‘2019’)
models.Person.onjects.filter(birth__month=‘2019’)
models.Person.onjects.filter(birth__day=‘2019’)
models.Person.onjects.filter(birth__contains=‘2019-01-01’)
models.Person.onjects.filter(birth__contains=’-01-01’) - 查找字段为null
models.Person.onjects.filter(name__isnull=True)
外键操作
- 正向查询 同上
- 反向查询
per=models.Person.onjects.get(pk=1)
print(per.per_set.all())
#小写类名_set 或者自定义数据库的时候加上参数 related_name=‘books’ - 基于字段的查询 pub是外键 name是出版社的字段
models.Book.objects.filter(pub__name=‘新华出版社’)#也可同上指定related_query_name,pub则也改为相应的数据
多对多
设置多对多关系
set方法
添加多对多的关系
author_obj.books.add(1,2)
author_obj.books.add(*modles.Book.objects.filter(id__in=[3,4]))
移除
author_obj.books.remove(1,2)
author_obj.books.remove(*modles.Book.objects.filter(id__in=[3,4]))
清空多对对关系
author_obj.books.clear()
新建
author_obj.books.create(name=‘倜然’,pid=‘12’)
聚合和分组
- 导入
from django.db.models import Max, Min,Count,Sum,Avg
- 使用 aggregate为终止字句
models.Book.objects.all().aggregate(Max(‘price’),min(‘price’))
分组group
按照书分组计数作者
annotate 注释 过程使用了分组
ret=models.book.objects.annotate(Count(‘authors’).values())
统计每一出版社卖的最便宜的书的价格
ret=models.Pulisher.object.annotate(Min(‘book_price’)).values()
按照pub ,pub_name分组
ret=models.book.object.values(‘pub’,‘pub_name’).annotate(Min(‘Price’))
统计不止一个作者的图书
ret=models.Book.objects.annotate(count=Count(‘author’)).filter(count__gt=1)
F和Q
- 导入
from django.db.modles import F ,Q
modles.book.objects.filter(sale_gt=F('kucun)) #where sale>kucun
modles.book.objects.filter(id__lte=3).update(‘sale’)*3+13)
Q ( )
|
&
~
re=modles.book.objects.filter(Q(id__lt=3),Q(id__gt=5))
re=modles.book.objects.filter(Q(id__lt=3)|Q(id__gt=5))
事务
from django.db import transaction
try:
with transaction.atomic():
models.Book.objects.all.update(kucun=F('kucun')-10)
int('sss')
models.Book.objects.all.update(kucun=F('kucun')-10)
except Exception as e
print(e)
cookie
保存在浏览器本地的一组组键值对
django中操作cookie
登录时的cookie
-
导入
from functools import wraps
-
写装饰器
def login_required(func): @wraps(func) def inner(request,*args,**kwargs): # 是否登陆了 is_login = request.COOKIES.get('is_login') # 登录了 if is_login != '1': return redirect('/login/?url={}'.format(request.path_info)) ret=func(request,*args,**kwargs) return ret return inner
-
然后加装饰器
-
优化登录(返回登录前的页面)
def login(request): if request.method=='POST': user=request.POST.get('user') pwd=request.POST.get('pwd') if user=='alex' and pwd=='123': #登录成功之后保存登录状态到cookie #如果有返回的页面(没有登录前) url=request.GET.get('url') if url: urld=url print(url) else: urld='/publisher_list/' ret = redirect(urld) ret.set_cookie('is_login', '1') return ret else: error='' return render(request,'login.html',locals())
cookie操作
设置cookie
repponse.set_cookie(key,value)
response.set_signed_cookie(key,value,salt='s28')# 加密
max_age超时时间
path 是cookie生效的页面
secure=False https进行传输
httponly =False 无法被js获取
设置cookie
response.COOKIE()
response.get_signed_Cookie(key,salt='s28',defalut='')#加密
删除cookie 设置cookie为0 超时时间为0
response.delete_cookie(key)