目錄javascript
代碼mysql
github下載jquery
在線演示git
教程github
學習自慕課網-使用python3.x與Django2.0.1開發的在線教育平臺
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
安裝成功後,同時也安裝了不少依賴的包。
(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]
再運行就正常了
(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)
(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)
# 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)
# 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)
# 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)
此時項目目錄結構:
運行項目,進後臺管理界面以下:
將全局配置修改:
使用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)
再進後臺的界面,以下:
(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也一樣方法改爲顯示中文
大功告成
(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頁面,而後點‘’登陸」,跳轉到登陸頁面了
(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>用 戶 名</label> <input name="username" id="account_l" type="text" placeholder="手機號/郵箱" /> </div> <div class="form-group marb8 "> <label>密 碼</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>
若是用戶登陸錯誤,應該有提示錯誤信息,下面代碼:
<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>
(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
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')
MxOnline/settings.py添加以下代碼:
AUTHENTICATION_BACKENDS = ( 'users.views.CustomBackend', )
而後經過郵箱也能夠實現登陸了
(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)]
基於類的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})
(4)完善login.html的錯誤提示信息
<div class="form-group marb20 {% if login_form.errors.username %}errorput{% endif %}"> <label>用 戶 名</label> <input name="username" id="account_l" type="text" placeholder="手機號/郵箱" /> </div> <div class="form-group marb8 {% if login_form.errors.username %}errorput{% endif %}"> <label>密 碼</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>用 戶 名</label> <input name="username" id="account_l" type="text" placeholder="手機號/郵箱" /> </div> <div class="form-group marb8 {% if login_form.errors.username %}errorput{% endif %}"> <label>密 碼</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>
顯示效果,當不輸入用戶名,密碼小與五位數的時候的提示信息以下: