做者: 何全,github地址: https://github.com/hequan2017 QQ交流羣: 620176501html
經過此教程完成從零入門,可以獨立編寫一個簡單的CMDB系統。git
目前主流的方法開發方式,分爲2種:mvc 和 mvvc方式。本教程爲 mvc 方式,即 django負責渲染html。後面會推出 mvvc(先後端分離)的入門教程。github
教程項目地址: https://github.com/hequan2017/husky/數據庫
教程文檔地址: https://github.com/hequan2017/husky/tree/master/doc
django首頁
pycharm : 菜單欄 tools --> 選擇 run manage.py taskbootstrap
manage.py@husky > startapp system # 建立一個APP ,用來管理系統後端
具體內容請看實際頁面,下面只是把重點代碼 進行展現。瀏覽器
from django.contrib import admin from django.urls import path from system.views import index from django.conf.urls import include urlpatterns = [ path('admin/', admin.site.urls), path('', index), path('index', index, name="index"), path('system/', include('system.urls', namespace='system')), ## 引入 system 的urls 文件 ]
system/__init.py 新建空白文件session
@login_required(login_url="/system/login") def index(request): """ 首頁 :param request: :return: """ return render(request, 'system/index.html',{}) #render 結合一個給定的模板和一個給定的上下文字典,並返回一個渲染後的 HttpResponse 對象。
繼承user表結構,重建user表mvc
⽤用⼀一個 Python 類來描述數據表, 咱們 稱之爲 模型(model) 。 運⽤用這個類,你能夠經過簡單的
Python 的代碼來建立、檢索、更更新、刪除 數據庫中的記錄⽽而⽆無需寫⼀一條⼜又⼀一條的SQL語句句,這
就是傳說中的ORM(Object Relation Mapping)
from django.db import models from django.contrib.auth.models import AbstractUser class Users(AbstractUser): # AbstractUser 重寫 user 須要集成表 """ 基於django表 添加字段 , 若有須要調用user的狀況,請使用此表 """ position = models.CharField(max_length=64, verbose_name='職位信息', blank=True, null=True) avatar = models.CharField(max_length=256, verbose_name='頭像', blank=True, null=True) mobile = models.CharField(max_length=11, verbose_name='手機', blank=True, null=True) class Meta: db_table = 'users' verbose_name = '用戶信息' verbose_name_plural = verbose_name def __str__(self): return self.username
由於更改了默認的user表,須要先把庫刪了。再進行重建。
drop database husky; create database husky;
pycharm : 菜單欄 tools --> 選擇 run manage.py task
makemigrations 生成數據文件
migrate 根據文件,執行生成表結構
createsuperuser
import sys INSTALLED_APPS = [ # 這裏填寫 建立的app ,結構爲, 一個項目 能夠有多個APP "system", 'bootstrap3' ] AUTH_USER_MODEL = 'system.users' AUTHENTICATION_BACKENDS = ('system.views.CustomBackend',) ## 從新登陸驗證,增長郵箱名字也能夠用做登陸 SESSION_ENGINE = 'django.contrib.sessions.backends.db' SESSION_COOKIE_SAMESITE = 'Lax' CSRF_COOKIE_SAMESITE = 'Lax' SESSION_COOKIE_AGE = 432000 LOGIN_URL = '/auth/login' LANGUAGE_CODE = 'zh-Hans' TIME_ZONE = 'Asia/Shanghai' USE_I18N = True USE_L10N = False USE_TZ = True DATETIME_FORMAT = 'Y-m-d H:i:s' DATE_FORMAT = 'Y-m-d' # logging LOGGING = { 'version': 1, 'disable_existing_loggers': False, 'formatters': { 'verbose': { 'format': '[argus] %(levelname)s %(asctime)s %(module)s %(message)s' } }, 'handlers': { 'console': { 'level': 'DEBUG', 'class': 'logging.StreamHandler', 'stream': sys.stdout, 'formatter': 'verbose' }, }, 'loggers': { 'tasks': { 'handlers': ['console'], 'level': 'DEBUG', 'propagate': True, }, 'asset': { 'handlers': ['console'], 'level': 'DEBUG', 'propagate': True, }, }, } # 表格table PAGINATION_SETTINGS = { 'PAGE_RANGE_DISPLAYED': 3, 'MARGIN_PAGES_DISPLAYED': 2, 'SHOW_FIRST_PAGE_WHEN_INVALID': True, } # 表格table 一頁 展現數據 DISPLAY_PER_PAGE = 15
View 包含了了項⽬目的業務邏輯,咱們稱之爲視圖,也是咱們開發過程當中主要編寫的內容
def login_view(request): """ 登陸 :param request: username,password :return: """ error_msg = "用戶名或密碼錯誤,或者被禁用,請重試" if request.method == "GET": return render(request, 'system/login.html', {'error_msg': error_msg, }) if request.method == "POST": u = request.POST.get("username") p = request.POST.get("password") user = authenticate(request, username=u, password=p) if user is not None: if user.is_active: login(request, user) request.session['is_login'] = True login_ip = request.META['REMOTE_ADDR'] return redirect('/index') ## 重定向到的一個具體的網址 else: return render(request, 'system/login.html', {'error_msg': error_msg, }) else: return render(request, 'system/login.html', {'error_msg': error_msg, }) class CustomBackend(ModelBackend): """ 用戶名字/郵箱名字 登陸 :param request: :return: """ def authenticate(self, request, username=None, password=None, **kwargs): try: user = Users.objects.get(Q(username=username) | Q(email=username)) if user.check_password(password): return user except Exception as e: logger.error(e) return None
指出了了什什麼樣的 URL 調⽤用什什麼的視圖。 在這個例例⼦子中 /latest/ URL 將會調⽤用 latest_books() 這
個函數。 換句句話說,若是你的域名是example.com,任何⼈人瀏覽⽹網址 http://example.com/latest/ 將
會調⽤用 latest_books()這個函數返回結果給⽤用戶
from django.urls import path from system.views import login_view app_name = "system" urlpatterns = [ path('login', login_view, name="login") ]
簡單來講就是html 模板,它描述了了項⽬目的界⾯面結構。 模板引擎也內置了了⼀一些tag 。
登陸不繼承 base.html ,爲一個單獨頁面
<h3>歡迎登陸 系統</h3> <form class="m-t" role="form" action="{% url "system:login" %}" method="POST"> {% csrf_token %} <div class="form-group"> <input type="text" name="username" class="form-control" placeholder="用戶名" required=""> </div> <div class="form-group"> <input type="password" name="password" class="form-control" placeholder="密碼" required=""> </div> <button type="submit" class="btn btn-primary block full-width m-b">登陸</button> <a href="#"> <span style="color: red;"> {{ error_msg }}</span><br> 不推薦使用IE/360瀏覽器(兼容模式)瀏覽!<br /> </a> <div id="login_container"></div> </form>
def logout_view(request): """ 註銷 :param request: :return: """ logout(request) return redirect('system:login')
path('logout', logout_view, name="logout"),
<li> <a href="{% url "system:logout" %}"> <i class="fa fa-sign-out"></i> 註銷 </a> </li>
用戶表單是Web端的一項基本功能,大而全的Django框架中天然帶有現成的基礎form對象,本文就Python的Django框架中forms表單類的使用方法詳解。
from django import forms class UserPasswordForm(forms.Form): old_password = forms.CharField(max_length=128, widget=forms.PasswordInput, label='舊密碼') new_password = forms.CharField(min_length=8, max_length=128, widget=forms.PasswordInput, label='新密碼', help_text="* 你的密碼必須包含至少 8 個字符,不能是你們都愛用的常見密碼,不能所有爲數字") confirm_password = forms.CharField(min_length=8, max_length=128, widget=forms.PasswordInput, label='確認密碼', help_text="* 和上面密碼一致") def __init__(self, *args, **kwargs): self.instance = kwargs.pop('instance') super().__init__(*args, **kwargs) def clean_old_password(self): old_password = self.cleaned_data['old_password'] if not self.instance.check_password(old_password): raise forms.ValidationError('舊密碼錯誤') return old_password def clean_confirm_password(self): new_password = self.cleaned_data['new_password'] confirm_password = self.cleaned_data['confirm_password'] if new_password != confirm_password: raise forms.ValidationError('新密碼與確認密碼不一致') return confirm_password def save(self): password = self.cleaned_data['new_password'] self.instance.set_password(password) self.instance.save() return self.instance
system/views.py
class UserPasswordUpdateView(LoginRequiredMixin, UpdateView): """ 修改密碼 :param request: :return: """ template_name = 'system/password.html' model = Users form_class = UserPasswordForm success_url = reverse_lazy('system:logout') def get_object(self, queryset=None): return self.request.user def get_context_data(self, **kwargs): return super().get_context_data(**kwargs) def get_success_url(self): return super().get_success_url()
path('password_update', UserPasswordUpdateView.as_view(), name="password_update"),
templates/system/password.html
<div class="wrapper wrapper-content animated fadeInRight"> <form method="post" class="form-horizontal" action="" enctype="multipart/form-data"> {% csrf_token %} {% if form.non_field_errors %} <div class="alert alert-danger" style="margin: 20px auto 0px"> {{ form.non_field_errors }} </div> {% endif %} <div class="form-group"> <div class="col-sm-10 col-sm-offset-0"> {{ msg }} {% bootstrap_field form.old_password layout="horizontal" %} {% bootstrap_field form.new_password layout="horizontal" %} {% bootstrap_field form.confirm_password layout="horizontal" %}</div> </div> <div class="hr-line-dashed"></div> <div class="form-group"> <div class="col-sm-4 col-sm-offset-3"> <button id="submit_button" class="btn btn-primary" type="submit">提交</button> <button class="btn btn-white" type="reset">重置</button> </div> </div> </form> </div>
後臺界面配置文件,每一個APP 能夠建立一個
from django.contrib import admin from system.models import Users from django.contrib.auth.admin import UserAdmin class UsersAdmin(UserAdmin): fieldsets = ( (None, {'fields': ('username', 'password')}), ('基本信息', {'fields': ('first_name', 'last_name', 'email')}), ('權限', {'fields': ('is_active', 'is_staff', 'is_superuser', 'groups', 'user_permissions')}), ('登陸時間', {'fields': ('last_login', 'date_joined')}), ('其餘信息', {'fields': ( 'position', 'avatar', 'mobile',)}), ) @classmethod def show_group(self, obj): return [i.name for i in obj.groups.all()] @classmethod def show_user_permissions(self, obj): return [i.name for i in obj.user_permissions.all()] list_display = ('username', 'show_group', 'show_user_permissions') list_display_links = ('username',) search_fields = ('username',) filter_horizontal = ('groups', 'user_permissions') admin.site.register(Users, UsersAdmin) admin.site.site_header = '管理後臺' admin.site.site_title = admin.site.site_header