A股上市公司传智教育(股票代码 003032)旗下技术交流社区北京昌平校区

 找回密码
 加入黑马

QQ登录

只需一步,快速开始

Fourier尤尤莫莫

初级黑马

  • 黑马币:12

  • 帖子:5

  • 精华:0

© Fourier尤尤莫莫 初级黑马   /  2018-9-10 15:10  /  2144 人查看  /  3 人回复  /   0 人收藏 转载请遵从CC协议 禁止商业使用本文

ZT地址 : http://www.cnblogs.com/derek1184405959/p/8590360.html
一、前言
开发环境:
    python:  3.6.4
    Django: 2.0.2
后台管理:xadmin
1.1.项目介绍
系统概括:
  • 系统具有完整的用户登录注册以及找回密码功能,拥有完整个人中心。
  • 个人中心: 修改头像,修改密码,修改邮箱,可以看到我的课程以及我的收藏。可以删除收藏,我的消息。
  • 导航栏: 公开课,授课讲师,授课机构,全局搜索。
  • 点击公开课–> 课程列表,排序-搜索。热门课程推荐,课程的分页。
  • 点击课程–> 课程详情页中对课程进行收藏,取消收藏。富文本展示课程内容。
  • 点击开始学习–> 课程的章节信息,课程的评论信息。课程资源的下载链接。
  • 点击授课讲师–>授课讲师列表页,对讲师进行人气排序以及分页,右边有讲师排行榜。
  • 点击讲师的详情页面–> 对讲师进行收藏和分享,以及讲师的全部课程。
  • 导航栏: 授课机构有分页,排序筛选功能。
  • 机构列表页右侧有快速提交我要学习的表单。
  • 点击机构–> 左侧:机构首页,机构课程,机构介绍,机构讲师。
  • 后台管理系统可以切换主题。左侧每一个功能都有列表显示, 增删改查,筛选功能。
  • 课程列表页可以对不同字段进行排序。选择多条记录进行删除操作。
  • 课程列表页:过滤器->选择字段范围等,搜索,导出csv,xml,json。
  • 课程新增页面上传图片,富文本的编辑。时间选择,添加章节,添加课程资源。
  • 日志记录:记录后台人员的操作
1.2.创建工程
创建工程
django-admin startproject MxOnline
然后开始项目的开发
二、models设计
项目的开发都是从models设计开始,后台的管理和前端的渲染无非就是对数据库的增删改查,所以models设计的好坏对整个项目的开发起着至关重要的因素。
下面是我画的图,可以很直观的看出来我们需要的models。
放大显示:

创建四个app
[url=][/url]
python manage.py startapp userspython manage.py startapp coursepython manage.py startapp organizationpython manage.py startapp operation[url=][/url]

然后分别设计每个app的models
2.1.users 用户
自定义userProfile
系统自动生成的user表如下:
  • id: 主键, password 密码, last_login Django自动记录用户最后登录时间,。
  • is_superuser 表明用户是否是超级用户(后台管理会用到)。
  • username 用户名字段不要随便改动, email 邮箱,
  • is_staff 表示是否是员工(后台管理会用到)。
  • is_active 用户是否是激活状态, date_joined 注册时间。

我们要扩展user表,添加需要的字段

个人中心页面信息:

users/models.py添加代码:
[url=][/url]
# users/models.pyfrom django.db import modelsfrom django.contrib.auth.models import AbstractUserclass 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所以需要安装该库
pip install pillow
注册app
[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
AUTH_USER_MODEL = 'users.UserProfile'
设计数据库为Mysql
[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]

init.py里面导入pymysql模块
# user/__init__.pyimport pymysqlpymysql.install_as_MySQLdb()
迁移数据库
python manage.py makemigrationspython manage.py migrate
user中还需要添加的表(这些功能比较独立):
  • EmailVerifyRecord - 邮箱验证码
  • Banner - 轮播图

EmailVerifyRecord   验证码
代码如下:
[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]

Banner   轮播图
代码如下:
[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]

说明:
  image上传到哪里
      url是图片的路径
      index控制轮播图的播放顺序

这样users的三张表就创建完了
写代码要根据PEP8规范
每个class之间要空两格
2.2.Course 课程
课程app中需要四张表
  • Course  课程表
  • Lesson  章节信息
  • Video    视频
  • CourseResource  课程资源
(1)Course  课程表
代码如下:
[url=][/url]
from datetime import datetimefrom django.db import modelsclass 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]

(2)Lesson 章节信息表
代码如下:
[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]

(3)Video 视频
代码如下:
[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]

