Django项目于之在线教育平台网站的实战开发(完结)

2022-09-15 12:30:01 浏览数 (1)

大家好,又见面了,我是你们的朋友全栈君。

说明:该篇博客是博主一字一码编写的,实属不易,请尊重原创,谢谢大家!

接着上一篇博客继续往下写 :https://blog.csdn.net/qq_41782425/article/details/90141577

项目源码下载

目录

一丶常见web攻击及防范

二丶Xadmin多种配置

三丶Xadmin插件开发(富文本编辑器)

四丶Xadmin插件开发(导出excel)

五丶项目部署上线

六丶项目总结


一丶常见web攻击及防范

1.sql注入攻击与防范

sql注入的危害

  • 非法读取丶篡改丶删除数据库中的数据
  • 盗取用户的各类敏感信息,获取利益
  • 通过修改数据库来修改网页上的内容
  • 注入木马等

sql注入登录演示

  • 定义原始方法登录视图
代码语言:javascript复制
# sql注入登录演示
class UnsafeLoginView(View):
    """不安全登录,使用最原始的方法进行登录"""
    def get(self, request):
        return render(request, "login.html")
    def post(self, request):
        user_name = request.POST.get("username", "")
        pass_word = request.POST.get("password", "")
        import MySQLdb
        conn = MySQLdb.connect(host="127.0.0.1", user="root", passwd="mysql", db="mxonline", charset="utf8")
        cursor = conn.cursor()
        sql = "select * from  users_userprofile where username = '{0}' and password = '{1}' ".format(user_name, pass_word)
        res = cursor.execute(sql)
        # 获取用户所有数据
        all_users = cursor.fetchall()
  • 在根级urls中修改登录视图为上一步定义的视图
代码语言:javascript复制
url(r'^login/$', UnsafeLoginView.as_view(), name="login"),  # 登录页
  • Debug测试输入不存在的用户名和密码,res变量的值为0,表示未查询到结果
  • 在登录页面,输入特殊的用户名,密码随便输入,如下图所示
  • Debug测试的结果是,居然查询到了数据,原因是1=1此条件为真所以肯定能查询到数据
  • 使用以上的sql语句在数据库进行查询,同样也能查询到数据

2.xss攻击原理及防范

xss跨站脚本攻击(Cross Site Scripting)的危害

  • 盗取各类用户账号,如用户网银账号丶各类管理员账号
  • 盗窃企业重要的具有商业价值的资料
  • 非法转账
  • 控制受害者机器向其他网站发起攻击丶注入木马等

xss攻击原理

  • 服务器对用户发送的请求地址中的name属性的值,直接做回显,并没有做任何加密处理,当黑客将请求地址中的name属性的值修改成一段js脚本,比如下图所示的获取cookie并进行alert打印,那么就会获取到用户的保存在本地的cookie

xss攻击流程图

  • 以下的js脚本只是其中的一种而已,而黑客是怎么将url发送给受害者的比如邮件,QQ等等

xss攻击防范

  • 首先代码里对用户输入的地方和变量都需要仔细检查长度和对(” <” >” ; ‘)等字符做过滤
  • 避免直接在cookie中泄露用户隐私,例如email丶密码等等
  • 通过使cookie和系统ip进行绑定来降低cookie泄露后的危险
  • 尽量采用POST进行表单提交而不使用GET(也就是请求地址中不出现参数)

3.csrf攻击与防范

csrf跨站请求伪造(Cross-site request forgery)的危害

  • 以你的名义进行邮件发送
  • 盗取你的账号
  • 购买商品
  • 虚拟货币转账

csrf攻击原理

csrf防范

  • 表单提交时加上打印出csrf_token的值即可对跨站攻击进行有效的防范{% csrf_token %}

二丶Xadmin多种配置

1.导航栏icon的修改

  • 首先登陆Font Awesome官网,下载最新版本图标字体库以及CSS框架
  • 在xadmin源码中查看当前使用的font-awesome的版本为4.0.3
  • 将下载好的font-awesome-4.7.0进行解压后,替换编辑器源码中的font-awesome目录文件
  • 在xadmin后端页面中左侧导航栏,修改用户心下的邮箱验证码图标
  • 在xadmin源码中auth.py模块中找到UserAdmin模型类中的图标属性变量为model_icon
  • 即在users/adminx中找到邮箱验证码的EmailVerifyRecordAdmin类,在类中添加model_icon属性,具体需要改成什么样的图标,需要在官网上找到要修改图片样式,如下图所示
  • 然后紧接着在EmailVerifyRecordAdmin邮箱验证码注册类中执行model_icon属性为上图的样式
  • Ctrl F5强制刷新xadmin后台,用户信息邮箱验证码的图标就修改成功了

2.xadmin后台表数据设定默认字段排序

  • 比如当用户点击查看课程列表时,整个列表数据是乱序的,比如点击数
  • 想让课程列表中的数据按照点击数的倒序进行排序,就需要在对应的注册类中添加如下ordering属性即可
代码语言:javascript复制
class CourseAdmin(object):
    list_display = ['name', 'desc', 'detail', 'degree', 'learn_times', 'students', 'click_nums']
    search_fields = ['name', 'desc', 'detail', 'degree', 'students']
    list_filter = ['name', 'desc', 'detail', 'degree', 'learn_times', 'students']
    ordering = ['-click_nums']
  • 刷新页面,成功按照课程点击数倒序排列显示数据

3.xadmin后台管理中字段设置为只读

  • 在课程数据中如点击数丶收藏认识丶学习人数应该是只读而不能进行修改编辑的
  • 在注册类中添加readonly_fields属性指向要只读的字段
代码语言:javascript复制
readonly_fields = ['students', 'click_nums', 'fav_nums']
  • 刷新页面则,指定只读的字段则显示在页面底部

4.在xadmin后台中不显示某些字段

  • 在注册类中添加exclude属性的值即可,需要注意的是exclude属性与readonly_fields属性时冲突的,所以需要去除readonly_fields属性中的click_nums字段
代码语言:javascript复制
readonly_fields = ['students', 'fav_nums']
exclude = ['click_nums']
  • 刷新页面则,不显示点击数字段

5.增加课程时修改外键选择的样式

  • 增加一门课程,需要通过下拉框来选择对应课程的机构,当数据庞大时,使用下拉框就没有搜索框来的方便
  • 在organization/adminx中找到外键所指向的注册类,在该类中设置样式
代码语言:javascript复制
relfield_style = 'fk-ajax'
  • 刷新页面,在选择课程机构时则成功显示出搜索框

6.inline的使用

  • 在xadmin后台管理中为课程添加章节信息时,不能在增加课程页面直接添加,而是需要退出课程到章节字段中去选择课程后才能添加课程的章节信息,在xadmin中也能像django admin那样去做到在一个页面直接添加外键的信息,在课程管理的adminx中需要定义一个类LessonInline,通过课程注册类中添加inlines的属性指向LessonInline对象即可达到效果
代码语言:javascript复制
class LessonInline(object):
    model = Lesson
    extra = 0


class CourseAdmin(object):
    list_display = ['name', 'desc', 'detail', 'degree', 'learn_times', 'students', 'click_nums']
    search_fields = ['name', 'desc', 'detail', 'degree', 'students']
    list_filter = ['name', 'desc', 'detail', 'degree', 'learn_times', 'students']
    ordering = ['-click_nums']
    readonly_fields = ['students', 'fav_nums']
    exclude = ['click_nums']
    inlines = [LessonInline]
  • 刷洗页面,增加课程页面底部就会出现章节,点击 则可以添加该课程对应的章节信息,很是方便
  • 需要注意的是,inline只能完成一成嵌套,不能完成多层,比如课程—章节—视频这就没法,但一个课程对应多个外键,就可以在inlines 属性中添加多个类,因为是列表类型的变量,在课程增加页面,除了添加章节还可以添加课程资源
代码语言:javascript复制
class LessonInline(object):
    model = Lesson
    extra = 0


class CourseResourceInline(object):
    model = CourseResource
    extra = 0


class CourseAdmin(object):
    list_display = ['name', 'desc', 'detail', 'degree', 'learn_times', 'students', 'click_nums']
    search_fields = ['name', 'desc', 'detail', 'degree', 'students']
    list_filter = ['name', 'desc', 'detail', 'degree', 'learn_times', 'students']
    ordering = ['-click_nums']
    readonly_fields = ['students', 'fav_nums']
    exclude = ['click_nums']
    inlines = [LessonInline, CourseResourceInline]
  • 刷新页面,在增加课程页面就可以同时添加章节信息以及课程资源数据了

7.自定义列表返回数据,同一个model注册两个管理器

  • 在之前主页动态数据展示时,因公开课程栏中嵌套了轮播图,就需要在课程所在的模型类Course添加is_banner是否轮播字段
  • 如果想在课程管理中产生另一个表数据,这个表数据只显示轮播的课程数据那么就需要在courses/models中创建一个轮播课程模型类,这个类必须继承Course,只需要在类中编写Meta类并定义名称即可
代码语言:javascript复制
class BannerCourse(Course):
    class Meta:
        verbose_name = "轮播课程"
        verbose_name_plural = verbose_name
        proxy = True
  • 将上面定义的模型类,在courses/adminx中进行导入注册
代码语言:javascript复制
class BannerCourseAdmin(object):
    list_display = ['name', 'desc', 'detail', 'degree', 'learn_times', 'students', 'click_nums']
    search_fields = ['name', 'desc', 'detail', 'degree', 'students']
    list_filter = ['name', 'desc', 'detail', 'degree', 'learn_times', 'students']
    ordering = ['-click_nums']
    readonly_fields = ['students', 'fav_nums']
    exclude = ['click_nums']
    inlines = [LessonInline, CourseResourceInline]

xadmin.site.register(BannerCourse, BannerCourseAdmin)
  • 强制刷新页面后,在课程管理导航栏下成功创建一个轮播课程表数据,这个数据说白了跟课程的数据一模一样只是名称变了
  • 如何让轮播课程表中数据只显示轮播的课程,在轮播课程对应的注册类中定义一个方法,该方法用于对父类Course模型类中的is_banner字段进行过滤,将过滤后的数据进行返回即可,为什么可以对is_banner字段进行过滤,因为BannerCourseAdmin与BannerCourse进行注册关联,并且BannerCourse这个模型类又继承Course模型类,即可以对is_banner字段进行过滤处理了
代码语言:javascript复制
class BannerCourseAdmin(object):
    list_display = ['name', 'desc', 'detail', 'degree', 'learn_times', 'students', 'click_nums']
    search_fields = ['name', 'desc', 'detail', 'degree', 'students']
    list_filter = ['name', 'desc', 'detail', 'degree', 'learn_times', 'students']
    ordering = ['-click_nums']
    readonly_fields = ['students', 'fav_nums']
    exclude = ['click_nums']
    inlines = [LessonInline, CourseResourceInline]

    def queryset(self):
        qs = super(BannerCourseAdmin, self).queryset()
        qs = qs.filter(is_banner=True)
        return qs
  • 刷新页面查看轮播课程数据,则成功只显示轮播的课程数据
  • 既然在轮播课程中只显示轮播课程数据,那么在课程中也应当只显示出不轮播的课程数据,跟上面同理在CourseAdmin注册类中定义queryset方法,只需要修改父类名以及将filter方法中的条件改成False即可
代码语言:javascript复制
class CourseAdmin(object):
    list_display = ['name', 'desc', 'detail', 'degree', 'learn_times', 'students', 'click_nums']
    search_fields = ['name', 'desc', 'detail', 'degree', 'students']
    list_filter = ['name', 'desc', 'detail', 'degree', 'learn_times', 'students']
    ordering = ['-click_nums']
    readonly_fields = ['students', 'fav_nums']
    exclude = ['click_nums']
    inlines = [LessonInline, CourseResourceInline]
    
    def queryset(self):
        qs = super(CourseAdmin, self).queryset()
        qs = qs.filter(is_banner=False)
        return qs
  • 查看课程下的数据,只有13条,总共课程16条数据,轮播课程3条,所以数据筛选正确

