根据b站视频https://www.bilibili.com/video/BV1bW411N7xN?p=8整理的
不清楚可以去看视频哟
1前期准备
pip freeze # 查看已安装的包
pip install django==2.0.5 # 安装django2.0.5
cd .. #返回上一级
cd Django_Projects
django-admin startproject to_do_list # 创建项目
cd to_do_list # 进入项目文件夹
python manage.py runserver # 启动服务器
# 在浏览器网址栏输入 localhost:8000
ctrl + c # 关闭服务器
成功显示如下
2准备app
- 激活虚拟环境
cd desktop
cd Django_venv # 到虚拟环境文件夹
cd Scripts # 执行该文件
activate
cd ..
cd Django_Projects
cd to_do_list # 进入todo项目文件夹
python manage.py runserver # 启动服务器
ctrl+c 关闭服务器
- 一个app负责一种功能 创建一个 todolist App 负责实现 待办事项 功能
python manage.py startapp todolist
将to_do_list整个拖到文本编辑器
- 注册该app,告诉服务器我存在
在settings.py INSTALLED_APPS 中加入
'todolist',
- 在这个app里面做个html网页,放在templates(网页模板)文件夹中
右键 new file home.html
!tab
h1 tab 会自动生成
右键 open in browser 选default 选择其他可能会出现找不到文件chrome
这种问题主要是因为在pycharm中关于chrome的安装路径配置不正确造成的,具体的解决办法为:
打开pycharm–》File–》setting–》Tools–》Web Browsers
然后添加chrome安装路径,然后就成功啦~
3配置url和view
- 设置好网址, 给这个页面起个什么网址
- 当用户通过这个网址发出请求时,将网页发送给他
- 因为这个网页是待办事项网页, 网址设置和用户请求都让 todolist APP处理
to_do_list/to_do_list/urls.py [所有网址首先由它接手]
||
||
\ /
\/
to_do_list/todolist/urls.py [与待办事项相关的网址交给我接手]
||
||
\ /
\/
to_do_list/todolist/views.py [用户通过这些网址发出的请求的由我来处理]
这里django可能下滑波浪线 可以在settings把环境选在scripts下 因为刚开始装的时候是吧django装在scripts下
4.bootstrap导航栏
https://v4.bootcss.com/docs/4.0/examples/ 找到Navbar static 复制源代码
替换cdn
5.bootstrap表格
https://v4.bootcss.com/docs/4.0/content/tables/
6.bootstrap表单
https://v4.bootcss.com/docs/components/forms/
7.网址名,网页名
关于include()
大项目 -> 要避免网址名 网页名冲突
render() 如何找到网页 ?
根据所提供的网页名称,找所有的templates的文件夹,取第一个匹配的
网页名字重复怎么办?
给个前缀
建个新文件夹在templates下,以 app的名字 命名
templates/app的名字/网页名字
views.py -> return render(request, "todolist/home.html")
<a href="hostname/urlpattern"></a>
想改网址怎么办?要改的地方好多o(╥﹏╥)o
给网址起名字
<a href="{% url 'url_name' %}"></a> template tag{% tag_name %}
网址名跟其他app里面的网址名字重复怎么办?
给个前缀
8 模版继承
我想改变导航栏的样式怎么办? 3个网页都要改?
Template inheritance
做个模板html(所有网页的风格主题), 其他网页继承它,拓展它, 类似python的类继承
extends
{% extends "base.html" %}
block tag
{% block blockname %}
{% endblock blockname %}
three-level 大网站建议三级,小网站两级
article.html
/
base_news.html
/ \
base.html live.html
\
base_sports.html
到main之前的 和之后的粘贴下来 做成base.html
{% block 主体%}
{% endblock 主体 %}
在被剪切的那个网页放入
{ % extends "todolist/base.html"%}
{% block 主体 %}
9.静态文件
新建static文件夹,存放 图片 css javascript
里面,再新建一个app文件夹,避免与其他app的static文件夹里面的静态文件冲突
app/static/app/images
app/static/app/js
app/static/app/css
app/static/app/icons
{% load static %}
{% static "路径" %}
10.处理用户请求
request GET
HTML form -> action="" method="POST" button->submit
{% csrf_token %} 跨站请求伪造
name="" 给input的起名字
request.POST是什么? QueryDict
content dictionary 在html中通过var访问字典
{{ var }} 变量{{ }} 和标签{% %}
post是发送请求 action='' 表发送到自己的服务器
11.增删改查
刷新后会出现如图错误 因为我们定义的是post 而刷新方法是get
所以 要承担用户的post和get请求
增删改查 用字典存储, 只要服务器开着…
如果是get请求怎么办? 比如刷新 判断request.method 如果是get 只要将原来页面返回给他即可
def edit(request):
# 显示回给用户
if request.method=='POST':
content = {'待办事项': request.POST['待办事项']} # 因为request.post是字典 可以找他的key 而找到所对应的值
return render(request,"todolist/edit.html",content) #值显示在这个网页中
elif request.method=='GET':
return render(request, "todolist/edit.html")
如果是get请求怎么办? request.POST 中不存在’待办事项’这个键
如果是post请求, 但用户不写内容怎么办? request.POST 中的’待办事项’这个键对应值为 空的字符串 ‘’
def edit(request):
# 显示回给用户
if request.method=='POST':
if request.POST['待办事项']==' ':#如果用户在待办里什么都不写 返回给页面警告
return render(request,"todolist/edit.html", {'警告':'请输入内容!'})
else:
content = {'待办事项': request.POST['待办事项']} # 因为request.post是字典 可以找他的key 而找到所对应的值
return render(request,"todolist/edit.html",content) #值显示在这个网页中
elif request.method=='GET':
return render(request, "todolist/edit.html")
用GET方法删除,划掉真的对吗? 用隐藏的form
全局列表
{% for in %}
{{ forloop.counter }}
{% if %}
{% else %}
{% endif %}
{% endfor %}
"{% url 'todolist:删除' forloop.counter %}" #中间的空格相当于/
del/<forloop_counter>
#按照序号删除
def delete(request,forloop_counter):
lst.pop(int(forloop_counter)-1)
return redirect("todolist:编辑") #不是渲染 render 而是跳转到网址去(有名字的地方 不是网站)
redirect()
重点在于 查找路径todo/ del/<forloop_counter> 当你删除序号的待办事项 是todo/ del/2
12.bootstrap弹窗
https://v4.bootcss.com/docs/4.0/components/alerts/
<div class="alert alert-warning alert-dismissible fade show" role="alert">
<strong>Holy guacamole!</strong> You should check in on some of those fields below.
<button type="button" class="close" data-dismiss="alert" aria-label="Close">
<span aria-hidden="true">×</span>
</button>
</div>
js
<script src="https://code.jquery.com/jquery-3.3.1.slim.min.js" integrity="sha384-q8i/X+965DzO0rT7abK41JStQIAqVgRVzpbzo5smXKp4YfRvH+8abtTE1Pi6jizo" crossorigin="anonymous"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.14.3/umd/popper.min.js" integrity="sha384-ZMP7rVo3mIykV+2+9J3UJ46jBk0WLaUAdn689aCwoqbBJiSnjAK/l8WvCWPIPm49" crossorigin="anonymous"></script>
<script src="https://stackpath.bootstrapcdn.com/bootstrap/4.1.1/js/bootstrap.min.js" integrity="sha384-smHYKdLADwkXOn1EmN1qk/HfnUcbVRZyYmZ4qpPea6sjB/pTJ0euyQp0Mk8ck+5T" crossorigin="anonymous"></script>
Modal https://v4.bootcss.com/docs/4.0/components/modal/
13.数据库
数据库,建标
CREATE TABLE 待办事项表
(
序号 INT NOT NULL AUTO_INCREMENT,
待办事项 VARCHAR(100) NOT NULL,
已完成 tinyint(1) NOT NULL DEFAULT 0,
PRIMARY KEY (序号)
)ENGINE=InnoDB CHARSET=utf8;
增加数据
INSERT INTO 待办事项表 (待办事项) VALUES ('看电影');
INSERT INTO 待办事项表 (待办事项) VALUES ('逛街');
INSERT INTO 待办事项表 (待办事项) VALUES ('陪客户吃饭');
建表 和 增删改查 django都能帮我们搞定
设置数据库连接
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.sqlite3',
'NAME': os.path.join(BASE_DIR, 'db.sqlite3'),
}
}
create Model
创建Model类,用来描述表的构成: 有哪些列(待办事项,完成状态,序号…)
这是给网站开发者看的
makemigrations -> 中文:制作迁移文件
例如:0001_initial.py 也是用来描述表的构成
django会利用这个文件来建表改表
每次新增model(表) 或者 修改model(表的构成) 都要 makemigrations
这是给django自己看的,它用这个文件来建表或修改表
python manage.py sqlmigrate todolist 0001 不会真的建表,只是查看
查看django用 0001_initial.py 文件, 转化成了什么sql语句(不同的数据库服务器,语句不一样)帮我们建表, todolist是app的名字
BEGIN;
--
-- Create model Todo
--
CREATE TABLE "todolist_todo" (
"id" integer NOT NULL PRIMARY KEY AUTOINCREMENT,
"thing" varchar(50) NOT NULL,
"done" bool NOT NULL
);
COMMIT;
migrate -> 中文:迁移,即运行这个文件 0001_initial.py 真正在数据库中建表,或修改表的结构
python mange.py shell
from todolist.models import Todo
Todo.objects.all() -> QuerySet 查询集合 简单理解为表中的所有数据
-> 所有行的集合__str__ 显示更友好,命令行以及admin界面
Todo.objects.count() -> 行的数量
a_row = Todo(thing='逛街', done=False) -> 创建一行数据, 但并未保存
a_row.save() -> 真正保存到库中
a_row.id -> 保存之后才有id(序号)
a_row.thing -> 获取这一行的 thing(待办事项) 的值
Todo.objects.filter(done=False) -> 获取 [[所有]] done 为 False 的行, 即未完成的事项, 结果是个集合
another_row = Todo.objects.get(thing='逛街') -> 获取 thing 为 的行,仅一行
get不到会报错
another_row.thing = '去超市' -> 修改这一行的thing为 '去超市'
another_row.save() -> 改完别忘了保存
another_row.delete() -> 删除这一行
Todo.objects.all() -> 看看现在有什么
exit() ctrl+z 回车
Register Models -> 注册model 注册后, 可以通过django自带的app -> admin后台界面来管理表数据
a = Todo.objects.get(id=2)
a.delete()
def cross(request,i_id):
if request.POST['完成状态']=='已完成':
a = Todo.objects.get(id=i_id)
a.done=True
return redirect("todolist:编辑")
else:
a = Todo.objects.get(id=i_id)
a.done= False
return redirect("todolist:编辑")
#点击划掉按钮 会向划掉网址发送一个请求 post请求里面包含来了一个‘完成状态’信息
其对应的值是已完成 然后交给views.py 的cross处理
—————————————————————————————————————————————
登录注册
思路
1auth.urls
from django.contrib import admin
from django.urls import path,include
urlpatterns = [
path('admin/', admin.site.urls),
path('', include('myauth.urls')),
]
2 myauth.urls
from django.urls import path,include
from . import views
app_name='myauth'
urlpatterns = [
path('',views.主页,name='主页'),
path('login/',views.登录,name='登录'),
]
3 views.py
def 主页(请求):
return render(请求,'myauth/home.html')
4 html
创建超级管理员
python manage.py createsuperuser
python manage.py runserver 开启服务器
在model中建表 建注册的新要求
from django.db import models
from django.contrib.auth.models import User
# Create your models here.
class 普通会员表(models.Model):
用户=models.OneToOneField(User,on_delete=models.CASCADE)
昵称=models.CharField(blank=True,max_length=50)
生日=models.DateField(blank=True,null=True)#生日可以为空 修改model后要重新建立迁移文件
class Meta:
verbose_name_plural="普通会员表s"
之后在cmd输入以下两句 真正的建表
python manage.py makemigrations
python manage.py migrate
在admin.py
from django.contrib import admin
from django.contrib.auth.admin import UserAdmin as BaseUserAdmin
from django.contrib.auth.models import User
from .models import 普通会员表
class 普通会员表Inline(admin.TabularInline):#两张表一起显示 表格显示法 一对一
model= 普通会员表
can_delete = False
verbose_name_plural = '普通会员表'
class UserAdmin(BaseUserAdmin):
inlines = (普通会员表Inline,)
admin.site.unregister(User)
admin.site.register(User,UserAdmin) #重新注册 前者注册model这个表 后者注册配置文件
新建forms.py
from django.contrib.auth.forms import UserCreationForm
from django.contrib.auth.models import User
from django import forms
#创建一个表单给用户填写 之前的UserCreationForm是django帮我们写的 所以现在新建的继承UserCreationForm
class 自定义注册表单(UserCreationForm):
昵称 = forms.CharField(required=False, max_length=50)#required=False昵称不一定写
生日 = forms.DateField(required=False)
class Meta:
model=User #自定义注册表属于普通会员表 而其又属于User(UserCreationFor创建产生的
fields=('username','password1','password2','email','昵称','生日')#指定非超级用户(管理员)什么地方可以编辑什么地方不可以
之后再views.py 导入
from .forms import 自定义注册表单
将UserCreationForm替换成自定义注册表单
若不满意django自带的错误提示 可以用if else 自己写
或者自定义错误 但是一般比较麻烦的是不知道对应的键值 所以输入as.json
这样就知道键值是 invalid
可以在def 中修改invalid的值
建立个人中心
现有网址再有网页再有函数
urls.py
path('user_center/',views.user_center,name='个人中心'),
path('user_center/edit_profile',views.编辑个人信息,name='编辑个人信息'),
path('user_center/change_password',views.修改密码,name='修改密码'),
views.py
from django.contrib.auth.decorators import login_required
@login_required(login_url="myauth:登录") #一定要登录 没登录的话跳到登录页面
def 个人中心(请求):
return render(请求,'myauth/user_center.html')
@login_required(login_url="myauth:登录")
def 编辑个人信息(请求):
if 请求.method == 'POST':#编辑成功到中心
return redirect(请求,'myauth/user_center.html')
else:#get 是想编辑
return render(请求, 'myauth/edit_profile.html')
@login_required(login_url="myauth:登录")
def 修改密码(请求):
if 请求.method == 'POST': # 编辑成功到中心
return redirect(请求, 'myauth/user_center.html')
else: # get 是想编辑
return render(请求, 'myauth/change_password.html')