(4)CourseResourse  课程资源
[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        城市信息
(1)CourseOrg
代码如下:
[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]

(2)CityDict
代码如下:
[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]

(3)Teacher
代码如下:
[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 用户收藏
(1)UserAsk
代码如下:
[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]

(2)UserMessage
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]

(3)CourseComments
代码如下:
[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]

(4)UserCourse
代码如下:
[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]

(5)UserFavorite
代码如下:
[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]

上面所有models的完整代码如下:
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放到一个文件夹
创建package: apps
把之前的四个app全部剪切到apps包里面
不要选“Search for references”
去掉searchfor的勾选。拖进去之后会报错,说找不到那些import的模块了。
解决方案:右键Mark为sourceRoot。根目录下找不到的,会去apps下搜索。
但是这时候cmd下还是会报错。需要在settings设置
插入第0是希望它先搜索我们app下东西:
import osimport 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的安装
django2.0的安装(源码安装方式):
https://github.com/sshwsfc/xadmin/tree/django2
把zip文件放到pip目录下,运行下面命令安装:
pip install xadmin-django2
其它版本
如果上面安装提示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
[url=][/url]
# urls.pyfrom django.urls import pathimport xadminurlpatterns = [    path('xadmin/', xadmin.site.urls),][url=][/url]

(5)注册app
把下面两个app注册到settings.py的INSTALLED_APPS中
'xadmin','crispy_forms'
(6)重新生成数据库
python manage.py makemigrationspython manage.py migrate
(7)设置成中文
[url=][/url]
LANGUAGE_CODE = 'zh-hans'TIME_ZONE = 'Asia/Shanghai'USE_I18N = TrueUSE_L10N = TrueUSE_TZ = False[url=][/url]

(8)创建一个管理员用户
python manage.py createsuperuser
现在就可以运行了
python manage.py runserver
可以看到成功进入管理界面

datetimefield报错问题解决:
当我们点增加用户信息,会报错

可以看到报的是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.pyimport xadminfrom .models import EmailVerifyRecord#xadmin中这里是继承object,不再是继承adminclass EmailVerifyRecordAdmin(object):    passxadmin.site.register(EmailVerifyRecord,EmailVerifyRecordAdmin)[url=][/url]

(2)完善功能,增加显示字段,搜索和过滤
修改users/adminx.py,代码如下:
[url=][/url]
# 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)[url=][/url]

刷新后的界面:
users中Banner也注册进去
[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注册
(1)course
代码如下: 注意外键
[url=][/url]
# 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)[url=][/url]

(2)organizations
代码如下:
[url=][/url]
# 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)[url=][/url]

(3)operation
代码如下:
[url=][/url]
# 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)[url=][/url]

全部代码:
users/adminx.py
course/adminx.py
organization/adminx.py
operation/adminx.py
此时项目目录结构:

运行项目,进后台管理界面如下:
3.5.xadmin的全局配置
将全局配置修改:
  • 如左上角:django Xadmin。下面的我的公司
  • 主题修改,app名称汉化,菜单收叠。
使用Xadmin的主题功能。
把全站的配置放在users\adminx.py中:
(1)添加主题功能
[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]

没添加主题前,右上角界面
添加主题后,可以选择自己喜欢的主题
(2)全局配置
修改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全部代码
再进后台的界面,如下:
(3)修改app的名字
在apps.py里面配置app的显示名称
以users/apps.py为例,其它三个同样操作
默认apps.py里面的代码
from django.apps import AppConfigclass UsersConfig(AppConfig):    name = 'users'
修改后:
[url=][/url]
from django.apps import AppConfigclass UsersConfig(AppConfig):    name = 'users'    verbose_name = '用户'[url=][/url]

还要在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中
[url=][/url]
# 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'),][url=][/url]

(5)登录页面
把login.html拷贝到templates文件夹下
使用ctrl+f查找出所有“../”, 然后ctrl+r 全部替换为“/static/”
配置login的url
[url=][/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'),][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.用户登录
(1)修改login的路由
[url=][/url]
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路由][url=][/url]

(2)写login的视图
[url=][/url]
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')[url=][/url]

(3)更改login.html
login.html
如果用户登录错误,应该有提示错误信息,下面代码:
<div class="error btns login-form-tips" id="jsLoginTips">{{ msg }}</div>


(4)修改index.html
原始index.html的代码
[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
(5)增加邮箱登录
让用户可以通过邮箱或者用户名都可以登录,用自定义authenticate方法
这里是继承ModelBackend类来做的验证
ModelBackend源码
[url=][/url]
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[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 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': '用户名或密码错误'})[url=][/url]

继承的View类
View类源码参考
基于类的urls配置
from users.views import LoginView  path('login/',LoginView.as_view(),name = 'login'),
(2)users下新建form.py文件
代码如下:
[url=][/url]
# users/forms.pyfrom 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 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})[url=][/url]

views.py
(4)完善login.html的错误提示信息
[url=][/url]
<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>[url=][/url]

主要修改两处
login.html
显示效果,当不输入用户名,密码小与五位数的时候的提示信息如下:



3 个回复

倒序浏览
、加油加油
回复 使用道具 举报
回复 使用道具 举报
6666
回复 使用道具 举报
您需要登录后才可以回帖 登录 | 加入黑马