前言: 今晚寫一篇關于學員/講師/銷售員CRM系統(tǒng)。這個小項目是27號開始做的,大概搞了一星期不到。我把一些知識點總結下,還寫下當時克服的BUG。
Django練習小項目:學員管理系統(tǒng)設計開發(fā)
帶著項目需求學習是最有趣和效率最高的,今天就來基于下面的需求來繼續(xù)學習Django
項目需求:
分講師\學員\課程顧問角色
學員可以屬于多個班級,學員成績按課程分別統(tǒng)計
每個班級至少包含一個或多個講師
一個學員要有狀態(tài)轉化的過程 ,比如未報名前,報名后,畢業(yè)老學員
客戶要有咨詢紀錄, 后續(xù)的定期跟蹤紀錄也要保存
每個學員的所有上課出勤情況\學習成績都要保存
學??梢杂蟹中^(qū),默認每個校區(qū)的員工只能查看和管理自己校區(qū)的學員
客戶咨詢要區(qū)分來源
拿到需求后,先要分析,再設計表結構: 超級重要!!
View Code
先來張圖看看效果: 下圖是銷售員Alex登陸后看到的界面
點擊右上方Alex已招學員,出現(xiàn)下圖界面:
一、前端界面實現(xiàn)
界面看著我感覺是蠻漂亮的,登陸界面和信息界面都是搞bootstrap模版的。只要將bootstrap模版修改下,就變成所需要的界面啦。不會修改的可以看看如何使用bootstrap。
二、字數顯示限制
如果備注過多,會使界面不好看,要想使備注只顯示一定的字數,可用下列方法: 只顯示13個字節(jié)
1 | <td>{{ customer.consult_memo|truncatechars: 13 }}< / td> |
三、報名狀態(tài)加色
第一種方法,比較麻煩,有興趣可看django進階-modelform&admin action
第二種方法更簡單
1. 在bootstrap添加自定義的css樣式文件,custom.css
2. 在基礎模版(我定義的是base.html,其它html模塊是繼承它的)導入custom.css文件:
1 | <link href = "/static/bootstrap-3.3.7-dist/css/custom.css" rel = "stylesheet" > |
3. 你隨意在custom.css定義樣式
View Code
4. 在對應的customer.html的標簽加入樣式; customer.status是后臺傳給前端的,是學生的報名狀態(tài)。
1 | < td class="{{ customer.status }}">{{ customer.get_status_display }}</ td > |
四、分頁功能
其實Alex銷售員登陸后看到的界面只有兩條客戶的信息,這是我在后臺寫的。注意看左下角有個分頁,類似與百度搜索的分頁。其實分頁實現(xiàn)起來還是有點難度的。
先看django官方文檔。官方文檔寫得很詳細!!
View Code
后臺實現(xiàn):
1 def customers(request): 2 print(">>>>request:",request) 3 # 查找所有客戶,獲取所有信息的結果集,但并不是所有信息都已經取出來了(如果有上萬條數據,不能一次性取出來,先取一部分), 4 customer_list = models.Customer.objects.all() 5 print(">>>>customers:", customer_list) 6 paginator = Paginator(customer_list, 2) # 生成分頁實例: 每一頁有兩條數據 7 page = request.GET.get("page") # 獲取前端點擊的頁數,參數page可自定義 8 try: 9 customer_objs = paginator.page(page) # 生成第page頁的對象10 except PageNotAnInteger:11 # If page is not an integer, deliver first page12 # 如果輸入的頁碼不是下標,則返回第一頁13 customer_objs = paginator.page(1)14 except EmptyPage:15 # If page is out of range (e.g. 9999), deliver last page of results.16 # 如果輸入的頁碼超出,則跳轉到最后的頁碼17 customer_objs = paginator.page(paginator.num_pages)18 19 return render(request, "crm/customer.html", {"customer_list": customer_objs})
前端實現(xiàn):
1 <div class="pagination"> 2 3 <nav> 4 <ul class="pagination"> 5 {% if customer_list.has_previous %} 6 <li class=""><a href="?page={{ customer_list.previous_page_number }}" aria-label="Previous"><span aria-hidden="true">«</span></a></li> 7 {% endif %} 8 9 {% for page_num in customer_list.paginator.page_range %}10 <!-- abs_page為函數名,后兩個為參數 -->11 {% abs_page customer_list.number page_num %}12 13 {% endfor %}14 15 {% if customer_list.has_next %}16 <li class=""><a href="?page={{ customer_list.next_page_number }}" aria-label="Next"><span aria-hidden="true">»</span></a></li>17 {% endif %}18 </ul>19 </nav>20 21 </div>
第一次進入http://127.0.0.1:8000/crm/customer/頁面時,請求為get方式,后臺接收到的page參數為空,故會出PagenotAnInterger異常,故會返回到第一頁!!
注意前端的第九行代碼: customer_list.paginator.page_range是頁數的范圍。customer_list只是一個第幾頁的實例而已,是無法獲取到頁數的范圍的。
但是問題來了,如果,你有100條數據,每頁只放兩條數據,意味著界面得有50個button,基本上頁面是放不下的。
如果頁面過多,看下百度怎么處理:
可用abs絕對值,若當前頁面為第6頁,想讓3、4、5和7、8、9也顯示出來,可在循環(huán)判斷頁面時,利用abs, 當|循環(huán)的頁面值-當前的頁面值|<=3 ,則顯示。
但問題又來了,前端的templates可沒有abs取絕對值這種后臺才有的方法,怎么辦??
自定義template tags
https://docs.djangoproject.com/es/1.9/howto/custom-template-tags/
效果圖:
后臺是如何自定義模版??
首先自定義templates模版,我隨便建了個文件custom_tags.py,必須放在新建包templatetags下:
custom_tags.py: 當頁碼絕對值之差小于3時,則返回頁碼按鈕的html給前端,反之不返回。
1 from django import template 2 from django.utils.html import format_html 3 4 register = template.Library() #django的語法庫 5 6 7 @register.simple_tag 8 def abs_page(current_page, loop_page): 9 offset = abs(current_page - loop_page)10 if offset < 3:11 if current_page == loop_page:12 page_ele = "<li class='active'><a href='?page=%s'>%s</a></li>" % (current_page, current_page)13 else:14 page_ele = "<li class=''><a href='?page=%s'>%s</a></li>" % (loop_page, loop_page)15 return format_html(page_ele) #將字符串轉化為html,返回給前端16 else:17 return ""
五、modelform進階
modelform之前有寫過,django進階-modelform&admin action, 但主要是寫django自帶的admin。
現(xiàn)在我有個需求,銷售員Alex想查看客戶的詳細信息。只需只擊客戶的ID號,便可查看,當然也可以修改。
前端:
1 | < td >< a href="/crm/customers/{{customer.id}}/">{{customer.id}}</ a ></ td > |
urls:
1 2 | # 當學員id當作參數,傳給customer_detail方法 url(r '^customers/(\d+)/$' , views.customer_detail), |
后臺:
1 2 3 4 | def customer_detail(request,customer_id): customer_obj = models.Customer.objects.get( id = customer_id) form = forms.CustomerModelForm() return render(request, "crm/customer_detail.html" ,{ "customer_form" :form}) |
看前端界面顯示: 雖然能顯示出表單,但無法顯示出學員的信息,而且太丑了!!
如何顯示出學員的信息:
1 2 | customer_obj = models.Customer.objects.get( id = customer_id) form = forms.CustomerModelForm(instance = customer_obj) # 將數據對象當作參數傳入 |
如何使前端界面更漂亮:
forms.py表單文件:
View Code
前端: 樣式是從bootstrap參考來的
View Code
效果圖:
修改后保存信息
View Code
六、必填與非必填字段
效果圖: 必填字段有加粗,且左上角有紅色*號
只需修改下前端代碼即可:
1 {% if field.field.required %} <!--若是必填字段 -->2 <label class="col-sm-2 control-label">3 <span style="color: red;font-size: larger">*</span>{{ field.label }}4 </label>5 {% else %} <!-- label在django默認為加粗 -->6 <label style="font-weight: normal" class="col-sm-2 control-label">{{ field.label }}</label>7 {% endif %}
權限分配, 這個改天再寫博客整理下: 三個角色的權限是不同的。對銷售員來講,無法修改非本人招收客戶的信息。
七、url別名
啥是url別名??
1 #當學員id當作參數,傳給customer_detail方法,2 #給該url起別名,一調用別名customer_detail,就關聯(lián)上url3 url(r'^customers/(\d+)/$',views.customer_detail,name="customer_detail"),
現(xiàn)在銷售員想查看客戶的詳細信息,只需一點擊客戶的ID號便可查看。so, ID號必須是個a標簽,下面來看看前端實現(xiàn):
1 <!-- 這里查看學員的詳細信息不應該寫列,否則當url一改變,得來這里改代碼 -->2 <!-- <td><a href = " /crm/customers/ {{customer.id}} / "> {{ customer.id }} </a></td> -->3 4 <td><a href = "{% url 'customer_detail' customer.id %}"> {{ customer.id }} </a></td>
注意了,如果不用url別名的話,就用第2行代碼。但是,這樣項目的可維護性大大降低了。當你需改動url時,必須到前端修改對應的a標簽。如果用了url別名,就不用再來前端修改了。
看到沒,我用瀏覽器審查元素,瀏覽器已經自動將ID號的a標簽,轉化為一條url. 神奇!!
1.非系統(tǒng)的學習也是在浪費時間 2.做一個會欣賞美,懂藝術,會藝術的技術人