Django+xadmin打造在線教育平臺(二)

目錄javascript

在線教育平臺(一)      在線教育平臺(二)css

在線教育平臺(三)      在線教育平臺(四)html

在線教育平臺(五)      在線教育平臺(六)前端

在線教育平臺(七)      在線教育平臺(八)java

在線教育平臺(九)      在線教育平臺(十)python

代碼mysql

github下載jquery

在線演示git

教程github

學習自慕課網-使用python3.x與Django2.0.1開發的在線教育平臺

3、xadmin後臺管理

3.1.xadmin的安裝

django2.0的安裝(源碼安裝方式):

https://github.com/sshwsfc/xadmin/tree/django2

把zip文件放到pip目錄下,運行下面命令安裝:

pip install xadmin-django2
是文件README.rst 出現了 Unicode 解碼錯誤,這個文件是沒有什麼用處的,能夠新建一個同名的空白文件替換掉

 首先下載zip源碼包:github.com/sshwsfc/xadmin

 解壓後,打開README.rst文件,清空裏面的內容,而後保存。

再壓縮成zip,放到pip目錄下:C:\Users\Administrator\AppData\Local\Programs\Python\Python36\Lib\site-packages\pip

此時打開cmd進行安裝:pip install xadmin-master.zip
其它版本

若是上面安裝提示Runtime錯誤:

更換安裝源(使用豆瓣源)

pip install -i https://pypi.douban.com/simple xadmin-django2

安裝成功後,同時也安裝了不少依賴的包。

3.2.xadmin的設置

 (1)新建Python Package "extra_apps",把源碼xadmin文件夾放到extra_apps文件夾下面,此時目錄結構以下:

(2)把extra_apps右鍵mark爲Source Root並在settings中加入

sys.path.insert(0,os.path.join(BASE_DIR, 'extra_apps'))

(3)由於咱們用源碼的xadmin,因此要卸載以前安裝的

pip uninstall xadmin

(4)配置路由

把admin改爲xadmin

# urls.py

from django.urls import path

import xadmin

urlpatterns = [
    path('xadmin/', xadmin.site.urls),
]

(5)註冊app

把下面兩個app註冊到settings.py的INSTALLED_APPS中

'xadmin',
'crispy_forms'

(6)從新生成數據庫

python manage.py makemigrations

python manage.py migrate

(7)設置成中文

LANGUAGE_CODE = 'zh-hans'

TIME_ZONE = 'Asia/Shanghai'

USE_I18N = True

USE_L10N = True

USE_TZ = False

(8)建立一個管理員用戶

python manage.py createsuperuser

如今就能夠運行了 

python manage.py runserver 

訪問後臺:http://127.0.0.1:8000/xadmin

 能夠看到成功進入管理界面

 

datetimefield報錯問題解決:

當咱們點增長用戶信息,會報錯

 

能夠看到報的是xadmin/widgets中第80行

 def render(self, name, value, attrs=None):
        input_html = [ht for ht in super(AdminSplitDateTime, self).render(name, value, attrs).split('\n') if ht != '']
        # return input_html
        return mark_safe('<div class="datetime clearfix"><div class="input-group date bootstrap-datepicker"><span class="input-group-addon"><i class="fa fa-calendar"></i></span>%s'
                         '<span class="input-group-btn"><button class="btn btn-default" type="button">%s</button></span></div>'
                         '<div class="input-group time bootstrap-clockpicker"><span class="input-group-addon"><i class="fa fa-clock-o">'
                         '</i></span>%s<span class="input-group-btn"><button class="btn btn-default" type="button">%s</button></span></div></div>' % (input_html[0], _(u'Today'), input_html[1], _(u'Now')))

上面貼出來的最後一行代碼就是widgets.py的第80行代碼。

能夠看出這句代碼是但願用「\n」把input_html裏的兩個標籤拆開,但兩個標籤之間沒有換行,因此沒能拆分,致使報錯。

input_html[1]就是報錯的代碼,由於input_html裏只有一個元素。

 解決辦法:

既然「\n」不能拆分標籤,那麼就換一種拆分方式,使用「/><」拆分。

原代碼:

input_html = [ht for ht in super(AdminSplitDateTime, self).render(name, value, attrs).split('\n') if ht != '']

修改後代碼:

input_html = [ht for ht in super(AdminSplitDateTime, self).render(name, value, attrs).split('/><') if ht != '']
input_html[0] = input_html[0] + "/>"
input_html[1] = "<" + input_html[1]

再運行就正常了

3.3.users app的models註冊

(1)在users下面建立adminx.py,代碼以下:

# users/adminx.py

import xadmin

from .models import EmailVerifyRecord

#xadmin中這裏是繼承object,再也不是繼承admin
class EmailVerifyRecordAdmin(object):
    pass

xadmin.site.register(EmailVerifyRecord,EmailVerifyRecordAdmin)

(2)完善功能,增長顯示字段,搜索和過濾

修改users/adminx.py,代碼以下:

# users/adminx.py

import xadmin

from .models import EmailVerifyRecord

#xadmin中這裏是繼承object,再也不是繼承admin
class EmailVerifyRecordAdmin(object):
    # 顯示的列
    list_display = ['code', 'email', 'send_type', 'send_time']
    # 搜索的字段,不要添加時間搜索
    search_fields = ['code', 'email', 'send_type']
    # 過濾
    list_filter = ['code', 'email', 'send_type', 'send_time']

xadmin.site.register(EmailVerifyRecord,EmailVerifyRecordAdmin)