8.list_editable属性

  • 在课程注册类CourseAdmin中添加list_editable属性,这个属性可以在列表中对设定的字段直接进行编辑,而不需要点击进入课程详情中进行编辑
代码语言:javascript复制
list_editable = ['name', 'degree']
  • 刷新课程列表页面,则指定可编辑的name字段以及degree字段则出现编辑按钮,点击按钮可直接进行编辑保存了

9.在课程列表中显示对应课程的章节数

  • 之前在页面模板中为了显示课程的章节数,在Course模型类中定义了get_zj_nums方法,用于获取课程的章节数,short_description方法是用于在xadmin后台显示的字段名称
代码语言:javascript复制
def get_zj_nums(self):
    #获取课程章节数
    return self.lesson_set.all().count()
get_zj_nums.short_description = "章节数"
  • 在课程注册类CourseAdmin中list_display属性中添加该方法名,对应django来说判断该字段为方法名时,则会去调用此方法
代码语言:javascript复制
list_display = ['name', 'desc', 'detail', 'degree', 'learn_times', 'students', 'click_nums', "get_zj_nums"]
  • 刷新课程列表页,则成功显示出课程对应的章节数

10.在课程列表字段添加跳转按钮,指定跳转的链接地址

  • 在Course模型类中定义go_to方法,具体如下,说明一下make_safe方法是让链接地址安全不进行转义操作
代码语言:javascript复制
def go_to(self):
    from django.utils.safestring import mark_safe
    return mark_safe("<a href='http://www.baidu.com'>跳转</a>")
go_to.short_description = "跳转"
  • 在注册类CourseAdmin中将以上方法名添加到list_display属性中
代码语言:javascript复制
list_display = ['name', 'desc', 'detail', 'degree', 'learn_times', 'students', 'click_nums', "get_zj_nums", "go_to"]
  • 测试显示跳转字段并进行目标地址的跳转

11.页面定时刷新插件

  • xadmin提供了此功能,在RefreshPlugin类中refresh_times为空列表,表示未进行设置刷新时间
  • 在CourseAdmin中添加refresh_times属性,并设定其值为3秒或5秒刷新条件
代码语言:javascript复制
refresh_times = [3, 5]
  • 测试自动刷新,选择3秒进行刷新测试,请注意链接地址的自动刷新

12.在保存课程的时候统计课程机构的课程数

  • 在CourseAdmin注册类中重写父类的save_models方法,当对课程进行修改或者增加时都会对数据进行保存,那么就会去调用重写的save_models方法,就可以在这个方法中查询获取对应的课程机构的课程数
代码语言:javascript复制
def save_models(self):
    # 在保存课程的时候统计课程机构的课程数
    obj = self.new_obj
    obj.save()
    if obj.course_org is not None:
        course_org = obj.course_org
        course_org.course_nums = Course.objects.filter(course_org=course_org).count()
        course_org.save()
  • 在课程机构中查看第一条数据同济大学的课程数,这里显示为0
  • Debug 断点测试,在课程中对Mysql主从复制课程所属的课程机构修改成同济大学,后点击保存
  • Debug断点测试完成后,查看课程机构中同济大学的课程数

三丶Xadmin插件开发(富文本编辑器)

说明: django ueditor富文本编辑器的集成

1.Xadmin插件制作官方中文文档 Xadmin 插件制作 — Django Xadmin 2.1.5 beta documentation

2.DjangoUeditor源码文档 GitHub – zhangfisher/DjangoUeditor: DjangoUeditor

3.DjangoUeditor使用

  • 安装DjangoUeditor
  • 在INSTALL_APPS里面增加DjangoUeditor
代码语言:javascript复制
INSTALLED_APPS = [
    'django.contrib.admin',
    .......,
    .......,
    "pure_pagination",
    "DjangoUeditor"
]
  • 配置urls
代码语言:javascript复制
url(r'^ueditor/',include('DjangoUeditor.urls' )),
  • 在需要使用富文本编辑器的模型类中导入UEditorField类,项目中Course模型类中的课程详情字段是需要使用富文本的,所以对detail字段进行如下修改
  • 说明:UEditorField继承自models.TextField,因此你可以直接将model里面定义的models.TextField直接改成UEditorField即可
代码语言:javascript复制
detail = UEditorField(verbose_name=u"课程详情",width=600, height=300, imagePath="courses/ueditor/",
                                         filePath="courses/ueditor/", default='')
  • 在xadmin/plugins目录下创建ueditor.py文件,在文件中进行如下编写
代码语言:javascript复制
import xadmin
from xadmin.views import BaseAdminPlugin, CreateAdminView, ModelFormAdminView, UpdateAdminView
from DjangoUeditor.models import UEditorField
from DjangoUeditor.widgets import UEditorWidget
from django.conf import settings


class XadminUEditorWidget(UEditorWidget):
    def __init__(self,**kwargs):
        self.ueditor_options=kwargs
        self.Media.js = None
        super(XadminUEditorWidget,self).__init__(kwargs)

class UeditorPlugin(BaseAdminPlugin):

    def get_field_style(self, attrs, db_field, style, **kwargs):
        if style == 'ueditor':
            if isinstance(db_field, UEditorField):
                widget = db_field.formfield().widget
                param = {}
                param.update(widget.ueditor_settings)
                param.update(widget.attrs)
                return {'widget': XadminUEditorWidget(**param)}
        return attrs

    def block_extrahead(self, context, nodes):
        js = '<script type="text/javascript" src="%s"></script>' % (settings.STATIC_URL   "ueditor/ueditor.config.js")         #自己的静态目录
        js  = '<script type="text/javascript" src="%s"></script>' % (settings.STATIC_URL   "ueditor/ueditor.all.min.js")   #自己的静态目录
        nodes.append(js)

xadmin.site.register_plugin(UeditorPlugin, UpdateAdminView)
xadmin.site.register_plugin(UeditorPlugin, CreateAdminView)
  • 在xadmin/plugins目录下的__init__.py文件中,将ueditor插件注册进去
代码语言:javascript复制
PLUGINS = (
    'actions', 
    '.......',
    'ueditor',
)

4.错误修正

说明:DjangoUeditor是基于Python 2.7的进行开发的,博主这里的开发环境为python3,所以需要对DjangoUeditor安装包下的models.py丶settings.py丶widgets.py丶commands.py丶urls.py丶views.py进行修改

  • models.py
代码语言:javascript复制
# from widgets import UEditorWidget,AdminUEditorWidget
from .widgets import UEditorWidget, AdminUEditorWidget
  • settings.py
代码语言:javascript复制
更新配置:从用户配置文件settings.py重新读入配置UEDITOR_SETTINGS,覆盖默认
def UpdateUserSettings():
    UserSettings=getattr(gSettings,"UEDITOR_SETTINGS",{}).copy()
    # if UserSettings.has_key("config"):UEditorSettings.update(UserSettings["config"])
    # if UserSettings.has_key("upload"):UEditorUploadSettings.update(UserSettings["upload"])
    if UserSettings.get("config"):UEditorSettings.update(UserSettings["config"])
    if UserSettings.get("upload"):UEditorUploadSettings.update(UserSettings["upload"])
  • widgets.py
代码语言:javascript复制
# import settings as USettings
# from  commands import *
from . import settings as USettings
from .commands import *
  • commands.py
代码语言:javascript复制
# import settings as USettings
from . import settings as USettings
  • urls.py
代码语言:javascript复制
#coding:utf-8
# from django import VERSION
# if VERSION[0:2]>(1,3):
#     from django.conf.urls import patterns, url
# else:
#     from django.conf.urls.defaults import patterns, url
#
# from views import get_ueditor_controller
#
# urlpatterns = patterns('',
#     url(r'^controller/$',get_ueditor_controller)
# )
from .widgets import UEditorWidget, AdminUEditorWidget
from .views import get_ueditor_controller
from django.conf.urls import url

