学习视频来源:最新Python的web开发全家桶
代码仓库:https://gitee.com/m_engmeng/django-learning
1. 创建项目
Django中项目会有一些默认的文件和文件夹
1.1 在终端
- 打开终端
- 进入某个目录(项目放在哪里)
- 输入命令——创建项目 (最后一个参数是项目名)
django-admin startproject mysite
- 继续输入—— 创建app (最后一个参数是app所处的路径以及名字)
python manage.py startapp myApp
1.2 默认项目的文件介绍
windows命令展示目录结构:
输入:tree
此时展现的是所有文件夹的路径所构成的树。
如果想连文件夹中的文件都展示,则输入:tree /f命令,可以显示所有资源。
mysite
- manage.py [项目的管理,启动项目、创建app、数据管理][不用改]
- mysite
- __init__.py
- settings.py [项目配置][**经常更改**]
- urls.py [URL和函数的对应关系] [**经常更改**]
- asgi.py [接收异步网络请求][不用改]
- wsgi.py [接受同步网络请求][不用改]
1.3 app(应用)
- 项目
- app: 用户管理 [独立的表结构、函数、HTML模板、CSS]
- app: 订单管理 [独立的表结构、函数、HTML模板、CSS]
- app: 后台管理 [独立的表结构、函数、HTML模板、CSS]
- app: 网站 [独立的表结构、函数、HTML模板、CSS]
- app: API [独立的表结构、函数、HTML模板、CSS]
...
APP 目录:
E:.
│ manage.py
│
├─myApp
│ │ admin.py [ 固定,不用动] django默认提供了admin后台管理
│ │ apps.py [ 固定,不用动] app启动类
│ │ models.py [ 重要 ] ,对数据库操作
│ │ tests.py [ 做单元测试]
│ │ views.py [ 重要 ] 函数
│ │ __init__.py
│ │
│ └─migrations [ 固定,不用动] 数据库变更记录
│ __init__.py
│
└─mysite
│ asgi.py
│ settings.py
│ urls.py
│ wsgi.py
│ __init__.py
└─__pycache__
settings.cpython-310.pyc
__init__.cpython-310.pyc
2 快速上手
2.1
-
运行前确保app已注册
- 首先找到 myApp中的apps文件,复制其中的类名MyappConfig
- 在mysite的文件夹下找到settings.py文件,在其中的INSTALLED_APPS 列表中,加入一行 ‘myApp.apps.MyappConfig’。
-
编写URL和视图函数的对应关系 (urls.py)
from myApp import views
urlpatterns = [
# path('admin/', admin.site.urls),
# 后面只要访问 xxx.com/index -> 就会对应views文件中的index函数
path('index/', views.index)
]
- 编写视图函数 [views.py]
from django.shortcuts import render, HttpResponse
# Create your views here.
# request 是默认参数,要加上
def index(request):
return HttpResponse("欢迎使用")
- 启动Django
- 命令行启动
python manage.py runserver
- 命令行启动
2.2 templates模板
在对应的app目录下创建templates文件夹,里面放置html文件
2.3 静态文件
在开发过程中一般将:
- 图片
- CSS
- js
在对应的app目录下创建static文件夹,里面分别创建- css文件夹
- img文件夹
- js文件夹
- plugins文件夹
如果想要引入static文件夹下的文件应作如下修改:
- 在settings.py的最后一行,加入:
STATIC_URL = '/static/'
STATICFILES_DIRS=(
os.path.join(BASE_DIR,'static'),
)
- 在html文件的body部分加入 {% load static %}
- 如果引用图片,则路径修改为:
<p>
<img src="{% static 'img/ger.jpg' %}" alt="germany" width="420" height="320">
</p>
3 Django模板语法
本质上:在HTML中写一些占位符,由数据对这些占位符进行替换和处理。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>tql</title>
</head>
<body>
<h1> Django模板语法学习 </h1>
<!-- 通过在函数中传入的字典的键来获取其值 -->
<div> {{ n1 }}</div>
<div> {{ n2 }} </div>
<hr />
<h2> 列表 </h2>
<!-- 获取列表中的值 -->
<div> {{ n2.0 }} </div>
<div> {{ n2.1 }} </div>
<div> {{ n2.2 }} </div>
<div> {{ n2.3 }} </div>
<!-- 通过循环获取列表中的值 -->
<div>
{% for item in n2 %}
<span> {{ item }} </span>
{% endfor %}
</div>
<hr />
<h2> 字典 </h2>
<div> {{ n3 }} </div>
<!-- 根据字典的键获取值 -->
<div> {{ n3.伯 }} </div>
<div> {{ n3.仲 }} </div>
<div> {{ n3.叔 }} </div>
<div> {{ n3.季 }} </div>
<!-- 遍历字典的键值对 -->
<ul>
{% for key,value in n3.items %}
<li> {{key}} = {{value}}</li>
{% endfor %}
</ul>
<hr />
<h2> 条件语句 </h2>
<!-- 条件判断 -->
{% if n1 == '季' %}
<h3>疾行</h3>
{% elif n1 == '霁月' %}
<h3>霁月</h3>
{% else %}
<h3>霁月壬</h3>
<button type="button" class="btn btn-info">信息</button>
{% endif %}
</body>
</html>
4 请求和响应
重定向: 浏览器向某个网站发送请求,网站返回给浏览器一个新的URL,浏览器去访问这个新的URL地址
# request 是一个对象,封装了用户发送过来的所有请求相关数据
# 1. [请求] 获取请求方式
print("用户请求的方式: " + request.method)
# 2. [请求] 在URL上传递值,例如 例如: http://123.249.26.154:5900/something/?n1=1&n2=2
print(request.GET)
# 3. [请求]在请求体中提交数据,目前是空值
print(request.POST)
# 4. [响应]HttpResponse("返回内容"),内容字符串内容返回给请求者
return HttpResponse("返回内容")
# 5. [响应]读取HTML的内容 + 渲染(替换) => 最终都转化为字符串返回给用户浏览器
return render(request, 'something.html', {"title":"Hello"})
# 6. [响应] 让浏览器重定向到其他的页面
return redirect("http://www.baidu.com")
5 数据库操作
Django 提供ORM框架来操控数据库
5.1 安装第三方模块
pip install mysqlclient
5.2 ORM
ORM可以帮助我们做两件事:
- 创建、修改、删除数据库中的表。[注:无法创建数据库]
- 操作表中的数据
5.2.1 自己创建数据库
- 启动Mysql服务
- 自带工具创建数据库
create database mydb DEFAULT CHARSET utf8 COLLATE utf8_general_ci;
5.2.2 django连接数据库(settings.py文件修改)
DATABASES = {
'default':{
'ENGINE':'django.db.backends.mysql',
'NAME':'mydb', # 数据库名字
'USER':'root',
'PASSWORD':'meng_19210504',
'HOST':'127.0.0.1',
'PORT':'3306',
}
}
5.2.3 Django操作表
- 创建表(models.py)
class UserInfo(models.Model):
name = models.CharField(max_length=32)
password = models.CharField(max_length=64)
age = models.IntegerField()
"""
上面的语句等同于
create table myapp_userinfo(
id bigint auto_increment primary key,
name varchar(32),
password varchar(64),
age int
)
"""
如果不想要某个表了,将class类注释后,重新执行 runsql.bat
- python3 manage.py makemigrations
- python3 manage.py migrate
- 修改表
-
- 默认值
修改表的话,如果原本表中存有数据,此时增加一个新的列,需要设定一个默认值。- 手动设定
age = models.IntegerField(default=2)
- 允许为空
data = models.IntegerField(null=True, blank=True)
- 手动设定
- 默认值
-
- 添加数据
如果某一列设置有默认值,那么可以不设置该列的数据,使用默认值
UserInfo.objects.create(name=“poker”, password=“123”, age=25)
- 添加数据
-
- 删除数据
# 删除数据 UserInfo.objects.filter(id=2).delete() # 删除表中所有数据 UserInfo.objects.all().delete()
-
- 获取数据
data_list = UserInfo.objects.all() print(data_list) for obj in data_list: print(obj.id, obj.name, obj.password, obj.age)
-
- 更新数据
UserInfo.objects.filter(name="roker").update(age=35)
-
案例:用户管理
-
urls.py
urlpatterns = [ # path('admin/', admin.site.urls), # 后面只要访问 xxx.com/index -> 就会对应views文件中的index函数 path('info/list/', views.info_list), path('info/add/', views.info_add), path('info/delete/', views.info_delete), ]
-
views.py中的info_list函数
def info_list(request): # 获取表中所有数据 data_list = UserInfo.objects.all() return render(request, 'info_list.html', {"data_list":data_list})
-
info_list.html
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Document</title> <!-- 新 Bootstrap 核心 CSS 文件 --> <link href="https://cdn.staticfile.org/twitter-bootstrap/3.3.7/css/bootstrap.min.css" rel="stylesheet"> <style> </style> </head> <body> <a href="/info/add">添加</a> <table border="1" class="table table-hover"> <thead> <tr> <th>ID</th> <th>姓名</th> <th>密码</th> <th>年龄</th> </tr> </thead> <tbody> {% for obj in data_list %} <tr> <td> {{ obj.id }} </td> <td> {{ obj.name }} </td> <td> {{ obj.password }} </td> <td> {{ obj.age }} </td> <td> <!-- 非常巧妙 --> <a href="/info/delete?nid={{ obj.id }}">删除</a> </td> </tr> {% endfor %} </tbody> </table> <!-- jQuery文件。务必在bootstrap.min.js 之前引入 --> <script src="https://cdn.staticfile.org/jquery/2.1.1/jquery.min.js"></script> <!-- 最新的 Bootstrap 核心 JavaScript 文件 --> <script src="https://cdn.staticfile.org/twitter-bootstrap/3.3.7/js/bootstrap.min.js"></script> </body> </html>
-
views.py中的info_add函数
def info_add(request): if request.method == 'GET': return render(request, 'info_add.html') else: # 获取用户提交的数据 name = request.POST.get("name") password = request.POST.get("pwd") age = request.POST.get("age") # 如果name或者password或者age有一个为空,就无法加入到数据库里面 if name=='' or password =='' or age=='': err_msgs = ['用户名不能为空', '密码不能为空', '年龄不能为空'] name_err, pwd_err, age_err = '', '', '' if name == '': name_err = err_msgs[0] if password == '': pwd_err = err_msgs[1] if age == '': age_err = err_msgs[2] return render(request, 'info_add.html', {"name_err":name_err, "pwd_err":pwd_err, "age_err":age_err}) # 添加到数据库 UserInfo.objects.create(name=name, password=password, age = age) # 自动跳转 return redirect("/info/list/")
-
info_add.html
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Document</title> <!-- 新 Bootstrap 核心 CSS 文件 --> <link href="https://cdn.staticfile.org/twitter-bootstrap/3.3.7/css/bootstrap.min.css" rel="stylesheet"> <style> </style> </head> <body> <form class="form-horizontal" role="form" action="/info/add/" method="post"> {% csrf_token %} <div class="form-group"> <label for="name" class="col-sm-2 control-label">用户名</label> <div class="col-sm-10"> <input type="text" class="form-control" id="name" name="name" placeholder="请输入名字"> </div> <label for="name_err" class="col-sm-2 control-label"></label> <div class="col-sm-10" style="color:red" name="name_err"> {{ name_err }} </div> </div> <div class="form-group"> <label for="pwd" class="col-sm-2 control-label">密码</label> <div class="col-sm-10"> <input type="text" class="form-control" id="pwd" name="pwd" placeholder="请输入密码"> </div> <label for="pwd_err" class="col-sm-2 control-label"> </label> <div class="col-sm-10" style="color:red" name="pwd_err"> {{ pwd_err }} </div> </div> <div class="form-group"> <label for="age" class="col-sm-2 control-label">年龄</label> <div class="col-sm-10"> <input type="text" class="form-control" id="age" name="age" placeholder="请输入年龄"> </div> <label for="age_err" class="col-sm-2 control-label"></label> <div class="col-sm-10" style="color:red" name="age_err"> {{ age_err }} </div> </div> <div class="form-group"> <div class="col-sm-offset-2 col-sm-10"> <div class="checkbox"> <label> <input type="checkbox">请记住我 </label> </div> </div> </div> <div class="form-group"> <div class="col-sm-offset-2 col-sm-10"> <button type="submit" class="btn btn-default">登录</button> </div> </div> </form> <!-- jQuery文件。务必在bootstrap.min.js 之前引入 --> <script src="https://cdn.staticfile.org/jquery/2.1.1/jquery.min.js"></script> <!-- 最新的 Bootstrap 核心 JavaScript 文件 --> <script src="https://cdn.staticfile.org/twitter-bootstrap/3.3.7/js/bootstrap.min.js"></script> </body> </html>
-
views.py中的info_delete函数
def info_delete(request): nid = request.GET.get("nid") UserInfo.objects.filter(id=nid).delete() return redirect("/info/list/")
Django开发(二)——部门列表展示、添加、删除、编辑
模板继承
当开发项目的时候,网页的导航栏等信息在多个网页中是相同的,所以为了降低每个网页的代码量,可以将网页中的相同的元素抽取出来,形成一个html文件,然后其他的网页继承该模板,在该模板上增加内容即可。
例如: 模板文件 layout.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Document</title>
<!-- 新 Bootstrap 核心 CSS 文件 -->
<link href="https://cdn.staticfile.org/twitter-bootstrap/3.3.7/css/bootstrap.min.css" rel="stylesheet">
<style>
</style>
</head>
<body>
{% block content %}
{% endblock %}
<!-- jQuery文件。务必在bootstrap.min.js 之前引入 -->
<script src="https://cdn.staticfile.org/jquery/2.1.1/jquery.min.js"></script>
<!-- 最新的 Bootstrap 核心 JavaScript 文件 -->
<script src="https://cdn.staticfile.org/twitter-bootstrap/3.3.7/js/bootstrap.min.js"></script>
</body>
</html>
继承文件:list.html
{% extends 'layout.html' %}
{% block content %}
<body>
<a href="/info/add">添加</a>
<table border="1" class="table table-hover">
<thead>
<tr>
<th>ID</th>
<th>姓名</th>
<th>密码</th>
<th>年龄</th>
</tr>
</thead>
<tbody>
{% for obj in data_list %}
<tr>
<td> {{ obj.id }} </td>
<td> {{ obj.name }} </td>
<td> {{ obj.password }} </td>
<td> {{ obj.age }} </td>
<td>
<!-- 非常巧妙 -->
<a href="/info/delete?nid={{ obj.id }}">删除</a>
</td>
</tr>
{% endfor %}
</tbody>
</table>
{% endblock %}
则在list.html文件中自动使用layout.html中的内容,将两块内容自动拼接。
如果想要不仅在网页的<body></body>
部分增添内容,还想要在<style></style>,<script></script>
等中添加内容,只需要多定义几个变量即可,示例如下:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Document</title>
<!-- 新 Bootstrap 核心 CSS 文件 -->
<link href="https://cdn.staticfile.org/twitter-bootstrap/3.3.7/css/bootstrap.min.css" rel="stylesheet">
{% block style %}
{% endblock %}
</head>
<body>
{% block content %}
{% endblock %}
<!-- jQuery文件。务必在bootstrap.min.js 之前引入 -->
<script src="https://cdn.staticfile.org/jquery/2.1.1/jquery.min.js"></script>
<!-- 最新的 Bootstrap 核心 JavaScript 文件 -->
<script src="https://cdn.staticfile.org/twitter-bootstrap/3.3.7/js/bootstrap.min.js"></script>
{% block script %}
{% endblock %}
</body>
</html>
可以看到,可以在任何地方自行添加要补充的内容,同时要注意 {}中的block这个是不能变的,block后面跟的是自定义的变量,变量名自定义
该案例中的模板html depart_layout.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Index</title>
<!-- 新 Bootstrap 核心 CSS 文件 -->
<link href="https://cdn.staticfile.org/twitter-bootstrap/3.3.7/css/bootstrap.min.css" rel="stylesheet">
</head>
<body>
<nav class="navbar navbar-default">
<div class="container">
<!-- Brand and toggle get grouped for better mobile display -->
<div class="navbar-header">
<button type="button" class="navbar-toggle collapsed" data-toggle="collapse"
data-target="#bs-example-navbar-collapse-1" aria-expanded="false">
<span class="sr-only">Toggle navigation</span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
</button>
<a class="navbar-brand" href="#">员工管理系统</a>
</div>
<!-- Collect the nav links, forms, and other content for toggling -->
<div class="collapse navbar-collapse" id="bs-example-navbar-collapse-1">
<ul class="nav navbar-nav">
<li><a href="#">部门管理</a></li>
<li><a href="#">部门管理</a></li>
</ul>
<ul class="nav navbar-nav navbar-right">
<li><a href="#">注册</a></li>
<li class="dropdown">
<a href="#" class="dropdown-toggle" data-toggle="dropdown" role="button" aria-haspopup="true"
aria-expanded="false">poker <span class="caret"></span></a>
<ul class="dropdown-menu">
<li><a href="#">Action</a></li>
<li><a href="#">Another action</a></li>
<li><a href="#">Something else here</a></li>
<li role="separator" class="divider"></li>
<li><a href="#">Separated link</a></li>
</ul>
</li>
</ul>
</div><!-- /.navbar-collapse -->
</div><!-- /.container-fluid -->
</nav>
<!-- 增加部分 -->
<div>
{% block content %}{% endblock %}
</div>
<!-- jQuery文件。务必在bootstrap.min.js 之前引入 -->
<script src="https://cdn.staticfile.org/jquery/2.1.1/jquery.min.js"></script>
<!-- 最新的 Bootstrap 核心 JavaScript 文件 -->
<script src="https://cdn.staticfile.org/twitter-bootstrap/3.3.7/js/bootstrap.min.js"></script>
</body>
</html>
展示
1. 在 urls.py 文件中增加path
path('depart/list/', views.depart_list)
2. 在 views.py 文件中编辑 depart_list 函数
def depart_list(request):
"""部门列表"""
depart_list = Department.objects.all()
return render(request, "depart_list.html", {"depart_list": depart_list})
3. 在templates文件夹下创建 depart_list.html (注:下面展示的是将所有功能都写好之后的html)
{% extends 'depart_layout.html' %}
<!-- 增加部分 -->
{% block content %}
<div class="container">
<div style="margin-bottom: 10px">
<a class="btn btn-primary" href="/depart/add/" target="_blank">新建部门</a>
</div>
<div class="panel panel-default">
<!-- Default panel contents -->
<div class="panel-heading">
<span class="glyphicon glyphicon-th-list" aria-hidden="true" style="margin-right: 5px;"></span>
<span> 部门列表 </span>
</div>
<!-- Table -->
<table class="table table-vordered">
<thead>
<tr>
<th>ID</th>
<th>名称</th>
<th>操作</th>
</tr>
</thead>
<tbody>
{% for obj in depart_list %}
<tr>
<th>{{ obj.id }}</th>
<td>{{ obj.title }}</td>
<td>
<a class="btn btn-primary btn-xs" href="/depart/{{ obj.id }}/edit/">编辑</a>
<a class="btn btn-danger btn-xs" href="/depart/delete/?nid={{ obj.id }}">删除</a>
</td>
</tr>
{% endfor %}
</tbody>
</table>
</div>
</div>
{% endblock %}
添加
1. 在 urls.py 文件中增加path
path('depart/add/', views.depart_add)
2. 在 views.py 文件中编辑 depart_add 函数
def depart_add(request):
"""添加部门"""
if request.method == "GET":
return render(request, "depart_add.html")
else:
# 获取用户提交的部门数据
depart_title = request.POST.get("depart_title")
# 保存用户提交的部门数据
Department.objects.create(title=depart_title)
return redirect("/depart/list/")
3. 在templates文件夹下创建 depart_add.html
{% extends 'depart_layout.html' %}
<!-- 增加部分 -->
{% block content %}
<div class="container">
<div class="panel panel-default">
<!-- Default panel contents -->
<div class="panel-heading">
<span class="glyphicon glyphicon-th-list" aria-hidden="true" style="margin-right: 5px;"></span>
<span> 新建部门 </span>
</div>
<div class="panel-body">
<form action="/depart/add/" method="post">
{% csrf_token %}
<div class="form-group">
<label>部门名称</label>
<input type="text" class="form-control" placeholder="部门名称" name="depart_title" />
</div>
<button type="submit" class="btn btn-primary">保存</button>
</form>
</div>
</div>
</div>
{% endblock %}
删除
1. 在 urls.py 文件中增加path
path('depart/delete/', views.depart_delete)
2. 在 views.py 文件中编辑 depart_delete 函数
def depart_delete(request):
"""部门删除"""
nid = request.GET.get('nid')
Department.objects.filter(id=nid).delete()
# 重定向回部门列表
return redirect('/depart/list/')
3. 这里不用专门创建一个删除页面,只需要在depart_list.html中的删除按钮添加一个跳转标签即可,在跳转标签中添加参数,如下:
<a class="btn btn-danger btn-xs" href="/depart/delete/?nid={{ obj.id }}">删除</a>
编辑
1. 在 urls.py 文件中增加path
path('depart/<int:nid>/edit/', views.depart_edit)
注: 其中<int:nid>
表示一个变量名为nid 的一个int变量,也就是如果要访问edit页面,必须在该位置传入一个int型整数
2. 在 views.py 文件中编辑 depart_edit 函数
注:这里,函数的参数列表里面增加了一个nid变量,这正好对应了网页链接中的<int:nid>
表示的整数,
def depart_edit(request, nid):
"""部门编辑"""
if request.method=="GET":
# 根据nid获取数据
# 这里如果不加first()函数,获取到的数据是一个列表类型,所以需要first函数获取第一个值
row_object = Department.objects.filter(id=nid).first()
return render(request, 'depart_edit.html', {"row_object":row_object})
else:
# 如果是POST请求保存修改
depart_title = request.POST.get('depart_title')
Department.objects.filter(id=nid).update(title=depart_title)
# 重定向回部门列表
return redirect('/depart/list/')
3. 在templates文件夹下创建 depart_edit.html
{% extends 'depart_layout.html' %}
<!-- 增加部分 -->
{% block content %}
<div class="container">
<div class="panel panel-default">
<!-- Default panel contents -->
<div class="panel-heading">
<span class="glyphicon glyphicon-th-list" aria-hidden="true" style="margin-right: 5px;"></span>
<span> 编辑部门 </span>
</div>
<div class="panel-body">
<form action="/depart/{{ row_object.id }}/edit/" method="post">
{% csrf_token %}
<div class="form-group">
<label>部门名称</label>
<!-- 这里 value就是默认值 -->
<input type="text" class="form-control" placeholder="部门名称" name="depart_title"
value="{{row_object.title }}" />
</div>
<button type="submit" class="btn btn-primary">保存</button>
</form>
</div>
</div>
</div>
{% endblock %}
<!-- jQuery文件。务必在bootstrap.min.js 之前引入 -->
<script src="https://cdn.staticfile.org/jquery/2.1.1/jquery.min.js"></script>
<!-- 最新的 Bootstrap 核心 JavaScript 文件 -->
<script src="https://cdn.staticfile.org/twitter-bootstrap/3.3.7/js/bootstrap.min.js"></script>
</body>
</html>
4. 同时要注意在depart_list.html页面中的编辑按钮 添加跳转链接
<a class="btn btn-primary btn-xs" href="/depart/{{ obj.id }}/edit/">编辑</a>