刷新後的界面:

users中Banner也註冊進去

class BannerAdmin(object):
    list_display = ['title', 'image', 'url','index', 'add_time']
    search_fields = ['title', 'image', 'url','index']
    list_filter = ['title', 'image', 'url','index', 'add_time']


xadmin.site.register(Banner,BannerAdmin)

3.4.剩餘app model註冊

(1)course

代碼以下: 注意外鍵

# course/adminx.py

import xadmin

from .models import Course, Lesson, Video, CourseResource

class CourseAdmin(object): '''課程''' list_display = [ 'name','desc','detail','degree','learn_times','students'] search_fields = ['name', 'desc', 'detail', 'degree', 'students'] list_filter = [ 'name','desc','detail','degree','learn_times','students'] class LessonAdmin(object): '''章節''' list_display = ['course', 'name', 'add_time'] search_fields = ['course', 'name'] #這裏course__name是根據課程名稱過濾 list_filter = ['course__name', 'name', 'add_time'] class VideoAdmin(object): '''視頻''' list_display = ['lesson', 'name', 'add_time'] search_fields = ['lesson', 'name'] list_filter = ['lesson', 'name', 'add_time'] class CourseResourceAdmin(object): '''課程資源''' list_display = ['course', 'name', 'download', 'add_time'] search_fields = ['course', 'name', 'download'] list_filter = ['course__name', 'name', 'download', 'add_time'] # 將管理器與model進行註冊關聯 xadmin.site.register(Course, CourseAdmin) xadmin.site.register(Lesson, LessonAdmin) xadmin.site.register(Video, VideoAdmin) xadmin.site.register(CourseResource, CourseResourceAdmin)

(2)organizations

 代碼以下:

# organization/adminx.py

import xadmin

from .models import CityDict, CourseOrg, Teacher



class CityDictAdmin(object):
    '''城市'''
    
    list_display = ['name', 'desc', 'add_time']
    search_fields = ['name', 'desc']
    list_filter = ['name', 'desc', 'add_time']


class CourseOrgAdmin(object):
    '''機構'''
    
    list_display = ['name', 'desc', 'click_nums', 'fav_nums','add_time' ]
    search_fields = ['name', 'desc', 'click_nums', 'fav_nums']
    list_filter = ['name', 'desc', 'click_nums', 'fav_nums','city__name','address','add_time']


class TeacherAdmin(object):
    '''老師'''
    
    list_display = [ 'name','org', 'work_years', 'work_company','add_time']
    search_fields = ['org', 'name', 'work_years', 'work_company']
    list_filter = ['org__name', 'name', 'work_years', 'work_company','click_nums', 'fav_nums', 'add_time']


xadmin.site.register(CityDict, CityDictAdmin)
xadmin.site.register(CourseOrg, CourseOrgAdmin)
xadmin.site.register(Teacher, TeacherAdmin)

(3)operation

代碼以下:

# operation/adminx.py

import xadmin

from .models import UserAsk, UserCourse, UserMessage, CourseComments, UserFavorite


class UserAskAdmin(object):
    '''用戶表單我要學習'''

    list_display = ['name', 'mobile', 'course_name', 'add_time']
    search_fields = ['name', 'mobile', 'course_name']
    list_filter = ['name', 'mobile', 'course_name', 'add_time']


#
class UserCourseAdmin(object):
    '''用戶課程學習'''

    list_display = ['user', 'course', 'add_time']
    search_fields = ['user', 'course']
    list_filter = ['user', 'course', 'add_time']



class UserMessageAdmin(object):
    '''用戶消息後臺'''

    list_display = ['user', 'message', 'has_read', 'add_time']
    search_fields = ['user', 'message', 'has_read']
    list_filter = ['user', 'message', 'has_read', 'add_time']



class CourseCommentsAdmin(object):
    '''用戶評論後臺'''

    list_display = ['user', 'course', 'comments', 'add_time']
    search_fields = ['user', 'course', 'comments']
    list_filter = ['user', 'course', 'comments', 'add_time']



class UserFavoriteAdmin(object):
    '''用戶收藏後臺'''

    list_display = ['user', 'fav_id', 'fav_type', 'add_time']
    search_fields = ['user', 'fav_id', 'fav_type']
    list_filter = ['user', 'fav_id', 'fav_type', 'add_time']


# 將後臺管理器與models進行關聯註冊。
xadmin.site.register(UserAsk, UserAskAdmin)
xadmin.site.register(UserCourse, UserCourseAdmin)
xadmin.site.register(UserMessage, UserMessageAdmin)
xadmin.site.register(CourseComments, CourseCommentsAdmin)
xadmin.site.register(UserFavorite, UserFavoriteAdmin)

 所有代碼:

# users/adminx.py

import xadmin

from .models import EmailVerifyRecord,Banner

#xadmin中這裏是繼承object,再也不是繼承admin
class EmailVerifyRecordAdmin(object):
    # 顯示的列
    list_display = ['code', 'email', 'send_type', 'send_time']
    # 搜索的字段
    search_fields = ['code', 'email', 'send_type']
    # 過濾
    list_filter = ['code', 'email', 'send_type', 'send_time']


class BannerAdmin(object):
    list_display = ['title', 'image', 'url','index', 'add_time']
    search_fields = ['title', 'image', 'url','index']
    list_filter = ['title', 'image', 'url','index', 'add_time']


xadmin.site.register(EmailVerifyRecord,EmailVerifyRecordAdmin)
xadmin.site.register(Banner,BannerAdmin)
users/adminx.py
# course/adminx.py