urlpatterns = [
    url(r'^controller/$', get_ueditor_controller),
]
  • views.py
代码语言:javascript复制
# import settings as USettings
from . import settings as USettings

#保存上传的文件
def save_upload_file(PostFile,FilePath):
    try:
        f = open(FilePath, 'wb')
        for chunk in PostFile.chunks():
            f.write(chunk)
    # except Exception,E:
    #     f.close()
    #     return u"写入文件错误:"  E.message
    # f.close()
    # return u"SUCCESS"
    except Exception as E:
        f.close()
        return u"写入文件错误:"  E.message
    f.close()
    return u"SUCCESS"
  • 重启项目进入xadmin后台进行增加课程操作时,结果报错了
  • 回到编辑器,查看错误位置
  • 查看安装包DjangoUeditor中发现并没有ueditor.html,甚至连templates目录都没有

解决方法有三种:第一种就是在github上将别人修正好的适合python3的DjangoUeditor源码拷贝进行源码安装;第二种就是自己下载DjangoUeditor免安装源码放在项目extra_apps目录下;第三种就是下载DjangoUeditor源码安装,在对其下的模块进行修正

  • 博主选择第三种,将下载好的DjangoUeditor-master.zip进行解压,将解压后的文件放在项目根目录下,具体操作如下
  • 完成上一步后,刷新页面则成功在课程详情字段加载出富文本编辑器
  • 添加新的课程使用富文本编辑器
  • 查看课程列表,在刚新增的课程详情页中显示全是HTML代码
  • 在进入课程详情后,详情页面显示出转义的内容
  • 需要在course-detail模板中找到课程详情数据块,对数据块内容进行转义关闭
代码语言:javascript复制
<div class="tab_cont tab_cont1">
    {% autoescape off %}
	<p>{
  
  { course.detail }}</p>
    {% endautoescape %}
</div>
  • 刷新页面,成功显示出在富文本编写的内容

5.总结步骤:

代码语言:javascript复制
安装
1.pip install DjangoUeditor
2.settings.py 中加入DjangoUeditor
3.url(r'ueditor/', include('DjangoUeditor.urls'))
4.detail = UeditorField()

xadmin
1.plugins中添加ueditor.py文件,在__init__中加入ueditor
2.adminx中添加style_fields = {'detail':'ueditor'}

四丶Xadmin插件开发(导出excel)

说明:excel的导入插件开发

1.在xadmin/plugins中创建excel.py文件,拷贝如下内容

代码语言:javascript复制
import xadmin
from xadmin.views import BaseAdminPlugin, ListAdminView
from django.template import loader
from xadmin.plugins.utils import get_context_dict


#excel 导入
class ListImportExcelPlugin(BaseAdminPlugin):
    import_excel = False

    def init_request(self, *args, **kwargs):
        return bool(self.import_excel)

    def block_top_toolbar(self, context, nodes):
        nodes.append(loader.render_to_string('xadmin/excel/model_list.top_toolbar.import.html', context=get_context_dict(context)))


xadmin.site.register_plugin(ListImportExcelPlugin, ListAdminView)

2.在xadmin/templates/xadmin目录下创建excel目录,在目录下创建model_list.top_toolbar.import.html文件,文件内容如下

