我的django项目经历

423 阅读16分钟
ZT地址 : www.cnblogs.com/derek118440…
一、前言
开发环境:
    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.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所以需要安装该库
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__.py
import
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
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]


(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
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的安装
django2.0的安装(源码安装方式):
https://github.com/sshwsfc/xadmin/tree/django2

把zip文件放到pip目录下,运行下面命令安装:
pip install xadmin-django2

其它版本

如果上面安装提示Runtime错误:
更换安装源(使用豆瓣源)
pip install -i 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.py
from
django.urls
import
path
import
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.py
import
xadmin
from
.models
import
EmailVerifyRecord
#
xadmin中这里是继承object,不再是继承admin
class
EmailVerifyRecordAdmin(object):
pass
xadmin.site.register(EmailVerifyRecord,EmailVerifyRecordAdmin)
[url=]
[/url]


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


刷新后的界面:
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.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]


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


(3)operation
代码如下:
[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名称汉化,菜单收叠。
使用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
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
'

其它三个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.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]


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


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


(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
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类
View类源码参考

基于类的urls配置
from
users.views
import
LoginView  path(
'
login/
'
,LoginView.as_view(),name =
'
login
'
),

(2)users下新建form.py文件
代码如下:
[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

(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

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



更多免费技术资料可关注:annalin1203