import xadmin

from .models import Course, Lesson, Video, CourseResource


# Course的admin管理器
class CourseAdmin(object):
    '''課程'''

    list_display = [ 'name','desc','detail','degree','learn_times','students']
    search_fields = ['name', 'desc', 'detail', 'degree', 'students']
    list_filter = [ 'name','desc','detail','degree','learn_times','students']


class LessonAdmin(object):
    '''章節'''

    list_display = ['course', 'name', 'add_time']
    search_fields = ['course', 'name']
    #這裏course__name是根據課程名稱過濾
    list_filter = ['course__name', 'name', 'add_time']


class VideoAdmin(object):
    '''視頻'''

    list_display = ['lesson', 'name', 'add_time']
    search_fields = ['lesson', 'name']
    list_filter = ['lesson', 'name', 'add_time']


class CourseResourceAdmin(object):
    '''課程資源'''

    list_display = ['course', 'name', 'download', 'add_time']
    search_fields = ['course', 'name', 'download']
    list_filter = ['course__name', 'name', 'download', 'add_time']


# 將管理器與model進行註冊關聯
xadmin.site.register(Course, CourseAdmin)
xadmin.site.register(Lesson, LessonAdmin)
xadmin.site.register(Video, VideoAdmin)
xadmin.site.register(CourseResource, CourseResourceAdmin)
course/adminx.py
# organization/adminx.py

import xadmin

from .models import CityDict, CourseOrg, Teacher


class CityDictAdmin(object):
    '''城市'''

    list_display = ['name', 'desc', 'add_time']
    search_fields = ['name', 'desc']
    list_filter = ['name', 'desc', 'add_time']


class CourseOrgAdmin(object):
    '''機構'''

    list_display = ['name', 'desc', 'click_nums', 'fav_nums','add_time' ]
    search_fields = ['name', 'desc', 'click_nums', 'fav_nums']
    list_filter = ['name', 'desc', 'click_nums', 'fav_nums','city__name','address','add_time']


class TeacherAdmin(object):
    '''老師'''

    list_display = [ 'name','org', 'work_years', 'work_company','add_time']
    search_fields = ['org', 'name', 'work_years', 'work_company']
    list_filter = ['org__name', 'name', 'work_years', 'work_company','click_nums', 'fav_nums', 'add_time']


xadmin.site.register(CityDict, CityDictAdmin)
xadmin.site.register(CourseOrg, CourseOrgAdmin)
xadmin.site.register(Teacher, TeacherAdmin)
organization/adminx.py
# operation/adminx.py

import xadmin

from .models import UserAsk, UserCourse, UserMessage, CourseComments, UserFavorite


class UserAskAdmin(object):
    '''用戶表單我要學習'''

    list_display = ['name', 'mobile', 'course_name', 'add_time']
    search_fields = ['name', 'mobile', 'course_name']
    list_filter = ['name', 'mobile', 'course_name', 'add_time']


#
class UserCourseAdmin(object):
    '''用戶課程學習'''

    list_display = ['user', 'course', 'add_time']
    search_fields = ['user', 'course']
    list_filter = ['user', 'course', 'add_time']



class UserMessageAdmin(object):
    '''用戶消息後臺'''

    list_display = ['user', 'message', 'has_read', 'add_time']
    search_fields = ['user', 'message', 'has_read']
    list_filter = ['user', 'message', 'has_read', 'add_time']



class CourseCommentsAdmin(object):
    '''用戶評論後臺'''

    list_display = ['user', 'course', 'comments', 'add_time']
    search_fields = ['user', 'course', 'comments']
    list_filter = ['user', 'course', 'comments', 'add_time']



class UserFavoriteAdmin(object):
    '''用戶收藏後臺'''

    list_display = ['user', 'fav_id', 'fav_type', 'add_time']
    search_fields = ['user', 'fav_id', 'fav_type']
    list_filter = ['user', 'fav_id', 'fav_type', 'add_time']


# 將後臺管理器與models進行關聯註冊。
xadmin.site.register(UserAsk, UserAskAdmin)
xadmin.site.register(UserCourse, UserCourseAdmin)
xadmin.site.register(UserMessage, UserMessageAdmin)
xadmin.site.register(CourseComments, CourseCommentsAdmin)
xadmin.site.register(UserFavorite, UserFavoriteAdmin)
operation/adminx.py

此時項目目錄結構:

 

 運行項目,進後臺管理界面以下:

 3.5.xadmin的全局配置

將全局配置修改:

  • 如左上角:django Xadmin。下面的個人公司
  • 主題修改,app名稱漢化,菜單收疊。

 使用Xadmin的主題功能。

把全站的配置放在users\adminx.py中:

 (1)添加主題功能

from xadmin import views

# 建立xadmin的最基本管理器配置,並與view綁定
class BaseSetting(object):
    # 開啓主題功能
    enable_themes = True
    use_bootswatch = True

# 將基本配置管理與view綁定
xadmin.site.register(views.BaseAdminView,BaseSetting)

沒添加主題前,右上角界面

添加主題後,能夠選擇本身喜歡的主題

(2)全局配置

 修改django admin 和下面的個人公司收起菜單

# 全局修改,固定寫法
class GlobalSettings(object):
    # 修改title
    site_title = 'NBA後臺管理界面'
    # 修改footer
    site_footer = '科比的公司'
    # 收起菜單
    menu_style = 'accordion'

