Django入门课程二
1:web网站的设计哲学(MVC/MTV的设计哲学)
用户输入网址是哪里定义的呢?——URL用户两种访问模式读(get)/写(post),谁来处理?——view(control)view处理的需要数据在哪存着的呢?——modelview处理完毕,用户请求看到的页面是谁渲染的呢?——template(view)2:Request && response
1: Request——用户有5种方式对服务器发起请求
GET请求不带参数 常用带参数?参数—— url 常用位置参数——url设计 不常用关键字参数——url设计 最常用POST请求(正常情况下都会带参数) 常用语表单场景
两种url来承接5种请求#get不带参数 get通过?加参数 post请求的url格式如下path('hello/', views.index, name='index'),#关键字传参数 (?<参数名>参数类型)——视图中直接通过参数名获取值(最常用)re_path('hello/(?P<year>[0-9]{4})/(?P<month>[0-9]{2})/', views.index, name='index')]
2:Response——2大类3小类获取到数据
request.method —— 判断请求的方式
request.body —— 第一种获取数据数据的方式
print(type(request.body)) # byteprint(QueryDict(request.body)) # QueryDictprint(QueryDict(request.body).dict) # dict
request.GET # 第二种方式获取GET QueryDictrequest.GET.get('name','devops')
request.POST # 第二种获取post数据方式 <QueryDict: {'year': ['2019']request.POST.getlist('id')
1. 安装mysql驱动
pip3 install mysqlclient
如果报错,请参考:https://blog.51cto.com/qiangsh/2422115
2. 修改数据库配置
$ cat devops/settings.py # 注释原有数据库配置# Database# https://docs.djangoproject.com/en/2.2/ref/settings/#databases## DATABASES = {# 'default': {# 'ENGINE': 'django.db.backends.sqlite3',# 'NAME': os.path.join(BASE_DIR, 'db.sqlite3'),# }# }# 使用mysql数据库替换掉上面sqlite3DATABASES = { 'default': { 'ENGINE': 'django.db.backends.mysql', 'NAME': 'devops', 'USER': 'devops', 'PASSWORD': '123456', 'HOST': '127.0.0.1', 'PORT': '3306', }}
3. 初始化数据库(需要在setting中注册APP)
# 查看现有的迁移文件的状态,是否同步到数据库中python manage.py showmigrations# 同步models到本地数据库文件python manage.py makemigrations# 同步数据库文件里的sql预计到数据库执行python manage.py migrate# 创建admin超级管理员(登录Django Admin页面使用)python manage.py createsuperuser# 启动python manage.py runserver 0.0.0.0:8000
MTV之模板继承——简化代码
1: HTML、CSS
table$ view.pyreturn render(request, 'index.html', {"user":user})
$ index.html<table><thead><tr> <th>姓名</th><th>年龄</th></tr><thead><tbody>{% for user in users %}<tr> <td>{{user.name}}</td><td>{{user.age}}</td></tr>{% endfor %}</tbody></table>
form
$ login.html<form method="POST",action="{% url 'hello:login' %}"><input name='username' type="text" ><input name='passwd' type="password" ><button type="submit">登录</button></form>
2: bootstrap
栅栏思想——庖丁解牛调用组件——擅假如物3: 实战——打通TV,模板继承,渲染一个表格数据
用户访问http://127.0.0.1:8000/hello/list第一步:定义用户访问入口——url$ cat hello/urls.pyapp_name = 'hello'urlpatterns = [ path('list/', views.list, name = 'list'),]
第二步:编写对于url的view,提供伪数据来处理用户请求
$ cat hello/views.pydef list(request,*args,**kwargs): users = [ {'username': 'qsh2', 'name_cn': 'qsh2', 'age': 18}, {'username': 'qsh3', 'name_cn': 'qsh3', 'age': 19}, {'username': 'qsh4', 'name_cn': 'qsh4', 'age': 20}, ] return render(request,'list.html',{'users':users})
第三步:模板继承及渲染
$ cat templates/base.html # 模板…… {% load static %} <title>{% block title %} 自动化运维平台 {% endblock %} </title> <a href="{#% url 'users:user_detail' request.user.id %#}" class="btn btn-default btn-flat">个人主页</a> <!-- 第二层右边内容部分 --><div class="content-wrapper"> <!-- 面包屑导航部分 --> <section class="content-header"> {% block breadcrunb %} {% endblock %} </section> <!-- 主要内容 --> <section class="content"> {% block content %} {% endblock %} </section></div><!-- 第二层右边结束 -->……
$ cat templates/list.html # 子页面继承<!-- 引用:子页面继承母模板 -->{% extends "base.html" %}<!-- 定义标题 -->{% block title %} 用户权限管理系统 {% endblock %}<!-- 块级:面包屑导航部分 -->{% block breadcrunb %} <h3>用户展示</h3><!-- 块级结束标志 -->{% endblock %}{% block content %} <table class="table table-striped table-hover table-bordered"> <thead> <tr> <th>序号</th> <th>用户名</th> <th>姓名</th> <th>年龄</th> </tr> </thead> <tbody><!--循环获取 views.py 返回的{'users':users}数据--> {% for user in users %} <tr> <td>{{ forloop.counter }}</td> <td>{{ user.username }}</td> <td>{{ user.name_cn }}</td> <td>{{ user.age }}</td> </tr> {% endfor %} </tbody> </table>{% endblock %}
效果图
$ cat users/models.py from django.db import modelsfrom django.contrib.auth.models import AbstractUser#UserProfile会被初始化为数据库表名(users_userprofile)class UserProfile(AbstractUser): name_cn = models.CharField('中文名', max_length=30) phone = models.CharField('手机', max_length=11, null=True, blank=True) class Meta: verbose_name = '用户信息' verbose_name_plural = verbose_name # 让后台显示为'用户信息' def __str__(self): return self.username
settings.py注册
$ cat settings.pyROOT_URLCONF = 'devops.urls'AUTH_USER_MODEL = 'users.UserProfile'
同步入库
python manage.py makemigrationspython manage.py migrate
数据库手动填充数据
打通MTV
定义url—— http://ip/user/userlist$ cat devops/urls.pyfrom django.contrib import adminfrom django.urls import path,includeurlpatterns = [ path('admin/', admin.site.urls), path('users/', include('users.urls')),]
$ cat users/urls.pyfrom django.urls import path, re_pathfrom . import viewsapp_name = 'users'urlpatterns = [ path('userlist/', views.userlist, name = 'userlist'),]
定义view.py(通过查询数据库的方式拿到数据)
$ cat users/views.pyfrom django.shortcuts import renderfrom users.models import UserProfiledef userlist(request,*args,**kwargs): #从.models 中获取表中所有数据 users = UserProfile.objects.all() print(users,type(users)) # <QuerySet [<UserProfile: admin>, <UserProfile: qsh2>, <UserProfile: qsh3>, <UserProfile: qsh4>, <UserProfile: qsh5>]> <class 'django.db.models.query.QuerySet'> return render(request,'list1.html',{'users':users})
通过引入模板美化
$ cat settings.pyTEMPLATES = [ { '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', ], }, },]STATIC_URL = '/static/'#添加以下几行STATICFILES_DIRS = ( os.path.join(BASE_DIR, "static"),)
$ cat list1.html{% extends 'base.html' %}{% block title %} 用户展示{% endblock %}{% block breadcrunb %} <h3>用户展示</h3>{% endblock %}{% block content %} <table class="table table-striped table-hover table-bordered"> <thead> <tr> <th>序号</th> <th>用户名</th> <th>姓名</th> <th>手机号</th> </tr> </thead> <tbody> {% for user in users %} <tr> <td>{{ forloop.counter }}</td> <td>{{ user.username }}</td> <td>{{ user.name_cn }}</td> <td>{{ user.phone }}</td> </tr> {% endfor %} </tbody> </table>{% endblock %}
效果图
FBV to CBV 花式实现各种用户登录FBV vs CBVlogin VS session传统提交 VS ajaxform认证让系统更健壮认证系统 && 权限系统
用户登录第一版——FBV+数据库
url: http://ip:8000/login$ cat devops/urls.pyurlpatterns = [ #访问根路径走 users.urls 路由规则 path('', include('users.urls')), ]
$ cat users/urls.pyfrom django.urls import path,re_pathfrom . import viewsapp_name = 'users'urlpatterns = [ path("login/", views.login, name='login'),]
view:
$ cat users/views.pyfrom django.http import HttpResponse, QueryDict, HttpResponseRedirectfrom django.shortcuts import renderfrom .models import UserProfile# 引入密码加密模块,Django框架自带的一套加密方法from django.contrib.auth.hashers import make_passworddef login(request, **kwargs): data = "" if request.method == "POST": username = request.POST.get('username','qsh') passwd = request.POST.get('password','123456') #user = UserProfile.objects # users.UserProfile.objects user = models.UserProfile.objects.filter(username=username).first() print('user:', user,user.password) # user: qsh2 pbkdf2_sha256$150000$44dU9PmGegDb$Yv95GU+eFy9Yw/DwinEaOP6fH8nCkQ0ElAUxMfDoR8c= print('make_password',make_password(passwd)) # 给输入的密码加密后字符 if user: # 如果数据库查询出来的密码(密文)和输入密码匹配(make_password模块加密) if user.password == make_password(passwd): return HttpResponseRedirect("/userlist/") else: data = "your passwd is wrong" else: data = "user is not exist" return render(request, 'login.html', {'data':data}) if request.method == "GET": return render(request, 'login.html', {'data':data})
template:
$ cat templates/login.html<form action="{% url 'users:login' %}" method="post"> <!--用户名--> <div class="form-group has-feedback"> <input name="username" type="text" class="form-control" placeholder="用户名"> {% if forms.username.errors %} <span >{{ forms.username.errors }}</span> {% endif %} </div> <!--密码--> <div class="form-group has-feedback"> <input name="password" type="password" class="form-control" placeholder="密码"> {% if forms.password.errors %} <span >{{ forms.password.errors }} </div></span> {% endif %} <!--错误信息及登陆--> <div class="row"> <div class="col-xs-8"> <span id="errors" >{% if data %} {{ data }} {% else %} {% endif %}</span> </div> <div class="col-xs-4"> <button type="submit" class="btn btn-primary btn-block btn-flat">登录</button> </div> </div> </form>
第二个版本 引入CBV view (与历史无半点关系,从头来过)
url:$ cat devops/urls.pyfrom django.contrib import adminfrom django.urls import path, re_path, includeurlpatterns = [ path('admin/', admin.site.urls), path("", include('users.urls1')),]
$ cat users/urls1.pyfrom django.urls import path, re_pathfrom users import views1app_name = 'users'urlpatterns = [ # http://ip:8000/ path("", views1.IndexView.as_view(), name='index'), # http://ip:8000/login/ path("login/", views1.LoginView.as_view(), name='login'), # http://ip:8000/logout/ path("logout/", views1.LogoutView.as_view(), name='logout'), path("userlist/",views.userlist, name='userlist'),]
view :
$ cat users/views1.pyfrom django.views.generic import Viewfrom django.shortcuts import renderfrom django.http import HttpResponseRedirectfrom django.contrib.auth import authenticate, login, logoutfrom django.urls import reverseclass IndexView(View): """ 首页 """ def get(self, request): return render(request, 'list1.html')class LoginView(View): """ 登录模块 """ def get(self, request): return render(request, "login.html") def post(self, request): username = request.POST.get("username", None) password = request.POST.get("password", None) print(username) user = authenticate(username=username, password=password) print(user) if user: if user.is_active: # 默认为当前登录用户创建session login(request, user) # 登录成功则跳到首页 # return HttpResponseRedirect('/') # 命名空间的写法 return HttpResponseRedirect(reverse("users:userlist")) else: return render(request, "login.html", {"msg": "用户未激活!"}) else: return render(request, "login.html", {"msg": "用户名或密码错误!"}) class LogoutView(View): """ 登出功能 """ def get(self, request): logout(request) return HttpResponseRedirect(reverse("users:login"))
实现效果
直接访问http://127.0.0.1:8000/,右上角显示游客访问http://127.0.0.1:8000/login/ 登录后,右上角退出后返回登录页用户认证版本迭代
不需要任何验证class IndexView(View): """ 首页 """ def get(self, request): return render(request, 'list1.html')
class IndexView(View): """ 首页 """ def get(self, request): if not request.user.is_authenticated: return HttpResponseRedirect(reverse("users:login")) return render(request, 'list1.html')
没登录不会进入用户列表页,而是跳转到登录页
# CBV应用装饰器, django的bug,不能直接对类进行装饰,必须使用 method_decorator,把装饰器当作参数传进去。from django.utils.decorators import method_decoratorfrom django.contrib.auth import authenticate, login, logout,decoratorsclass IndexView(View): """ 首页 """ # login_url 用户没有通过测试时跳转的地址,默认是 settings.LOGIN_URL @method_decorator(decorators.login_required(login_url='/login/')) def get(self, request): return render(request, 'list1.html')
from django.contrib.auth.mixins import LoginRequiredMixin# LoginRequiredMixin验证用户class IndexView(LoginRequiredMixin, View): """ 首页 """ # 用户没有通过或者权限不够时跳转的地址,默认是 settings.LOGIN_URL. login_url = '/login/' # 把没通过检查的用户重定向到没有 "next page" 的非登录页面时,把它设置为 None ,这样它会在 URL 中移除。 redirect_field_name = 'redirect_to' # http://127.0.0.1:8000/login/?redirect_to=/ def get(self, request): return render(request, 'list1.html')
声明:本站所有文章资源内容,如无特殊说明或标注,均为采集网络资源。如若本站内容侵犯了原著者的合法权益,可联系本站删除。