代码语言:javascript复制
{% load i18n %}
<div class="btn-group export">
  <a class="dropdown-toggle btn btn-default btn-sm" data-toggle="dropdown" href="#">
    <i class="icon-share"></i> 导入 <span class="caret"></span>
  </a>
  <ul class="dropdown-menu" role="menu" aria-labelledby="dLabel">
      <li><a data-toggle="modal" data-target="#export-modal-import-excel"><i class="icon-circle-arrow-down"></i> 导入 Excel</a></li>
  </ul>
    <script>
        function fileChange(target){
//检测上传文件的类型
            var imgName = document.all.submit_upload.value;
            var ext,idx;
            if (imgName == ''){
                document.all.submit_upload_b.disabled=true;
                alert("请选择需要上传的 xls 文件!");
                return;
            } else {
                idx = imgName.lastIndexOf(".");
                if (idx != -1){
                    ext = imgName.substr(idx 1).toUpperCase();
                    ext = ext.toLowerCase( );
{#                    alert("ext=" ext);#}
                    if (ext != 'xls' && ext != 'xlsx'){
                        document.all.submit_upload_b.disabled=true;
                        alert("只能上传 .xls 类型的文件!");

                        return;
                    }
                } else {
                    document.all.submit_upload_b.disabled=true;
                    alert("只能上传 .xls 类型的文件!");
                    return;
                }
            }

        }
    </script>
    <div id="export-modal-import-excel" class="modal fade">
      <div class="modal-dialog">
        <div class="modal-content">
          <form method="post" action="" enctype="multipart/form-data">
              {% csrf_token %}
          <div class="modal-header">
            <button type="button" class="close" data-dismiss="modal" aria-hidden="true">&times;</button>
            <h4 class="modal-title">导入 Excel</h4>
          </div>
          <div class="modal-body">
               <input type="file" onchange="fileChange(this)" name="excel" id="submit_upload">

          </div>
          <div class="modal-footer">
            <button type="button" class="btn btn-default" data-dismiss="modal">{% trans "Close" %}</button>
            <button class="btn btn-success" type="submit" id="submit_upload_b"><i class="icon-share"></i> 导入</button>
          </div>
          </form>
        </div><!-- /.modal-content -->
      </div><!-- /.modal-dalog -->
    </div><!-- /.modal -->

</div>

3.在courses/adminx下的CourseAdmin类中添加import_excel = True属性,并定义一个post方法,在这个方法中可以任意添加任何逻辑代码,这里就不进行逻辑代码的演示了,直接pass,但必须返回如下调用,不然会出错

代码语言:javascript复制
def post(self, request, *args, **kwargs):
    if 'excel' in request.FILES:
        pass
    return super(CourseAdmin, self).post(request, args, kwargs)

4.在plugins/__init__.py中注册此插件

代码语言:javascript复制
PLUGINS = (
    'actions', 
    'filters', 
    'bookmark', 
    'export', 
    'ueditor',
    'excel',
)
  • 测试刷新课程列表页,在右上角菜单栏中显示出导入按钮,因为没有写对上传excel文件操作,所以这里只能显示出此功能

五丶项目部署上线

1.指定python3版本创建django_py3虚拟环境,并进入此环境

2.安装项目所需的包

3.查看当前虚拟环境下的包

4.运行项目

  • 在终端执行python3 manage.py runserver
  • 结果报错了,这个错无非就是安装的DjangoUeditor包中源码为python2编写的
  • 将windows虚拟环境D:django_py3Libsite-packages下的DjangoUeditor包替换掉ubuntu虚拟环境django_py3/lib/python3.5/site-packages下的DjangoUeditor
  • 再次使用命令启动项目,结果又报错了,原因是没有mxonline的数据库

5.将windows上的mxonline数据库数据传输到ubuntu中

  • 在ubuntu中创建mxonline数据库
  • 查看ubuntu上的IP地址
  • 博主这里在使用Navicat软件时,不小心将mxonline数据库数据表数据清空了,所以导致博主需要花大量时间在xadmin后台进行数据的添加,所以博主先将数据库mxonline进行备份,免得再出现该情况
  • 使用Navicat软件测试在windows上测试连接ubuntu中的mysql
  • 在Windows上打开Navicat软件,通过该软件数据传输功能将mxonline数据库数据传输到ubuntu中的mxonline数据中
  • 点击开始后,出现success表示成功
  • 回到ubuntu中,重新启动项目,则启动成功
  • 打开浏览器访问成功访问主页并显示动态数据

6.安装nginx

说明:安装过程不用演示,很简单

  • 因博主在之前Django电商项目中已经安装过了所以这里不用安装,并且ngin.conf配置文件中的配置为Django电商项目的配置;在Django电商项目部署配置nginx时,将默认的配置文件进行了备份(nginx.conf.fefault),所以只需要指定该配置文件来启动nginx即可
  • 在浏览器中直接输入ubuntu IP地址即默认访问80端口,则显示nginx服务启动成功页面

7.安装uwsgi

  • 进入虚拟环境中安装uwsgi
  • 使用uwsgi启动项目
  • 在浏览器中输入http://192.168.4.63:8000/ 则成功加载出页面动态数据;但静态资源无法加载出来

8.nginx配置

  • 拷贝nginx默认的配置文件到当前目录下并命名为mx_nginx.conf
  • 编写mx_nginx.conf文件内容,具体如下
代码语言:javascript复制
server {
        listen       80;
        server_name  192.168.4.63 www.mxonline.com;

        #charset koi8-r;

        #access_log  logs/host.access.log  main;
	location /static {
            alias /home/taogang/Desktop/MxOnline/static;
        }

        location /media {
            alias /home/taogang/Desktop/MxOnline/media;
        }

        location / {
            include   uwsgi_params;
            uwsgi_pass  127.0.0.1:8000;
        }
}
  • 指定以上配置文件启动nginx服务器

9.将项目所用到的所有静态资源文件收集到static目录下

  • 需要在settings配置文件中配置收集静态文件路径,之前Django电商项目也是这样的
  • 进入项目虚拟环境,执行命令进行收集

10.创建并配置uwsgi.ini文件

  • 在项目根目录下创建一个uwsgi.ini配置文件,编写以下内容
  • 在配置文件settings中,设置为线上环境
代码语言:javascript复制
DEBUG = False

ALLOWED_HOSTS = ['*']

11.测试使用uwsgi启动项目

  • 启动uwsgi
  • 在浏览器直接访问http://192.168.4.63/ 成功加载动态数据以及静态资源文件

12.在windows中使用域名访问网站

  • 切换到windows中,在浏览器输入http://192.168.4.63/ 成功访问ubuntu中uwsgi启动的网站,之所以能够访问是因为通过vmware虚拟机搭建的ubuntu桥接模式为同一网段ip,即可以互相ping通
  • 接下来想要在浏览器地址栏中输入www.mxonline.com域名来访问网站主页,则需要在windows电脑hosts文件中添加如下内容,则表示输入此域名相当于访问192.168.4.63IP地址,因为没有购买域名,所以只能这样做,仅限于本地可以使用该域名访问
  • 测试在浏览器中输入mxonline.com – 是否成功访问主页

六丶项目总结

1.数据库设计

  • users app model用户信息相关数据表设计
  • organization app model课程机构数据表设计
  • courses app model课程相关数据表设计
  • operation app model用户操作相关数据表设计

2.后台管理系统开发

  • xadmin安装以及model注册
  • xadmin全局配置

3.登录和注册以及找回密码

  • 登录(session和cookie机制)
  • 注册(form表单提交和图片验证码以及发送邮件)
  • 找回密码(邮件发送)

4.课程机构

  • 机构列表(分页和筛选以及排序)
  • 机构详情(收藏和富文本编辑)
  • 咨询提交(modelform验证和保存)

5.课程功能

  • 课程列表(分页和排序)
  • 课程详情(收藏丶章节展示丶资源展示丶评论)

6.讲师功能

  • 讲师列表(分页和排序)
  • 讲师详情(收藏)

7.个人中心

  • 用户信息修改(修改密码丶头像丶邮箱丶基本信息)
  • 我的课程
  • 我的收藏(取消收藏)
  • 我的消息

8.全局功能

  • 搜索功能(公开课丶课程机构丶授课老师)
  • 全局404和500页面配置
  • 首页开发
  • 点击数和收藏数修改以及退出功能

9.web攻击及防范

  • sql注入攻击
  • xss攻击
  • csrf攻击

10.xadmin进阶开发

  • userprofile注册和设置
  • xadmin常见功能设置
  • inlinemode注册和proxy代理注册
  • django ueditor富文本编辑器集成
  • excel导入插件集成

发布者:全栈程序员栈长,转载请注明出处:https://javaforall.cn/164302.html原文链接:https://javaforall.cn

0 人点赞