# 將title和footer信息進行註冊
xadmin.site.register(views.CommAdminView,GlobalSettings)
# users/adminx.py

import xadmin

from .models import EmailVerifyRecord,Banner

from xadmin import views

# 建立xadmin的最基本管理器配置,並與view綁定
class BaseSetting(object):
    # 開啓主題功能
    enable_themes = True
    use_bootswatch = True

# 全局修改,固定寫法
class GlobalSettings(object):
    # 修改title
    site_title = 'NBA後臺管理界面'
    # 修改footer
    site_footer = '科比的公司'
    # 收起菜單
    menu_style = 'accordion'


#xadmin中這裏是繼承object,再也不是繼承admin
class EmailVerifyRecordAdmin(object):
    # 顯示的列
    list_display = ['code', 'email', 'send_type', 'send_time']
    # 搜索的字段
    search_fields = ['code', 'email', 'send_type']
    # 過濾
    list_filter = ['code', 'email', 'send_type', 'send_time']


class BannerAdmin(object):
    list_display = ['title', 'image', 'url','index', 'add_time']
    search_fields = ['title', 'image', 'url','index']
    list_filter = ['title', 'image', 'url','index', 'add_time']


xadmin.site.register(EmailVerifyRecord,EmailVerifyRecordAdmin)
xadmin.site.register(Banner,BannerAdmin)

# 將基本配置管理與view綁定
xadmin.site.register(views.BaseAdminView,BaseSetting)

# 將title和footer信息進行註冊
xadmin.site.register(views.CommAdminView,GlobalSettings)
users/adminx.py所有代碼

再進後臺的界面,以下:

(3)修改app的名字

 在apps.py裏面配置app的顯示名稱

 以users/apps.py爲例,其它三個一樣操做

默認apps.py裏面的代碼

from django.apps import AppConfig


class UsersConfig(AppConfig):
    name = 'users'

修改後:

from django.apps import AppConfig


class UsersConfig(AppConfig):
    name = 'users'
    verbose_name = '用戶'

還要在users/__init__.py中引用apps.py的配置

添加代碼以下:

# users/__init__.py

default_app_config = 'users.apps.UsersConfig'

其它三個app也一樣方法改爲顯示中文

 大功告成

 

4、完成登陸功能

4.1.首頁和登陸頁面的配置

(1)把html文件中index.html拷貝到templates文件夾內

前端初始文件能夠去我github上面下載:https://github.com/derek-zhang123/MxOnline

(2)新建static目錄用來存放靜態文件

在settings.py中設置路徑

STATICFILES_DIRS = (
    os.path.join(BASE_DIR,'static'),
)

(3)引用靜態文件

 使用ctrl+f查找出全部「../」, 而後ctrl+r 所有替換爲「/static/」

(4)配置靜態文件的url

MxOnline/urls.py中

# MxOnline/urls.py

import xadmin

from django.urls import path

from django.views.generic import TemplateView

urlpatterns = [
    path('xadmin/', xadmin.site.urls),
    path('', TemplateView.as_view(template_name='index.html'),name='index'),
]

(5)登陸頁面

把login.html拷貝到templates文件夾下

使用ctrl+f查找出全部「../」, 而後ctrl+r 所有替換爲「/static/」

 配置login的url

# MxOnline/urls.py

urlpatterns = [
    path('xadmin/', xadmin.site.urls),
    path('', TemplateView.as_view(template_name='index.html'),name='index'),
    path('login/', TemplateView.as_view(template_name='login.html'),name='login'),
]

更改index.html裏面跳轉到登陸界面的url

原始樣子

<!-- <a style="color:white" class="fr registerbtn" href="register.html">註冊</a> -->

<!-- <a style="color:white" class="fr loginbtn" href="login.html">登陸</a> -->

取消註釋,將login.html改成「login/」

<a style="color:white" class="fr registerbtn" href="register.html">註冊</a>
<a style="color:white" class="fr loginbtn" href="/login/">登陸</a>

如今能夠訪問index頁面,而後點‘’登陸」,跳轉到登陸頁面了

4.2.用戶登陸

(1)修改login的路由

from django.views.generic import TemplateView
from users import views


urlpatterns = [
    path('xadmin/', xadmin.site.urls),
    path('', TemplateView.as_view(template_name='index.html'),name='index'),
    path('login/',views.user_login,name = 'login'),     #修改login路由
]

(2)寫login的視圖

from django.shortcuts import render
from django.contrib.auth import authenticate,login

def user_login(request):
    if request.method == 'POST':
        # 獲取用戶提交的用戶名和密碼
        user_name = request.POST.get('username',None)
        pass_word = request.POST.get('password',None)
        # 成功返回user對象,失敗None
        user = authenticate(username=user_name,password=pass_word)
        # 若是不是null說明驗證成功
        if user is not None:
            # 登陸
            login(request,user)
            return render(request,'index.html')
        else:
            return render(request,'login.html',{'msg':'用戶名或密碼錯誤'})
    
    elif request.method == 'GET':
        return render(request,'login.html')

