Django+Xadmin打造在線教育系統(tǒng)(九)

xadmin的進(jìn)階開(kāi)發(fā)

因版本問(wèn)題.有些配置可能無(wú)效

自定義icon

xadmin的圖標(biāo)采用的是第三方css樣式font awesome,我們可以進(jìn)官網(wǎng)下載最新的樣式替代原本的晨仑,下載地址:http://www.fontawesome.com.cn/

下載完后把里面的“css”和“fonts”兩個(gè)文件夾拷貝到xadmin的源碼(路徑:xadmin/static/vendor/font-awesome)里面
使用model_icon來(lái)進(jìn)行修改

# Course的admin管理器
class CourseAdmin(object):
    '''課程'''

    list_display = [ 'name','desc','detail','degree','learn_times','students']
    search_fields = ['name', 'desc', 'detail', 'degree', 'students']
    list_filter = [ 'name','desc','detail','degree','learn_times','students']
    model_icon = 'fa fa-book'

默認(rèn)排序呻畸、只讀字段和不顯示的字段

課程:

  • 按點(diǎn)擊數(shù)倒序排序
  • 點(diǎn)擊數(shù)不能編輯
  • 不顯示收藏人數(shù)
# Course的admin管理器
class CourseAdmin(object):
    '''課程'''

    list_display = [ 'name','desc','detail','degree','learn_times','students']   #顯示的字段
    search_fields = ['name', 'desc', 'detail', 'degree', 'students']             #搜索
    list_filter = [ 'name','desc','detail','degree','learn_times','students']    #過(guò)濾 
    model_icon = 'fa fa-book'            #圖標(biāo)
    ordering = ['-click_nums']           #排序
    readonly_fields = ['click_nums']     #只讀字段,不能編輯
    exclude = ['fav_nums']               #不顯示的字段

下拉框搜索

寫(xiě)在外鍵所指的adminx配置中

relfield_style = 'fk-ajax'

當(dāng)有外鍵指向他巴柿,會(huì)以ajax方式加載
數(shù)據(jù)量過(guò)大時(shí)很有用

inlines添加數(shù)據(jù)

目前在添加課程的時(shí)候沒(méi)法添加章節(jié)和課程資源雌贱,我們可以用inlines去實(shí)現(xiàn)這一功能

class LessonInline(object):
    model = Lesson
    extra = 0


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


# 在CourseAdmin中使用inlines添加上面兩個(gè)的方法
class CourseAdmin(object):
    inlines = [LessonInline,CourseResourceInline]    #增加章節(jié)和課程資源

一張表分兩個(gè)Model來(lái)管理

課程里面分為輪播課程和不是輪播課程兩種類型啊送,我們可以分開(kāi)來(lái)管理
course/models.py里面新建一個(gè)Model

class BannerCourse(Course):
    '''顯示輪播課程'''
    class Meta:
        verbose_name = '輪播課程'
        verbose_name_plural = verbose_name
        #這里必須設(shè)置proxy=True,這樣就不會(huì)再生成一張表欣孤,同時(shí)還具有Model的功能
        proxy = True

course/adminx.py

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']    #過(guò)濾
    model_icon = 'fa fa-book'            #圖標(biāo)
    ordering = ['-click_nums']           #排序
    readonly_fields = ['click_nums']     #只讀字段
    exclude = ['fav_nums']               #不顯示的字段
    inlines = [LessonInline,CourseResourceInline]    #增加章節(jié)和課程資源

    def queryset(self):
        # 重載queryset方法馋没,來(lái)過(guò)濾出我們想要的數(shù)據(jù)的
        qs = super(CourseAdmin, self).queryset()
        # 只顯示is_banner=True的課程
        qs = qs.filter(is_banner=False)
        return qs


