ZT地址 : www.cnblogs.com/derek118440… 一、前言1.1.项目介绍 - 系统具有完整的用户登录注册以及找回密码功能,拥有完整个人中心。
- 个人中心: 修改头像,修改密码,修改邮箱,可以看到我的课程以及我的收藏。可以删除收藏,我的消息。
- 导航栏: 公开课,授课讲师,授课机构,全局搜索。
- 点击公开课–> 课程列表,排序-搜索。热门课程推荐,课程的分页。
- 点击课程–> 课程详情页中对课程进行收藏,取消收藏。富文本展示课程内容。
- 点击开始学习–> 课程的章节信息,课程的评论信息。课程资源的下载链接。
- 点击授课讲师–>授课讲师列表页,对讲师进行人气排序以及分页,右边有讲师排行榜。
- 点击讲师的详情页面–> 对讲师进行收藏和分享,以及讲师的全部课程。
- 导航栏: 授课机构有分页,排序筛选功能。
- 机构列表页右侧有快速提交我要学习的表单。
- 点击机构–> 左侧:机构首页,机构课程,机构介绍,机构讲师。
- 后台管理系统可以切换主题。左侧每一个功能都有列表显示, 增删改查,筛选功能。
- 课程列表页可以对不同字段进行排序。选择多条记录进行删除操作。
- 课程列表页:过滤器->选择字段范围等,搜索,导出csv,xml,json。
- 课程新增页面上传图片,富文本的编辑。时间选择,添加章节,添加课程资源。
- 日志记录:记录后台人员的操作
1.2.创建工程 django-admin startproject MxOnline 二、models设计项目的开发都是从models设计开始,后台的管理和前端的渲染无非就是对数据库的增删改查,所以models设计的好坏对整个项目的开发起着至关重要的因素。 下面是我画的图,可以很直观的看出来我们需要的models。
[url=]  [/url] python manage.py startapp userspython manage.py startapp coursepython manage.py startapp organizationpython manage.py startapp operation [url=]  [/url]
2.1.users 用户 - id: 主键, password 密码, last_login Django自动记录用户最后登录时间,。
- is_superuser 表明用户是否是超级用户(后台管理会用到)。
- username 用户名字段不要随便改动, email 邮箱,
- is_staff 表示是否是员工(后台管理会用到)。
- is_active 用户是否是激活状态, date_joined 注册时间。
我们要扩展user表,添加需要的字段 个人中心页面信息:
[url=]  [/url] # users/models.py from django.db import models from django.contrib.auth.models import AbstractUser class UserProfile(AbstractUser): gender_choices = ( ( ' male ' , ' 男 ' ), ( ' female ' , ' 女 ' ) ) nick_name = models.CharField( ' 昵称 ' ,max_length=50,default= '' ) birthday = models.DateField( ' 生日 ' ,null=True,blank=True) gender = models.CharField( ' 性别 ' ,max_length=10,choices=gender_choices,default= ' female ' ) adress = models.CharField( ' 地址 ' ,max_length=100,default= '' ) mobile = models.CharField( ' 手机号 ' ,max_length=11,null=True,blank=True) image = models.ImageField(upload_to= ' image/%Y%m ' ,default= ' image/default.png ' ,max_length=100) class Meta: verbose_name = ' 用户信息 ' verbose_name_plural = verbose_name def __str__ (self): return self.username [url=]  [/url]
因为Image字段需要用到pillow所以需要安装该库
[url=]  [/url] INSTALLED_APPS = [ ' django.contrib.admin ' , ' django.contrib.auth ' , ' django.contrib.contenttypes ' , ' django.contrib.sessions ' , ' django.contrib.messages ' , ' django.contrib.staticfiles ' , ' users ' ] [url=]  [/url]
AUTH_USER_MODEL = ' users.UserProfile '
[url=]  [/url] # DATABASES = { # 'default': { # 'ENGINE': 'django.db.backends.sqlite3', # 'NAME': os.path.join(BASE_DIR, 'db.sqlite3'), # } # } DATABASES = { ' default ' : { ' ENGINE ' : ' django.db.backends.mysql ' , ' NAME ' : ' mxonline ' , # 数据库名字 ' USER ' : ' root ' , # 账号 ' PASSWORD ' : ' 123456 ' , # 密码 ' HOST ' : ' 127.0.0.1 ' , # IP ' PORT ' : ' 3306 ' , # 端口 }} [url=]  [/url]
# user/__init__.py import pymysqlpymysql.install_as_MySQLdb()
python manage.py makemigrationspython manage.py migrate
- EmailVerifyRecord - 邮箱验证码
- Banner - 轮播图
[url=]  [/url] class EmailVerifyRecord(models.Model): send_choices = ( ( ' register ' , ' 注册 ' ), ( ' forget ' , ' 找回密码 ' ) ) code = models.CharField( ' 验证码 ' ,max_length=20) email = models.EmailField( ' 邮箱 ' ,max_length=50) send_type = models.CharField(choices=send_choices,max_length=10) send_time = models.DateTimeField(default=datetime.now) class Meta: verbose_name = ' 邮箱验证码 ' verbose_name_plural = verbose_name [url=]  [/url]
[url=]  [/url] class Banner(models.Model): title = models.CharField( ' 标题 ' ,max_length=100) image = models.ImageField( ' 轮播图 ' ,upload_to= ' banner/%Y%m ' ,max_length=100) url = models.URLField( ' 访问地址 ' ,max_length=200) index = models.IntegerField( ' 顺序 ' ,default=100) add_time = models.DateTimeField( ' 添加时间 ' ,default=datetime.now) class Meta: verbose_name = ' 轮播图 ' verbose_name_plural = verbose_name [url=]  [/url]
2.2.Course 课程 - Course 课程表
- Lesson 章节信息
- Video 视频
- CourseResource 课程资源
[url=]  [/url] from datetime import datetime from django.db import models class Course(models.Model): DEGREE_CHOICES = ( ( " cj " , " 初级 " ), ( " zj " , " 中级 " ), ( " gj " , " 高级 " ) ) name = models.CharField( " 课程名 " ,max_length=50) desc = models.CharField( " 课程描述 " ,max_length=300) detail = models.TextField( " 课程详情 " ) degree = models.CharField( ' 难度 ' ,choices=DEGREE_CHOICES, max_length=2) learn_times = models.IntegerField( " 学习时长(分钟数) " ,default=0) students = models.IntegerField( " 学习人数 " ,default=0) fav_nums = models.IntegerField( " 收藏人数 " ,default=0) image = models.ImageField( " 封面图 " ,upload_to= " courses/%Y/%m " ,max_length=100) click_nums = models.IntegerField( " 点击数 " ,default=0) add_time = models.DateTimeField( " 添加时间 " ,default=datetime.now,) class Meta: verbose_name = " 课程 " verbose_name_plural = verbose_name def __str__ (self): return self.name [url=]  [/url]
[url=]  [/url] class Lesson(models.Model): course = models.ForeignKey(Course,verbose_name= ' 课程 ' ,on_delete=models.CASCADE) name = models.CharField( " 章节名 " ,max_length=100) add_time = models.DateTimeField( " 添加时间 " ,default=datetime.now) class Meta: verbose_name = " 章节 " verbose_name_plural = verbose_name def __str__ (self): return ' 《{0}》课程的章节 >> {1} ' .format(self.course, self.name) [url=]  [/url]
[url=]  [/url] class Video(models.Model): lesson = models.ForeignKey(Lesson, verbose_name= " 章节 " ,on_delete=models.CASCADE) name = models.CharField( " 视频名 " ,max_length=100) add_time = models.DateTimeField( " 添加时间 " , default=datetime.now) class Meta: verbose_name = " 视频 " verbose_name_plural = verbose_name [url=]  [/url]
[url=]  [/url] class CourseResource(models.Model): course = models.ForeignKey(Course, verbose_name= " 课程 " ,on_delete=models.CASCADE) name = models.CharField( " 名称 " ,max_length=100) download = models.FileField( " 资源文件 " ,upload_to= " course/resource/%Y/%m " ,max_length=100) add_time = models.DateTimeField( " 添加时间 " , default=datetime.now) class Meta: verbose_name = " 课程资源 " verbose_name_plural = verbose_name [url=]  [/url]
2.3.organization 机构 - CourseOrg 课程机构基本信息
- Teacher 教师基本信息
- CityDict 城市信息
[url=]  [/url] class CourseOrg(models.Model): name = models.CharField( ' 机构名称 ' ,max_length=50) desc = models.TextField( ' 机构描述 ' ) click_nums = models.IntegerField( ' 点击数 ' ,default=0) fav_nums = models.IntegerField( ' 收藏数 ' ,default=0) image = models.ImageField( ' 封面图 ' ,upload_to= ' org/%Y%m ' ,max_length=100) address = models.CharField( ' 机构地址 ' ,max_length=150,) city = models.ForeignKey(CityDict,verbose_name= ' 所在城市 ' ,on_delete=models.CASCADE) add_time = models.DateTimeField(default=datetime.now) class Meta: verbose_name = ' 课程机构 ' verbose_name_plural = verbose_name [url=]  [/url]
[url=]  [/url] class CityDict(models.Model): name = models.CharField( ' 城市 ' ,max_length=20) desc = models.CharField( ' 描述 ' ,max_length=200) add_time = models.DateTimeField(default=datetime.now) class Meta: verbose_name = ' 城市 ' verbose_name_plural= verbose_name [url=]  [/url]
[url=]  [/url] class Teacher(models.Model): org = models.ForeignKey(CourseOrg,verbose_name= ' 所属机构 ' ,on_delete=models.CASCADE) name = models.CharField( ' 教师名 ' ,max_length=50) work_years = models.IntegerField( ' 工作年限 ' ,default=0) work_company = models.CharField( ' 就职公司 ' ,max_length=50) work_position = models.CharField( ' 公司职位 ' ,max_length=50) points = models.CharField( ' 教学特点 ' ,max_length=50) click_nums = models.IntegerField( ' 点击数 ' ,default=0) fav_nums = models.IntegerField( ' 收藏数 ' ,default=0) add_time = models.DateTimeField(default=datetime.now) class Meta: verbose_name = ' 教师 ' verbose_name_plural = verbose_name def __str__ (self): return " [{0}]的教师: {1} " .format(self.org, self.name) [url=]  [/url]
2.4.operation - UseAsk 用户咨询
- UserMessage 用户消息表
- CourseComments 用户评论
- UserCourse 用户学习的课程
- UserFavorite 用户收藏
[url=]  [/url] class UserAsk(models.Model): name = models.CharField( ' 姓名 ' ,max_length=20) mobile = models.CharField( ' 手机 ' ,max_length=11) course_name = models.CharField( ' 课程名 ' ,max_length=50) add_time = models.DateTimeField( ' 添加时间 ' ,default=datetime.now) class Meta: verbose_name = ' 用户咨询 ' verbose_name_plural = verbose_name def __str__ (self): return self.name [url=]  [/url]
user字段,默认0代表消息是发给所有用户,而不是某个单独的用户;可以通过user.id发给特定用户消息 [url=]  [/url] class UserMessage(models.Model): user = models.IntegerField( ' 接受用户 ' ,default=0) message = models.CharField( ' 消息内容 ' ,max_length=500) has_read = models.BooleanField( ' 是否已读 ' ,default=False) add_time = models.DateTimeField( ' 添加时间 ' , default=datetime.now) class Meta: verbose_name = ' 用户消息 ' verbose_name_plural = verbose_name [url=]  [/url]
[url=]  [/url] class CourseComments(models.Model): user = models.ForeignKey(UserProfile,verbose_name= ' 用户 ' ,on_delete=models.CASCADE) course = models.ForeignKey(Course,verbose_name= ' 课程 ' ,on_delete=models.CASCADE) comments = models.CharField( ' 评论 ' ,max_length=200) add_time = models.DateTimeField( ' 添加时间 ' , default=datetime.now) class Meta: verbose_name = ' 课程评论 ' verbose_name_plural = verbose_name [url=]  [/url]
[url=]  [/url] class UserCourse(models.Model): user = models.ForeignKey(UserProfile,verbose_name= ' 用户 ' ,on_delete=models.CASCADE) course = models.ForeignKey(Course,verbose_name= ' 课程 ' ,on_delete=models.CASCADE) add_time = models.DateTimeField( ' 添加时间 ' , default=datetime.now) class Meta: verbose_name = ' 用户课程 ' verbose_name_plural = verbose_name [url=]  [/url]
[url=]  [/url] class UserFavorite(models.Model): FAV_TYPE = ( (1, ' 课程 ' ), (2, ' 课程机构 ' ), (3, ' 讲师 ' ) ) user = models.ForeignKey(UserProfile,verbose_name= ' 用户 ' ,on_delete=models.CASCADE) fav_id = models.IntegerField( ' 数据id ' ,default=0) fav_type = models.IntegerField(verbose_name= ' 收藏类型 ' ,choices=FAV_TYPE,default=1) add_time = models.DateTimeField( ' 添加时间 ' , default=datetime.now) class Meta: verbose_name = ' 用户收藏 ' verbose_name_plural = verbose_name [url=]  [/url]
users/models.py
course/models.py
operations/models.py
organization/models.py
创建完models后一定要把所有的apps添加到settings的“INSTALLED_APPS”里面 [url=]  [/url] INSTALLED_APPS = [ ' django.contrib.admin ' , ' django.contrib.auth ' , ' django.contrib.contenttypes ' , ' django.contrib.sessions ' , ' django.contrib.messages ' , ' django.contrib.staticfiles ' , ' users ' , ' course ' , ' organization ' , ' operation ' ,] [url=]  [/url]
python manage.py makemigrationspython manage.py migrate
2.5.把四个app放到一个文件夹 不要选“Search for references” 去掉searchfor的勾选。拖进去之后会报错,说找不到那些import的模块了。 解决方案:右键Mark为sourceRoot。根目录下找不到的,会去apps下搜索。 但是这时候cmd下还是会报错。需要在settings设置 import os import sys # Build paths inside the project like this: os.path.join(BASE_DIR, ...) BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath( __file__ )))sys.path.insert(0,os.path.join(BASE_DIR, ' apps ' ))
三、xadmin后台管理3.1.xadmin的安装 https://github.com/sshwsfc/xadmin/tree/django2
pip install 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,所以要卸载之前安装的
[url=]  [/url] # urls.py from django.urls import path import xadminurlpatterns = [ path( ' xadmin/ ' , xadmin.site.urls),] [url=]  [/url]
把下面两个app注册到settings.py的INSTALLED_APPS中
python manage.py makemigrationspython manage.py migrate
[url=]  [/url] LANGUAGE_CODE = ' zh-hans ' TIME_ZONE = ' Asia/Shanghai ' USE_I18N = TrueUSE_L10N = TrueUSE_TZ = False [url=]  [/url]
python manage.py createsuperuser
python manage.py runserver
可以看到报的是xadmin/widgets中第80行 [url=]  [/url] 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 ' ))) [url=]  [/url]
上面贴出来的最后一行代码就是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,代码如下: [url=]  [/url] # users/adminx.py import xadmin from .models import EmailVerifyRecord # xadmin中这里是继承object,不再是继承admin class EmailVerifyRecordAdmin(object): pass xadmin.site.register(EmailVerifyRecord,EmailVerifyRecordAdmin) [url=]  [/url]
[url=]  [/url] # 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) [url=]  [/url]
[url=]  [/url] 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) [url=]  [/url]
3.4.剩余app model注册 [url=]  [/url] # 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) [url=]  [/url]
[url=]  [/url] # 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) [url=]  [/url]
[url=]  [/url] # 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) [url=]  [/url]
users/adminx.py
course/adminx.py
organization/adminx.py
operation/adminx.py
3.5.xadmin的全局配置 - 如左上角:django Xadmin。下面的我的公司
- 主题修改,app名称汉化,菜单收叠。
把全站的配置放在users\adminx.py中: [url=]  [/url] from xadmin import views # 创建xadmin的最基本管理器配置,并与view绑定 class BaseSetting(object): # 开启主题功能 enable_themes = True use_bootswatch = True # 将基本配置管理与view绑定 xadmin.site.register(views.BaseAdminView,BaseSetting) [url=]  [/url]
修改django admin 和下面的我的公司收起菜单 [url=]  [/url] # 全局修改,固定写法 class GlobalSettings(object): # 修改title site_title = ' NBA后台管理界面 ' # 修改footer site_footer = ' 科比的公司 ' # 收起菜单 menu_style = ' accordion ' # 将title和footer信息进行注册 xadmin.site.register(views.CommAdminView,GlobalSettings) [url=]  [/url]
users/adminx.py全部代码
以users/apps.py为例,其它三个同样操作 from django.apps import AppConfig class UsersConfig(AppConfig): name = ' users '
[url=]  [/url] from django.apps import AppConfig class UsersConfig(AppConfig): name = ' users ' verbose_name = ' 用户 ' [url=]  [/url]
还要在users/__init__.py中引用apps.py的配置 # users/__init__.py default_app_config = ' users.apps.UsersConfig '
四、完成登录功能4.1.首页和登录页面的配置 (1)把html文件中index.html拷贝到templates文件夹内 前端初始文件可以去我github上面下载:https://github.com/derek-zhang123/MxOnline STATICFILES_DIRS = ( os.path.join(BASE_DIR, ' static ' ),)
使用ctrl+f查找出所有“../”, 然后ctrl+r 全部替换为“/static/” [url=]  [/url] # MxOnline/urls.py import xadmin from django.urls import path from django.views.generic import TemplateViewurlpatterns = [ path( ' xadmin/ ' , xadmin.site.urls), path( '' , TemplateView.as_view(template_name= ' index.html ' ),name= ' index ' ),] [url=]  [/url]
把login.html拷贝到templates文件夹下 使用ctrl+f查找出所有“../”, 然后ctrl+r 全部替换为“/static/” [url=]  [/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 ' ),] [url=]  [/url]
更改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.用户登录 [url=]  [/url] from django.views.generic import TemplateView from 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路由 ] [url=]  [/url]
[url=]  [/url] 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 ' ) [url=]  [/url]
login.html
< div class ="error btns login-form-tips" id ="jsLoginTips" > {{ msg }} </ div >
[url=]  [/url] < 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 > [url=]  [/url]
我们应该做个验证,当用户已登录状态的时候,显示用户姓名和图像及其个人中心信息 index.html
让用户可以通过邮箱或者用户名都可以登录,用自定义authenticate方法 ModelBackend源码
[url=]  [/url] 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 [url=]  [/url]
users/views.py
MxOnline/settings.py添加如下代码: AUTHENTICATION_BACKENDS = ( ' users.views.CustomBackend ' ,)
4.3.用form实现登录 (1)把前面views中的user_login()函数改成基于类的形式 [url=]  [/url] 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 ' : ' 用户名或密码错误 ' }) [url=]  [/url]
View类源码参考
from users.views import LoginView path( ' login/ ' ,LoginView.as_view(),name = ' login ' ),
[url=]  [/url] # users/forms.py from django import forms # 登录表单验证 class LoginForm(forms.Form): # 用户名密码不能为空 username = forms.CharField(required=True) password = forms.CharField(required=True,min_length=5) [url=]  [/url]
(3)定义好forms后利用它来做验证,并完善错误提示信息 [url=]  [/url] 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}) [url=]  [/url]
views.py
[url=]  [/url] < 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 > [url=]  [/url]
login.html
显示效果,当不输入用户名,密码小与五位数的时候的提示信息如下:
|
|