(3)更改login.html

 <form action="/login/" method="post" autocomplete="off">
                    <input type='hidden' name='csrfmiddlewaretoken' value='mymQDzHWl2REXIfPMg2mJaLqDfaS1sD5' />
                    <div class="form-group marb20 ">
                        <label>&nbsp;&nbsp;</label>
                        <input name="username" id="account_l" type="text" placeholder="手機號/郵箱" />
                    </div>
                    <div class="form-group marb8 ">
                        <label>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</label>
                        <input name="password" id="password_l" type="password" placeholder="請輸入您的密碼" />
                    </div>
                    <div class="error btns login-form-tips" id="jsLoginTips">{{ msg }}</div>
                     <div class="auto-box marb38">

                        <a class="fr" href="forgetpwd.html">忘記密碼?</a>
                     </div>
                     <input class="btn btn-green" id="jsLoginBtn" type="submit" value="當即登陸 > " />
                <input type='hidden' name='csrfmiddlewaretoken' value='5I2SlleZJOMUX9QbwYLUIAOshdrdpRcy' />
                    {% csrf_token %}
                </form>
login.html

若是用戶登陸錯誤,應該有提示錯誤信息,下面代碼:

<div class="error btns login-form-tips" id="jsLoginTips">{{ msg }}</div>

 

 

(4)修改index.html

原始index.html的代碼

<div  class=" header">
             <div class="top">
                <div class="wp">
                    <div class="fl"><p>服務電話:<b>33333333</b></p></div>
                    <!--登陸後跳轉-->

                        
                         <a style="color:white" class="fr registerbtn" href="register.html">註冊</a>
                         <a style="color:white" class="fr loginbtn" href="/login/">登陸</a>
                        
                        <div class="personal">
                            <dl class="user fr">
                                <dd>bobby<img class="down fr" src="/static/images/top_down.png"/></dd>
                                <dt><img width="20" height="20" src="/static/media/image/2016/12/default_big_14.png"/></dt>
                            </dl>
                            <div class="userdetail">
                                <dl>
                                    <dt><img width="80" height="80" src="/static/media/image/2016/12/default_big_14.png"/></dt>
                                    <dd>
                                        <h2>django</h2>
                                        <p>bobby</p>
                                    </dd>
                                </dl>
                                <div class="btn">
                                    <a class="personcenter fl" href="usercenter-info.html">進入我的中心</a>
                                    <a class="fr" href="/logout/">退出</a>
                                </div>
                            </div>
                        </div>


                </div>
            </div>

 咱們應該作個驗證,當用戶已登陸狀態的時候,顯示用戶姓名和圖像及其我的中心信息

 若是沒有登陸,則顯示登陸和註冊

更改代碼以下:

<div  class=" header">
             <div class="top">
                {% if request.user.is_authenticated %}
                <div class="personal">
                            <dl class="user fr">
                                <dd>bobby<img class="down fr" src="/static/images/top_down.png"/></dd>
                                <dt><img width="20" height="20" src="/static/media/image/2016/12/default_big_14.png"/></dt>
                            </dl>
                            <div class="userdetail">
                                <dl>
                                    <dt><img width="80" height="80" src="/static/media/image/2016/12/default_big_14.png"/></dt>
                                    <dd>
                                        <h2>django</h2>
                                        <p>bobby</p>
                                    </dd>
                                </dl>
                                <div class="btn">
                                    <a class="personcenter fl" href="usercenter-info.html">進入我的中心</a>
                                    <a class="fr" href="/logout/">退出</a>
                                </div>
                            </div>
                        </div>
                {% else %}
                <div class="wp">
                    <div class="fl"><p>服務電話:<b>33333333</b></p></div>
                    <!--登陸後跳轉-->

                        
                         <a style="color:white" class="fr registerbtn" href="register.html">註冊</a>
                         <a style="color:white" class="fr loginbtn" href="/login/">登陸</a>
                        



                </div>
                {% endif %}
            </div>
index.html

 (5)增長郵箱登陸

 讓用戶能夠經過郵箱或者用戶名均可以登陸,用自定義authenticate方法

這裏是繼承ModelBackend類來作的驗證

class ModelBackend:
    """
    Authenticates against settings.AUTH_USER_MODEL.
    """

    def authenticate(self, request, username=None, password=None, **kwargs):
        if username is None:
            username = kwargs.get(UserModel.USERNAME_FIELD)
        try:
            user = UserModel._default_manager.get_by_natural_key(username)
        except UserModel.DoesNotExist:
            # Run the default password hasher once to reduce the timing
            # difference between an existing and a nonexistent user (#20760).
            UserModel().set_password(password)
        else:
            if user.check_password(password) and self.user_can_authenticate(user):
                return user

    def user_can_authenticate(self, user):
        """
        Reject users with is_active=False. Custom user models that don't have
        that attribute are allowed.
        """
        is_active = getattr(user, 'is_active', None)
        return is_active or is_active is None

    def _get_user_permissions(self, user_obj):
        return user_obj.user_permissions.all()

    def _get_group_permissions(self, user_obj):
        user_groups_field = get_user_model()._meta.get_field('groups')
        user_groups_query = 'group__%s' % user_groups_field.related_query_name()
        return Permission.objects.filter(**{user_groups_query: user_obj})

    def _get_permissions(self, user_obj, obj, from_name):
        """
        Return the permissions of `user_obj` from `from_name`. `from_name` can
        be either "group" or "user" to return permissions from
        `_get_group_permissions` or `_get_user_permissions` respectively.
        """
        if not user_obj.is_active or user_obj.is_anonymous or obj is not None:
            return set()

        perm_cache_name = '_%s_perm_cache' % from_name
        if not hasattr(user_obj, perm_cache_name):
            if user_obj.is_superuser:
                perms = Permission.objects.all()
            else:
                perms = getattr(self, '_get_%s_permissions' % from_name)(user_obj)
            perms = perms.values_list('content_type__app_label', 'codename').order_by()
            setattr(user_obj, perm_cache_name, {"%s.%s" % (ct, name) for ct, name in perms})
        return getattr(user_obj, perm_cache_name)

    def get_user_permissions(self, user_obj, obj=None):
        """
        Return a set of permission strings the user `user_obj` has from their
        `user_permissions`.
        """
        return self._get_permissions(user_obj, obj, 'user')

    def get_group_permissions(self, user_obj, obj=None):
        """
        Return a set of permission strings the user `user_obj` has from the
        groups they belong.
        """
        return self._get_permissions(user_obj, obj, 'group')

    def get_all_permissions(self, user_obj, obj=None):
        if not user_obj.is_active or user_obj.is_anonymous or obj is not None:
            return set()
        if not hasattr(user_obj, '_perm_cache'):
            user_obj._perm_cache = set()
            user_obj._perm_cache.update(self.get_user_permissions(user_obj))
            user_obj._perm_cache.update(self.get_group_permissions(user_obj))
        return user_obj._perm_cache

    def has_perm(self, user_obj, perm, obj=None):
        if not user_obj.is_active:
            return False
        return perm in self.get_all_permissions(user_obj, obj)

    def has_module_perms(self, user_obj, app_label):
        """
        Return True if user_obj has any permissions in the given app_label.
        """
        if not user_obj.is_active:
            return False
        for perm in self.get_all_permissions(user_obj):
            if perm[:perm.index('.')] == app_label:
                return True
        return False

    def get_user(self, user_id):
        try:
            user = UserModel._default_manager.get(pk=user_id)
        except UserModel.DoesNotExist:
            return None
        return user if self.user_can_authenticate(user) else None
ModelBackend源碼
from django.contrib.auth.backends import ModelBackend
from .models import UserProfile
from django.db.models import Q

#郵箱和用戶名均可以登陸
# 基礎ModelBackend類,由於它有authenticate方法
class CustomBackend(ModelBackend):
    def authenticate(self, request, username=None, password=None, **kwargs):
        try:
            # 不但願用戶存在兩個,get只能有一個。兩個是get失敗的一種緣由 Q爲使用並集查詢
            user = UserProfile.objects.get(Q(username=username)|Q(email=username))

            # django的後臺中密碼加密:因此不能password==password
            # UserProfile繼承的AbstractUser中有def check_password(self, raw_password):
            if user.check_password(password):
                return user
        except Exception as e:
            return None
# users/views.py

from django.shortcuts import render
from django.contrib.auth import authenticate,login

from django.contrib.auth.backends import ModelBackend
from .models import UserProfile
from django.db.models import Q

#郵箱和用戶名均可以登陸
# 基礎ModelBackend類,由於它有authenticate方法
class CustomBackend(ModelBackend):
    def authenticate(self, request, username=None, password=None, **kwargs):
        try:
            # 不但願用戶存在兩個,get只能有一個。兩個是get失敗的一種緣由 Q爲使用並集查詢
            user = UserProfile.objects.get(Q(username=username)|Q(email=username))

            # django的後臺中密碼加密:因此不能password==password
            # UserProfile繼承的AbstractUser中有def check_password(self, raw_password):
            if user.check_password(password):
                return user
        except Exception as e:
            return None

def user_login(request):
    if request.method == 'POST':
        # 獲取用戶提交的用戶名和密碼
        user_name = request.POST.get('username',None)
        pass_word = request.POST.get('password',None)
        # 成功返回user對象,失敗None
        user = authenticate(username=user_name,password=pass_word)
        # 若是不是null說明驗證成功
        if user is not None:
            # 登陸
            login(request,user)
            return render(request,'index.html')
        else:
            return render(request,'login.html',{'msg':'用戶名或密碼錯誤'})

    elif request.method == 'GET':
        return render(request,'login.html')
users/views.py

MxOnline/settings.py添加以下代碼:

AUTHENTICATION_BACKENDS = (
    'users.views.CustomBackend',
)

而後經過郵箱也能夠實現登陸了

4.3.用form實現登陸

(1)把前面views中的user_login()函數改爲基於類的形式

from django.views.generic.base import View

class LoginView(View):
    def get(self,request):
        return render(request, 'login.html')

    def post(self,request):
        # 獲取用戶提交的用戶名和密碼
        user_name = request.POST.get('username', None)
        pass_word = request.POST.get('password', None)
        # 成功返回user對象,失敗None
        user = authenticate(username=user_name, password=pass_word)
        # 若是不是null說明驗證成功
        if user is not None:
            # 登陸
            login(request, user)
            return render(request, 'index.html')
        else:
            return render(request, 'login.html', {'msg': '用戶名或密碼錯誤'})

繼承的View類

