博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
Django+xadmin打造在线教育平台(二)
阅读量:5122 次
发布时间:2019-06-13

本文共 33298 字,大约阅读时间需要 110 分钟。

目录

      

      

      

      

      

代码

教程

学习自慕课网-使用python3.x与Django2.0.1开发的在线教育平台

三、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.pyfrom django.urls import pathimport xadminurlpatterns = [    path('xadmin/', xadmin.site.urls),]

(5)注册app

把下面两个app注册到settings.py的INSTALLED_APPS中

'xadmin','crispy_forms'

(6)重新生成数据库

python manage.py makemigrationspython manage.py migrate

(7)设置成中文

LANGUAGE_CODE = 'zh-hans'TIME_ZONE = 'Asia/Shanghai'USE_I18N = TrueUSE_L10N = TrueUSE_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('
%s' '
' '
' '%s
' % (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.pyimport xadminfrom .models import EmailVerifyRecord#xadmin中这里是继承object,不再是继承adminclass EmailVerifyRecordAdmin(object):    passxadmin.site.register(EmailVerifyRecord,EmailVerifyRecordAdmin)

(2)完善功能,增加显示字段,搜索和过滤

修改users/adminx.py,代码如下:

# users/adminx.pyimport xadminfrom .models import EmailVerifyRecord#xadmin中这里是继承object,不再是继承adminclass 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.pyimport xadminfrom .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.pyimport xadminfrom .models import CityDict, CourseOrg, Teacherclass 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.pyimport xadminfrom .models import UserAsk, UserCourse, UserMessage, CourseComments, UserFavoriteclass 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.pyimport xadminfrom .models import EmailVerifyRecord,Banner#xadmin中这里是继承object,不再是继承adminclass 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.pyimport xadminfrom .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.pyimport xadminfrom .models import CityDict, CourseOrg, Teacherclass 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.pyimport xadminfrom .models import UserAsk, UserCourse, UserMessage, CourseComments, UserFavoriteclass 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.pyimport xadminfrom .models import EmailVerifyRecord,Bannerfrom 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,不再是继承adminclass 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 AppConfigclass UsersConfig(AppConfig):    name = 'users'

修改后:

from django.apps import AppConfigclass UsersConfig(AppConfig):    name = 'users'    verbose_name = '用户'

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

添加代码如下:

# users/__init__.pydefault_app_config = 'users.apps.UsersConfig'

其它三个app也同样方法改成显示中文

 大功告成

 

四、完成登录功能

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.pyimport xadminfrom django.urls import pathfrom django.views.generic import TemplateViewurlpatterns = [    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.pyurlpatterns = [    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

原始样子

取消注释,将login.html改为“login/”

现在可以访问index页面,然后点‘’登录”,跳转到登录页面了

4.2.用户登录

(1)修改login的路由

from django.views.generic import TemplateViewfrom users import viewsurlpatterns = [    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 renderfrom django.contrib.auth import authenticate,logindef 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

{% csrf_token %}
login.html

如果用户登录错误,应该有提示错误信息,下面代码:

 

 

(4)修改index.html

原始index.html的代码

服务电话:33333333

注册
登录
bobby

django

bobby

 我们应该做个验证,当用户已登录状态的时候,显示用户姓名和图像及其个人中心信息

 如果没有登录,则显示登录和注册

更改代码如下:

{% if request.user.is_authenticated %}
bobby

django

bobby

{% else %}

服务电话:33333333

注册
登录
{% endif %}
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 ModelBackendfrom .models import UserProfilefrom 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.pyfrom django.shortcuts import renderfrom django.contrib.auth import authenticate,loginfrom django.contrib.auth.backends import ModelBackendfrom .models import UserProfilefrom 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 Nonedef 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 Viewclass 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.pyfrom 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 LoginFormclass 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.pyfrom django.shortcuts import renderfrom django.contrib.auth import authenticate,loginfrom django.contrib.auth.backends import ModelBackendfrom .models import UserProfilefrom django.db.models import Qfrom django.views.generic.base import Viewfrom .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 Noneclass 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的错误提示信息

主要修改两处

    
慕学在线网登录

成功提交

您的需求提交成功!

邮件验证提示

我们已经向您的邮箱12@13.com发送了邮件,

为保证您的账号安全,请及时验证邮箱

去邮箱验证

没收到,您可以查看您的垃圾邮件和被过滤邮件,

也可以再次发送验证邮件

慕学在线网,在线学习平台!

login.html

 显示效果,当不输入用户名,密码小与五位数的时候的提示信息如下:

 

 

上一篇:

下一篇:

 

转载于:https://www.cnblogs.com/derek1184405959/p/8592800.html

你可能感兴趣的文章
【Demo 0011】多媒体播放器
查看>>
MySql DDL语言(数据库和数据表的管理)
查看>>
用示例说明BitMap索引的效率要优于B-Tree索引
查看>>
EF(Entity FrameWork)实体框架
查看>>
git基础-远程仓库的使用
查看>>
Elasticsearch及相关插件的安装
查看>>
Unknown storage engine 'InnoDB'
查看>>
Windows 环境下运用Python制作网络爬虫
查看>>
Wincc V7.3SE安装截图
查看>>
转载——开阔自己的视野,勇敢的接触新知识
查看>>
UML中的6大关系(关联、依赖、聚合、组合、泛化、实现)
查看>>
北京集训:20180310
查看>>
位运算 中度难度 子集
查看>>
tp5无刷新分页
查看>>
51单片机学习笔记之定时器程序设计
查看>>
Java——容器(泛型)
查看>>
javascript删除数组里的对象
查看>>
springcloud20---Config加入eureka
查看>>
Linux系统添加永久静态路由的方法
查看>>
简单的SQL注入学习
查看>>