1. 程式人生 > >django2整合xadmin list index out of range報錯追蹤和處理

django2整合xadmin list index out of range報錯追蹤和處理

今天又搞起了django,個人愛好用最新版的,所以雖然比著老師的視訊做,還是出了莫名其妙的問題

IndexError at /xadmin/goods/goods/add/
list index out of range

遇到了陣列越界
貼下報錯資訊,當然這個看不出什麼,陣列越界,這菜鳥都能看懂的英文

Error during template rendering
In template /Users/seth/pyenv/imooc_env36/lib/python3.6/site-packages/crispy_forms/templates/bootstrap3/field.html, error
at line 28 {% if field|is_checkbox and form_show_labels %}

這裡寫圖片描述

順便上張圖
一般人看到這裡就懵了,反正只知道陣列越界,天知道什麼原因,然後把這個圖貼給別人。
淡定,django的報錯很詳細的,往下看
這裡寫圖片描述
很明顯是時間這邊出了問題
時間add_time的欄位型別出了問題
先說下django的時間欄位型別
有3個,這裡直接貼網上的

需要了解跟時間相關的三個modelField,
DateTimeField和DateField和TimeField
儲存的內容分別對應著datetime(),date(),time()三個物件。
    對於auto_now和auto_now_add。兩者預設值都為False
。 auto_now=Ture,欄位儲存時會自動儲存當前時間,但要注意每次對其例項執行save()的時候都會將當前時間儲存,也就是不能再手動給它存非當前時間的值。 auto_now_add=True,欄位在例項第一次儲存的時候會儲存當前時間,不管你在這裡是否對其賦值。但是之後的save()是可以手動賦值的。也就是新例項化一個model,想手動存其他時間,就需要對該例項save()之後賦值然後再save()。

隨便拷貝了一句,大概只是介紹了auto_now和auto_now_add,和我們報錯無關,這裡只是拓展一下三個時間型別,
然後我們來看這datetime(),date(),time()3個物件

date “1000-01-01”到“9999-12-31” 3位元組
time-838:59:59”到“838:59:59” 3位元組
datetime “1000-01-01 00:00:00” 到“9999-12-31 23:59:59” 8位元組

date :“yyyy-mm-dd”格式表示的日期值 
time :“hh:mm:ss”格式表示的時間值 
datetime: “yyyy-mm-dd hh:mm:ss”格式

修改時間格式為DateField,完美解決,
有些人不樂意了,按天的新增時間還有毛用,是的,問題解決了,但業務邏輯不對了

這裡寫圖片描述

回到之前被忽略的xadmin的第80行程式碼報錯提示
找到相關程式碼

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')))

input_html[1]就是報錯的程式碼,因為input_html裡只有一個元素,從報錯資訊裡也能找到input_html的值
這裡寫圖片描述
仔細看input_html長度是為1的,所以沒辦法取到值
再看上一行程式碼,作者是想通過用“\n”把input_html裡的兩個標籤拆開,但兩個標籤之間沒有換行,所以沒能拆分,導致報錯。

input_html = [ht for ht in super(AdminSplitDateTime, self).render(name, value, attrs).split('\n') if ht != '']

但是,作者當初這樣寫,肯定是能把兩個拆開的,為什麼忽然不行了呢?
這裡寫圖片描述
我們來看看這個forms是哪個html的
ctrl點MultWidget進去
這裡寫圖片描述
找到html了

{% spaceless %}{% for widget in widget.subwidgets %}{% include widget.template_name %}{% endfor %}{% endspaceless %}

裡面就一句話,先補充一下spaceless標籤

spaceless標籤:

用法:{% spaceless %}…內容…{% endspaceless %}

含義:刪除包圍內容中的所有tab或者回車字元

所以自然xadmin那邊的程式碼就錯誤了
來看下作者的提交記錄
https://github.com/django/django/commit/47681af34447e5d45f3fdb316497cdf9fbd0b7ce
這裡寫圖片描述
英文不太好,不過意思應該是空格會導致多個widget的時候顯示有問題,所以就加了spaceless標籤
問題找到了,
但是django畢竟是主框架,我們儘量不要動他的程式碼,
我們來修改xadmin的程式碼
原來使用\n分割的
我們把程式碼改成下面這樣

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]

原來的程式碼不要刪,如圖,註釋掉就好

這裡寫程式碼片
但有人可能還不明白了,怎麼date型別就不出錯,其實上面寫了,data是年月日,datetime是年月日時分秒就要2個widget顯示了,所以就出問題了

文章參考https://blog.csdn.net/yuhan963/article/details/79167743,感謝作者