class View:
    """
    Intentionally simple parent class for all views. Only implements
    dispatch-by-method and simple sanity checking.
    """

    http_method_names = ['get', 'post', 'put', 'patch', 'delete', 'head', 'options', 'trace']

    def __init__(self, **kwargs):
        """
        Constructor. Called in the URLconf; can contain helpful extra
        keyword arguments, and other things.
        """
        # Go through keyword arguments, and either save their values to our
        # instance, or raise an error.
        for key, value in kwargs.items():
            setattr(self, key, value)

    @classonlymethod
    def as_view(cls, **initkwargs):
        """Main entry point for a request-response process."""
        for key in initkwargs:
            if key in cls.http_method_names:
                raise TypeError("You tried to pass in the %s method name as a "
                                "keyword argument to %s(). Don't do that."
                                % (key, cls.__name__))
            if not hasattr(cls, key):
                raise TypeError("%s() received an invalid keyword %r. as_view "
                                "only accepts arguments that are already "
                                "attributes of the class." % (cls.__name__, key))

        def view(request, *args, **kwargs):
            self = cls(**initkwargs)
            if hasattr(self, 'get') and not hasattr(self, 'head'):
                self.head = self.get
            self.request = request
            self.args = args
            self.kwargs = kwargs
            return self.dispatch(request, *args, **kwargs)
        view.view_class = cls
        view.view_initkwargs = initkwargs

        # take name and docstring from class
        update_wrapper(view, cls, updated=())

        # and possible attributes set by decorators
        # like csrf_exempt from dispatch
        update_wrapper(view, cls.dispatch, assigned=())
        return view

    def dispatch(self, request, *args, **kwargs):
        # Try to dispatch to the right method; if a method doesn't exist,
        # defer to the error handler. Also defer to the error handler if the
        # request method isn't on the approved list.
        if request.method.lower() in self.http_method_names:
            handler = getattr(self, request.method.lower(), self.http_method_not_allowed)
        else:
            handler = self.http_method_not_allowed
        return handler(request, *args, **kwargs)

    def http_method_not_allowed(self, request, *args, **kwargs):
        logger.warning(
            'Method Not Allowed (%s): %s', request.method, request.path,
            extra={'status_code': 405, 'request': request}
        )
        return HttpResponseNotAllowed(self._allowed_methods())

    def options(self, request, *args, **kwargs):
        """Handle responding to requests for the OPTIONS HTTP verb."""
        response = HttpResponse()
        response['Allow'] = ', '.join(self._allowed_methods())
        response['Content-Length'] = '0'
        return response

    def _allowed_methods(self):
        return [m.upper() for m in self.http_method_names if hasattr(self, m)]
View類源碼參考

基於類的urls配置

from users.views import LoginView

  path('login/',LoginView.as_view(),name = 'login'),

(2)users下新建form.py文件

 代碼以下:

# users/forms.py

from django import forms

# 登陸表單驗證
class LoginForm(forms.Form):
    # 用戶名密碼不能爲空
    username = forms.CharField(required=True)
    password = forms.CharField(required=True,min_length=5)

(3)定義好forms後利用它來作驗證,並完善錯誤提示信息

from .forms import LoginForm

class LoginView(View):
    def get(self,request):
        return render(request, 'login.html')

    def post(self,request):
        # 實例化
        login_form = LoginForm(request.POST)
        if login_form.is_valid():
            # 獲取用戶提交的用戶名和密碼
            user_name = request.POST.get('username', None)
            pass_word = request.POST.get('password', None)
            # 成功返回user對象,失敗None
            user = authenticate(username=user_name, password=pass_word)
            # 若是不是null說明驗證成功
            if user is not None:
                # 登陸
                login(request, user)
                return render(request, 'index.html')
            # 只有當用戶名或密碼不存在時,才返回錯誤信息到前端
            else:
                return render(request, 'login.html', {'msg': '用戶名或密碼錯誤','login_form':login_form})
            
        # form.is_valid()已經判斷不合法了,因此這裏不須要再返回錯誤信息到前端了
        else:
            return render(request,'login.html',{'login_form':login_form})
# users/views.py

from django.shortcuts import render
from django.contrib.auth import authenticate,login

from django.contrib.auth.backends import ModelBackend
from .models import UserProfile
from django.db.models import Q
from django.views.generic.base import View
from .forms import LoginForm

#郵箱和用戶名均可以登陸
# 基礎ModelBackend類,由於它有authenticate方法
class CustomBackend(ModelBackend):
    def authenticate(self, request, username=None, password=None, **kwargs):
        try:
            # 不但願用戶存在兩個,get只能有一個。兩個是get失敗的一種緣由 Q爲使用並集查詢
            user = UserProfile.objects.get(Q(username=username)|Q(email=username))

            # django的後臺中密碼加密:因此不能password==password
            # UserProfile繼承的AbstractUser中有def check_password(self, raw_password):
            if user.check_password(password):
                return user
        except Exception as e:
            return None


class LoginView(View):
    def get(self,request):
        return render(request, 'login.html')

    def post(self,request):
        # 實例化
        login_form = LoginForm(request.POST)
        if login_form.is_valid():
            # 獲取用戶提交的用戶名和密碼
            user_name = request.POST.get('username', None)
            pass_word = request.POST.get('password', None)
            # 成功返回user對象,失敗None
            user = authenticate(username=user_name, password=pass_word)
            # 若是不是null說明驗證成功
            if user is not None:
                # 登陸
                login(request, user)
                return render(request, 'index.html')
            # 只有當用戶名或密碼不存在時,才返回錯誤信息到前端
            else:
                return render(request, 'login.html', {'msg': '用戶名或密碼錯誤','login_form':login_form})

        # form.is_valid()已經判斷不合法了,因此這裏不須要再返回錯誤信息到前端了
        else:
            return render(request,'login.html',{'login_form':login_form})
views.py

(4)完善login.html的錯誤提示信息

<div class="form-group marb20 {% if login_form.errors.username %}errorput{% endif %}">
                        <label>&nbsp;&nbsp;</label>
                        <input name="username" id="account_l" type="text" placeholder="手機號/郵箱" />
                    </div>
                    <div class="form-group marb8 {% if login_form.errors.username %}errorput{% endif %}">
                        <label>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</label>
                        <input name="password" id="password_l" type="password" placeholder="請輸入您的密碼" />
                    </div>
                    <div class="error btns login-form-tips" id="jsLoginTips">
                        {% for key,error in login_form.errors.items %}
                            {{ error }}
                        {% endfor %}
                        {{ msg }}
                    </div>

主要修改兩處

<!DOCTYPE html>
<html>

<head>
    <meta charset="UTF-8">
    <meta name="renderer" content="webkit">
    <meta http-equiv="X-UA-Compatible" content="IE=Edge,chrome=1" >
    <title>慕學在線網登陸</title>
    <link rel="stylesheet" type="text/css" href="/static/css/reset.css">
    <link rel="stylesheet" type="text/css" href="/static/css/login.css">
</head>
<body>
<div class="dialog" id="jsDialog">
<!--提示彈出框-->
<div class="successbox dialogbox" id="jsSuccessTips">
    <h1>成功提交</h1>
    <div class="close jsCloseDialog"><img src="/static/images/dig_close.png"/></div>
    <div class="cont">
        <h2>您的需求提交成功!</h2>
        <p></p>
    </div>
</div>
<div  class="noactivebox dialogbox" id="jsUnactiveForm" >
    <h1>郵件驗證提示</h1>
    <div class="close jsCloseDialog"><img src="/static/images/dig_close.png"/></div>
    <div class="center">
        <img src="/static/images/send.png"/>
        <p>咱們已經向您的郵箱<span class="green" id="jsEmailToActive">12@13.com</span>發送了郵件,<br/>爲保證您的帳號安全,請及時驗證郵箱</p>
        <p class="a"><a class="btn" id="jsGoToEmail" target="_blank" href="http://mail.qq.com">去郵箱驗證</a></p>
        <p class="zy_success upmove"></p>
        <p style="display: none;" class="sendE2">沒收到,您能夠查看您的垃圾郵件和被過濾郵件,也能夠再次發送驗證郵件(<span class="c5c">60s</span></p>
        <p class="sendE">沒收到,您能夠查看您的垃圾郵件和被過濾郵件,<br/>也能夠<span class="c5c green" id="jsSenEmailAgin" style="cursor: pointer;">再次發送驗證郵件</span></p>
    </div>
</div>
</div>
<div class="bg" id="dialogBg"></div>
<header>
    <div class="c-box fff-box">
        <div class="wp header-box">
            <p class="fl hd-tips">慕學在線網,在線學習平臺!</p>
            <ul class="fr hd-bar">
                <li>服務電話:<span>33333333</span></li>
                <li class="active"><a href="login.html">[登陸]</a></li>
                <li><a href="register.html">[註冊]</a></li>
            </ul>
        </div>
    </div>
</header>
<section>
    <div class="c-box bg-box">
        <div class="login-box clearfix">
            <div class="hd-login clearfix">
                <a class="index-logo" href="index.html"></a>
                <h1>用戶登陸</h1>
                <a class="index-font" href="index.html">回到首頁</a>
            </div>
            <div class="fl slide">
                <div class="imgslide">
                    <ul class="imgs">
                            <li><a href=""><img width="483" height="472" src="/static/images/mysql.jpg" /></a></li>
                            <li><a href=""><img width="483" height="472" src="/static/images/mysql.jpg" /></a></li>
                            <li><a href=""><img width="483" height="472" src="/static/images/mysql.jpg" /></a></li>
                    </ul>
                </div>
                <div class="unslider-arrow prev"></div>
                <div class="unslider-arrow next"></div>
            </div>
            <div class="fl form-box">
                <h2>賬號登陸</h2> 
                <form action="/login/" method="post" autocomplete="off">
                    <input type='hidden' name='csrfmiddlewaretoken' value='mymQDzHWl2REXIfPMg2mJaLqDfaS1sD5' />
                    <div class="form-group marb20 {% if login_form.errors.username %}errorput{% endif %}">
                        <label>&nbsp;&nbsp;</label>
                        <input name="username" id="account_l" type="text" placeholder="手機號/郵箱" />
                    </div>
                    <div class="form-group marb8 {% if login_form.errors.username %}errorput{% endif %}">
                        <label>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</label>
                        <input name="password" id="password_l" type="password" placeholder="請輸入您的密碼" />
                    </div>
                    <div class="error btns login-form-tips" id="jsLoginTips">
                        {% for key,error in login_form.errors.items %}
                            {{ error }}
                        {% endfor %}
                        {{ msg }}
                    </div>
                     <div class="auto-box marb38">

                        <a class="fr" href="forgetpwd.html">忘記密碼?</a>
                     </div>
                     <input class="btn btn-green" id="jsLoginBtn" type="submit" value="當即登陸 > " />
                <input type='hidden' name='csrfmiddlewaretoken' value='5I2SlleZJOMUX9QbwYLUIAOshdrdpRcy' />
                    {% csrf_token %}
                </form>
                <p class="form-p">沒有慕學在線網賬號?<a href="register.html">[當即註冊]</a></p>
            </div>
        </div>
    </div>
</section>
<script src="/static/js/jquery.min.js" type="text/javascript"></script>
<script src="/static/js/unslider.js" type="text/javascript"></script>
<script src="/static/js/login.js"  type="text/javascript"></script>
</body>
</html>
login.html

 顯示效果,當不輸入用戶名,密碼小與五位數的時候的提示信息以下:

 

 

上一篇:Django+xadmin打造在線教育平臺(一)

下一篇:Django+xadmin打造在線教育平臺(三)

相關文章
相關標籤/搜索