1:web網站的設計哲學(MVC/MTV的設計哲學)html
2:Request && responsepython
1: Request——用戶有5種方式對服務器發起請求mysql
POST請求(正常狀況下都會帶參數) 經常使用語表單場景web
#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小類獲取到數據ajax
request.method —— 判斷請求的方式sql
request.body —— 第一種獲取數據數據的方式數據庫
print(type(request.body)) # byte print(QueryDict(request.body)) # QueryDict print(QueryDict(request.body).dict) # dict
request.GET # 第二種方式獲取GET QueryDictrequest.GET.get('name','devops')
django
request.POST # 第二種獲取post數據方式 <QueryDict: {'year': ['2019']request.POST.getlist('id')
bootstrap
1. 安裝mysql驅動
pip3 install mysqlclient
若是報錯,請參考:http://www.javashuo.com/article/p-nhvdbece-gv.html服務器
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數據庫替換掉上面sqlite3 DATABASES = { '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
1: HTML、CSS
$ view.py return 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>
$ 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,模板繼承,渲染一個表格數據
$ cat hello/urls.py app_name = 'hello' urlpatterns = [ path('list/', views.list, name = 'list'), ]
第二步:編寫對於url的view,提供僞數據來處理用戶請求
$ cat hello/views.py def list(request,*args,**kwargs): users = [ {'username': 'qsh1', 'name_cn': 'qsh1', 'age': 18}, {'username': 'qsh2', 'name_cn': 'qsh2', 'age': 19}, {'username': 'qsh3', 'name_cn': 'qsh3', '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 %} <h2>用戶展現</h2> <!-- 塊級結束標誌 --> {% 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 models from 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
$ cat settings.py ROOT_URLCONF = 'devops.urls' AUTH_USER_MODEL = 'users.UserProfile'
python manage.py makemigrations python manage.py migrate
打通MTV
$ cat devops/urls.py from django.contrib import admin from django.urls import path,include urlpatterns = [ path('admin/', admin.site.urls), path('users/', include('users.urls')), ]
$ cat users/urls.py from django.urls import path, re_path from . import views app_name = 'users' urlpatterns = [ path('userlist/', views.userlist, name = 'userlist'), ]
$ cat users/views.py from django.shortcuts import render from users.models import UserProfile def userlist(request,*args,**kwargs): #從.models 中獲取表中全部數據 users = UserProfile.objects.all() print(users,type(users)) # <QuerySet [<UserProfile: admin>, <UserProfile: qsh1>, <UserProfile: qsh2>, <UserProfile: qsh3>, <UserProfile: qsh4>]> <class 'django.db.models.query.QuerySet'> return render(request,'list1.html',{'users':users})
$ cat settings.py 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', ], }, }, ] STATIC_URL = '/static/' #添加如下幾行 STATICFILES_DIRS = ( os.path.join(BASE_DIR, "static"), )
$ cat list1.html {% extends 'base.html' %} {% block title %} 用戶展現 {% endblock %} {% block breadcrunb %} <h2>用戶展現</h2> {% 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+數據庫
$ cat devops/urls.py urlpatterns = [ #訪問根路徑走 users.urls 路由規則 path('', include('users.urls')), ]
$ cat users/urls.py from django.urls import path,re_path from . import views app_name = 'users' urlpatterns = [ path("login/", views.login, name='login'), ]
$ cat users/views.py from django.http import HttpResponse, QueryDict, HttpResponseRedirect from django.shortcuts import render from .models import UserProfile # 引入密碼加密模塊,Django框架自帶的一套加密方法 from django.contrib.auth.hashers import make_password def 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: qsh1 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})
$ 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 style="color:red">{{ 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 style="color:red">{{ forms.password.errors }} </div></span> {% endif %} <!--錯誤信息及登錄--> <div class="row"> <div class="col-xs-8"> <span id="errors" style="color:red">{% 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 (與歷史無半點關係,從頭來過)
$ cat devops/urls.py from django.contrib import admin from django.urls import path, re_path, include urlpatterns = [ path('admin/', admin.site.urls), path("", include('users.urls1')), ]
$ cat users/urls1.py from django.urls import path, re_path from users import views1 app_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'), ]
$ cat users/views1.py from django.views.generic import View from django.shortcuts import render from django.http import HttpResponseRedirect from django.contrib.auth import authenticate, login, logout from django.urls import reverse class 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"))
實現效果
用戶認證版本迭代
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_decorator from django.contrib.auth import authenticate, login, logout,decorators class 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')