class BannerCourseAdmin(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']
    model_icon = 'fa fa-book'
    ordering = ['-click_nums']
    readonly_fields = ['click_nums']
    exclude = ['fav_nums']
    inlines = [LessonInline,CourseResourceInline]

    def queryset(self):
        #重載queryset方法,來(lái)過(guò)濾出我們想要的數(shù)據(jù)的
        qs = super(BannerCourseAdmin, self).queryset()
        #只顯示is_banner=True的課程
        qs = qs.filter(is_banner=True)
        return qs

# 將管理器與model進(jìn)行注冊(cè)關(guān)聯(lián)
xadmin.site.register(Course, CourseAdmin)
xadmin.site.register(BannerCourse, BannerCourseAdmin)

xadmin的其它常見(jiàn)功能

可以在列表上快速修改內(nèi)容

list_editable = [ 'degree','desc']

自定義函數(shù)作為列

def get_zj_nums(self):
    return self.lesson_set.all().count()
get_zj_nums.short_description = "章節(jié)數(shù)"

顯示自定義的html代碼

def go_to(self):
    from django.utils.safestring import mark_safe
    # 如果不mark safe降传。會(huì)對(duì)其進(jìn)行轉(zhuǎn)義
    return  mark_safe("<a )
go_to.short_description = "跳轉(zhuǎn)"

refresh定時(shí)刷新工具

refresh_times = [3,5]           #自動(dòng)刷新(里面是秒數(shù))

字段聯(lián)動(dòng)
應(yīng)用場(chǎng)景:當(dāng)添加一門(mén)課程的時(shí)候篷朵,希望課程機(jī)構(gòu)里面的課程數(shù) +1
重寫(xiě)xadmin的save_models方法

 def save_models(self):
      # 在保存課程的時(shí)候統(tǒng)計(jì)課程機(jī)構(gòu)的課程數(shù)
      # 字段聯(lián)動(dòng)
      obj = self.new_obj
      # 新增課程還沒(méi)有保存,統(tǒng)計(jì)的課程數(shù)少一個(gè)
      obj.save()
      # 必須確定存在婆排。
      if obj.course_org is not None:
          # obj實(shí)際是一個(gè)course對(duì)象
          course_org = obj.course_org
          course_org.course_nums = Course.objects.filter(course_org = course_org).count()
          course_org.save()

xadmin自行探究

  • local 語(yǔ)言包
  • migration 數(shù)據(jù)表的記錄
  • plugins 每一個(gè)后臺(tái)頁(yè)面都是一個(gè)plugin 插件機(jī)制
  • static文件声旺。js css
  • template xadmin自己用到的html文件
  • 對(duì)django admin的封裝

增加富文本編輯器Ueditor

下載地址 https://github.com/twz915/DjangoUeditor3/
解壓后,把DjangoUeditor文件夾拷貝到項(xiàng)目目錄下面

# settings中添加app

INSTALLED_APPS = [
    'DjangoUeditor',
]
 # 富文本編輯器url
    path('ueditor/',include('DjangoUeditor.urls' )),

course/models.py中Course修改detail字段

class Course(models.Model):
    # detail = models.TextField("課程詳情")
    detail = UEditorField(verbose_name=u'課程詳情', width=600, height=300, imagePath="courses/ueditor/",
                          filePath="courses/ueditor/", default='')

xadmin/plugs目錄下新建ueditor.py文件段只,代碼如下

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/plugs/__init__.py里面添加ueditor插件

PLUGINS = (
   'ueditor',
)

course/adminx.py中使用

class CourseAdmin(object):
    #detail就是要顯示為富文本的字段名
    style_fields = {"detail": "ueditor"}

在模板中必須關(guān)閉Django的自動(dòng)轉(zhuǎn)義才能正常顯示

    <div class="tab_cont tab_cont1">
         {% autoescape off %}
         {{ course.detail }}
         {% endautoescape %}
     </div>

或者

    {{ course.detail|safe }}

導(dǎo)入excel

  • 如何注入導(dǎo)入excel代碼到菜單
  • 如何只在課程列表顯示
  • 如何接收文件對(duì)文件進(jìn)行處理

新建xadmin/plugins/excel.py

import xadmin
from xadmin.views import BaseAdminPlugin, ListAdminView
from django.template import loader


#excel 導(dǎo)入
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)

添加到init.py文件中

PLUGINS = (
   'excel',
)

新建xadmin/templates/xadmin/excel/model_list.top_toolbar.import.html

    {% 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> 導(dǎo)入 <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> 導(dǎo)入 Excel</a></li>
      </ul>
        <script>
            function fileChange(target){
    //檢測(cè)上傳文件的類型
                var imgName = document.all.submit_upload.value;
                var ext,idx;
                if (imgName == ''){
                    document.all.submit_upload_b.disabled=true;
                    alert("請(qǐng)選擇需要上傳的 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">導(dǎo)入 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> 導(dǎo)入</button>
              </div>
              </form>
            </div><!-- /.modal-content -->
          </div><!-- /.modal-dalog -->
        </div><!-- /.modal -->

    </div>

只需要在adminx中設(shè)置變量import_excel=True就可以開(kāi)啟導(dǎo)入按鈕
在adminx中重寫(xiě)post方法,將文件內(nèi)容保存到數(shù)據(jù)中

def post(self, request, *args , **kwargs):
    if 'excel' in request.FILES:
        pass
# 中間pass步驟不管做什么事情腮猖,都要最后return父類的

return super(CourseAdmin, self).post(request, args, kwargs)
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市赞枕,隨后出現(xiàn)的幾起案子澈缺,更是在濱河造成了極大的恐慌,老刑警劉巖炕婶,帶你破解...
    沈念sama閱讀 211,817評(píng)論 6 492
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件姐赡,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡柠掂,警方通過(guò)查閱死者的電腦和手機(jī)雏吭,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,329評(píng)論 3 385
  • 文/潘曉璐 我一進(jìn)店門(mén),熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)陪踩,“玉大人杖们,你說(shuō)我怎么就攤上這事〖缈瘢” “怎么了摘完?”我有些...
    開(kāi)封第一講書(shū)人閱讀 157,354評(píng)論 0 348
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)傻谁。 經(jīng)常有香客問(wèn)我孝治,道長(zhǎng),這世上最難降的妖魔是什么? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 56,498評(píng)論 1 284
  • 正文 為了忘掉前任谈飒,我火速辦了婚禮岂座,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘杭措。我一直安慰自己费什,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,600評(píng)論 6 386
  • 文/花漫 我一把揭開(kāi)白布手素。 她就那樣靜靜地躺著鸳址,像睡著了一般。 火紅的嫁衣襯著肌膚如雪泉懦。 梳的紋絲不亂的頭發(fā)上稿黍,一...
    開(kāi)封第一講書(shū)人閱讀 49,829評(píng)論 1 290
  • 那天,我揣著相機(jī)與錄音崩哩,去河邊找鬼巡球。 笑死,一個(gè)胖子當(dāng)著我的面吹牛邓嘹,可吹牛的內(nèi)容都是我干的酣栈。 我是一名探鬼主播,決...
    沈念sama閱讀 38,979評(píng)論 3 408
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼吴超,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼钉嘹!你這毒婦竟也來(lái)了鸯乃?” 一聲冷哼從身側(cè)響起鲸阻,我...
    開(kāi)封第一講書(shū)人閱讀 37,722評(píng)論 0 266
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎缨睡,沒(méi)想到半個(gè)月后鸟悴,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 44,189評(píng)論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡奖年,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,519評(píng)論 2 327
  • 正文 我和宋清朗相戀三年细诸,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片陋守。...
    茶點(diǎn)故事閱讀 38,654評(píng)論 1 340
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡震贵,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出水评,到底是詐尸還是另有隱情猩系,我是刑警寧澤,帶...
    沈念sama閱讀 34,329評(píng)論 4 330
  • 正文 年R本政府宣布中燥,位于F島的核電站寇甸,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜拿霉,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,940評(píng)論 3 313
  • 文/蒙蒙 一吟秩、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧绽淘,春花似錦涵防、人聲如沸。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 30,762評(píng)論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至伦意,卻和暖如春火窒,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背驮肉。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 31,993評(píng)論 1 266
  • 我被黑心中介騙來(lái)泰國(guó)打工熏矿, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人离钝。 一個(gè)月前我還...
    沈念sama閱讀 46,382評(píng)論 2 360
  • 正文 我出身青樓票编,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親卵渴。 傳聞我的和親對(duì)象是個(gè)殘疾皇子慧域,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,543評(píng)論 2 349

推薦閱讀更多精彩內(nèi)容

  • 世界十大名校第四名:斯坦福大學(xué) 小利蘭·斯坦福大學(xué),常直接稱為斯坦福大學(xué)浪读,為一所坐落于美國(guó)加利福尼亞州斯坦福市的私...
    麥吉可先森閱讀 804評(píng)論 0 0
  • 1.很有心機(jī)的小孩子—— 那天我拿了個(gè)玩具公仔在公園的涼亭里昔榴, 一個(gè)四五歲的孩子看見(jiàn)了,于是過(guò)來(lái)對(duì)我說(shuō):“姐姐碘橘,能...
    范末末閱讀 356評(píng)論 1 0
  • 天旺無(wú)意中登錄了網(wǎng)上的婚戀網(wǎng)站互订,一幅幅美眉的照片讓他無(wú)比貪戀,搜索了一下痘拆,竟然有很多本地征婚的女子仰禽。一時(shí)興起,天旺...
    阿衛(wèi)1閱讀 343評(píng)論 1 1
  • 方糖小語(yǔ) 方糖小語(yǔ) 陰冷的雨天在晶瑩透亮的玻璃杯...
    樂(lè)盡天真且陶陶閱讀 296評(píng)論 0 1