首先,咱們必須明確,在這四種角色登陸網站,看到頁面是不一樣,這裏不只涉及到後端的權限控制,還涉及到前端頁面的佈局,區分好這些角色看的東西哪些是相同的,哪些又是不一樣的呢,這個必須在這裏想明白,因此要作好頁面佈局css
頁面佈局,去到bootstrap中文網,尋找適合本身的佈局實例,而後右擊保存頁面下載代碼,copy代碼到本身的項目,而後刪刪改改,固然徹底能夠本身用boottrap進行頁面佈局也是能夠的,主要看你是否要求對前端精深,時刻明確本身的目的,學會借力打力,這樣作纔有效率,不然事事親力親爲,尤爲是在技術更新迭代如此快的時代,不免會讓本身陷入一種不進則退的尷尬境地,把本身定位爲一個代碼整合者或者是技術整合者,也是一個不失水準的定位,因此咱們在這個項目中,直接copy實例代碼,封面以下:html
在目錄架構上,主要是模板渲染和靜態文件分類,至於靜態文件分類呢,以前圖片和css和js什麼的,就不用多說了,主要是plugins,放啥呢,放一些前端插件,另一個就是模板渲染了,爲了更好的管理前端代碼,確定是要用到母版繼承的,其中base.html主要放一些鏈接css文件和js文件的靜態數據,而其body部分由子版index.html繼承,而繼承index.html也只定義爲頁面公用功能部分(菜單)前端
<!DOCTYPE html> <html lang="zh-CN"><head> <meta http-equiv="content-type" content="text/html; charset=UTF-8"> <meta charset="utf-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta name="viewport" content="width=device-width, initial-scale=1"> <!-- 上述3個meta標籤*必須*放在最前面,任何其餘內容都*必須*跟隨其後! --> <meta name="description" content=""> <meta name="author" content=""> <!--<link rel="icon" href="https://v3.bootcss.com/favicon.ico">--> <title>Perfect CRM</title> <!-- Bootstrap core CSS --> <link href="/static/css/bootstrap.css" rel="stylesheet"> <!-- IE10 viewport hack for Surface/desktop Windows 8 bug --> <link href="/static/css/ie10-viewport-bug-workaround.css" rel="stylesheet"> <!-- Custom styles for this template --> <link href="/static/css/dashboard.css" rel="stylesheet"> <!-- Just for debugging purposes. Don't actually copy these 2 lines! --> <!--[if lt IE 9]><script src="/static/js/ie8-responsive-file-warning.js"></script><![endif]--> <script src="/static/js/ie-emulation-modes-warning.js"></script> </head> {% block body %} {% endblock %} <!-- Bootstrap core JavaScript ================================================== --> <!-- Placed at the end of the document so the pages load faster --> <script src="/static/js/jquery.js"></script> <script>window.jQuery || document.write('<script src="../../assets/js/vendor/jquery.min.js"><\/script>')</script> <script src="/static/js/bootstrap.js"></script> <!-- Just to make our placeholder images work. Don't actually copy the next line! --> <script src="/static/js/holder.js"></script> <!-- IE10 viewport hack for Surface/desktop Windows 8 bug --> <script src="/static/js/ie10-viewport-bug-workaround.js"></script> </html>
{% extends 'base.html '%} {% block body %} <body> <nav class="navbar navbar-inverse navbar-fixed-top"> <div class="container-fluid"> <div class="navbar-header"> <button type="button" class="navbar-toggle collapsed" data-toggle="collapse" data-target="#navbar" aria-expanded="false" aria-controls="navbar"> <span class="sr-only">Toggle navigation</span> <span class="icon-bar"></span> <span class="icon-bar"></span> <span class="icon-bar"></span> </button> <a class="navbar-brand" href="#">Project name</a> </div> <div id="navbar" class="navbar-collapse collapse"> <ul class="nav navbar-nav navbar-right"> <li><a href="#">Dashboard</a></li> <li><a href="#">Settings</a></li> <li><a href="#">Profile</a></li> <li><a href="#">Help</a></li> </ul> <form class="navbar-form navbar-right"> <input class="form-control" placeholder="Search..." type="text"> </form> </div> </div> </nav> <div class="container-fluid"> <div class="row"> <div class="col-sm-3 col-md-2 sidebar"> <ul class="nav nav-sidebar"> <li class="active"><a href="#">Overview <span class="sr-only">(current)</span></a></li> <li><a href="#">Reports</a></li> <li><a href="#">Analytics</a></li> <li><a href="#">Export</a></li> </ul> <ul class="nav nav-sidebar"> <li><a href="">Nav item</a></li> <li><a href="">Nav item again</a></li> <li><a href="">One more nav</a></li> <li><a href="">Another nav item</a></li> <li><a href="">More navigation</a></li> </ul> <ul class="nav nav-sidebar"> <li><a href="">Nav item again</a></li> <li><a href="">One more nav</a></li> <li><a href="">Another nav item</a></li> </ul> </div> <div class="col-sm-9 col-sm-offset-3 col-md-10 col-md-offset-2 main"> <h1 class="page-header">Dashboard</h1> <div class="row placeholders"> <div class="col-xs-6 col-sm-3 placeholder"> <img src="data:image/gif;base64,R0lGODlhAQABAIAAAHd3dwAAACH5BAAAAAAALAAAAAABAAEAAAICRAEAOw==" class="img-responsive" alt="Generic placeholder thumbnail" width="200" height="200"> <h4>Label</h4> <span class="text-muted">Something else</span> </div> <div class="col-xs-6 col-sm-3 placeholder"> <img src="data:image/gif;base64,R0lGODlhAQABAIAAAHd3dwAAACH5BAAAAAAALAAAAAABAAEAAAICRAEAOw==" class="img-responsive" alt="Generic placeholder thumbnail" width="200" height="200"> <h4>Label</h4> <span class="text-muted">Something else</span> </div> <div class="col-xs-6 col-sm-3 placeholder"> <img src="data:image/gif;base64,R0lGODlhAQABAIAAAHd3dwAAACH5BAAAAAAALAAAAAABAAEAAAICRAEAOw==" class="img-responsive" alt="Generic placeholder thumbnail" width="200" height="200"> <h4>Label</h4> <span class="text-muted">Something else</span> </div> <div class="col-xs-6 col-sm-3 placeholder"> <img src="data:image/gif;base64,R0lGODlhAQABAIAAAHd3dwAAACH5BAAAAAAALAAAAAABAAEAAAICRAEAOw==" class="img-responsive" alt="Generic placeholder thumbnail" width="200" height="200"> <h4>Label</h4> <span class="text-muted">Something else</span> </div> </div> <h2 class="sub-header">Section title</h2> <div class="table-responsive"> <table class="table table-striped"> <thead> <tr> <th>#</th> <th>Header</th> <th>Header</th> <th>Header</th> <th>Header</th> </tr> </thead> <tbody> <tr> <td>1,001</td> <td>Lorem</td> <td>ipsum</td> <td>dolor</td> <td>sit</td> </tr> <tr> <td>1,002</td> <td>amet</td> <td>consectetur</td> <td>adipiscing</td> <td>elit</td> </tr> <tr> <td>1,003</td> <td>Integer</td> <td>nec</td> <td>odio</td> <td>Praesent</td> </tr> <tr> <td>1,003</td> <td>libero</td> <td>Sed</td> <td>cursus</td> <td>ante</td> </tr> <tr> <td>1,004</td> <td>dapibus</td> <td>diam</td> <td>Sed</td> <td>nisi</td> </tr> <tr> <td>1,005</td> <td>Nulla</td> <td>quis</td> <td>sem</td> <td>at</td> </tr> <tr> <td>1,006</td> <td>nibh</td> <td>elementum</td> <td>imperdiet</td> <td>Duis</td> </tr> <tr> <td>1,007</td> <td>sagittis</td> <td>ipsum</td> <td>Praesent</td> <td>mauris</td> </tr> <tr> <td>1,008</td> <td>Fusce</td> <td>nec</td> <td>tellus</td> <td>sed</td> </tr> <tr> <td>1,009</td> <td>augue</td> <td>semper</td> <td>porta</td> <td>Mauris</td> </tr> <tr> <td>1,010</td> <td>massa</td> <td>Vestibulum</td> <td>lacinia</td> <td>arcu</td> </tr> <tr> <td>1,011</td> <td>eget</td> <td>nulla</td> <td>Class</td> <td>aptent</td> </tr> <tr> <td>1,012</td> <td>taciti</td> <td>sociosqu</td> <td>ad</td> <td>litora</td> </tr> <tr> <td>1,013</td> <td>torquent</td> <td>per</td> <td>conubia</td> <td>nostra</td> </tr> <tr> <td>1,014</td> <td>per</td> <td>inceptos</td> <td>himenaeos</td> <td>Curabitur</td> </tr> <tr> <td>1,015</td> <td>sodales</td> <td>ligula</td> <td>in</td> <td>libero</td> </tr> </tbody> </table> </div> </div> </div> </div> </body> {% endblock %}
from django.conf.urls import url,include from django.contrib import admin urlpatterns = [ url(r'^admin/', admin.site.urls), url(r'^crm/', include('app01.urls')), # url(r'^test/', views.test), ]
要想實現不一樣角色用戶看到菜單項是不同的,那這裏就要實現動態菜單了,那你怎麼讓它動起來呢,要想知道這個問題的答案,你就必須想清楚這個問題:依據什麼動?角色?這個沒錯,可是你要想登陸網站的是角色嗎?不是吧,是用戶,對,就是用戶,用戶再綁定某些角色,因此這裏咱們要依據用戶來動,那怎麼動呢?首先,咱們要獲取用戶相關信息,而後返回前端,這裏就涉及到模板渲染仍是js加載,首次頁面加載,而且仍是頁面公共部分,固然首選模板渲染了,另外每一個角色加載哪些菜單項,也須要在某個地方進行定義,就在內存了,仍是在數據庫了?考慮易擴展性以及角色和菜單項之間是多對多的關係,在這裏咱們就數據庫存儲菜單關係,因此咱們還要增長一張菜單表python
class Role(models.Model): '''角色表''' name = models.CharField(max_length=32, unique=True) menus = models.ManyToManyField('Menu',blank=True) def __unicode__(self): return self.name class Meta: verbose_name_plural = "角色表" class Menu(models.Model): '''菜單''' name = models.CharField(max_length=32) url_name = models.CharField(max_length=64) #request url 有別名存別名 沒有就存url def __unicode__(self): return self.name class Meta: verbose_name_plural = '菜單表'
動態路由設計好,那接下來就是把它顯示到前端了,你會怎麼作了?固然是經過後端ORM查詢到用戶能夠有的菜單項,傳到前端,而後經過模板語言for循環渲染就能夠了。嗯!這樣作沒錯,你忽略一些小細節,這裏還能夠更簡潔一點--直接在前端查詢數據並for循環!你可能有些懵逼了,咱們來看是怎麼回事?還記得定義用戶表時,咱們的user字段是直接一對一關聯到django自帶認證系統的一張表嗎?jquery
class UserProfile(models.Model): '''帳號表''' user = models.OneToOneField(User) name = models.CharField(max_length=32) roles = models.ManyToManyField('Role', blank=True, null=True) def __unicode__(self): return self.name class Meta: verbose_name_plural = "帳號表"
django是把request直接嵌在了模板裏,而request.user指的就是django自帶的這張表,就直接在前端調用{{ request.user }},則顯示用戶名;既然能在前端調用django自帶表,那咱們就能夠用這張表查詢全部的有關用戶的信息了,由它查userprofile表是反向查詢,一對一反向查詢是 表.反向表名(小寫).字段,也就是request.user.userprofile.roles,你看就是這麼簡單ios
{% for role in request.user.userprofile.roles.all %} {% for menu in role.menus.all %} <li class="active"><a href="{% url menu.url_name %}">{{ menu.name }}<span class="sr-only">(current)</span></a></li> {% endfor %} {% endfor %}
{% extends 'base.html '%} {% block body %} <body> <nav class="navbar navbar-inverse navbar-fixed-top"> <div class="container-fluid"> <div class="navbar-header"> <button type="button" class="navbar-toggle collapsed" data-toggle="collapse" data-target="#navbar" aria-expanded="false" aria-controls="navbar"> <span class="sr-only">Toggle navigation</span> <span class="icon-bar"></span> <span class="icon-bar"></span> <span class="icon-bar"></span> </button> <a class="navbar-brand" href="#">Perfect CRM</a> </div> <!--顯示登陸用戶欄--> <div id="navbar" class="navbar-collapse collapse"> <ul class="nav navbar-nav navbar-right"> <!--留一個顯示用戶名--> <li><a href="#">{{ request.user }}</a></li> </ul> </div> </div> </nav> <div class="container-fluid"> <div class="row"> <!--左側欄--> <div class="col-sm-3 col-md-2 sidebar"> <ul class="nav nav-sidebar"> {% for role in request.user.userprofile.roles.all %} {% for menu in role.menus.all %} <li class="active"><a href="{% url menu.url_name %}">{{ menu.name }}<span class="sr-only">(current)</span></a></li> {% endfor %} {% endfor %} </ul> </div> <!--接下來是內容區--> <div class="col-sm-9 col-sm-offset-3 col-md-10 col-md-offset-2 main"> <!--內容圓餅圖區--> {% block page-content %} <h1 class="page-header">Dashboard</h1> <div class="row placeholders"> <div class="col-xs-6 col-sm-3 placeholder"> <img src="data:image/gif;base64,R0lGODlhAQABAIAAAHd3dwAAACH5BAAAAAAALAAAAAABAAEAAAICRAEAOw==" class="img-responsive" alt="Generic placeholder thumbnail" width="200" height="200"> <h4>Label</h4> <span class="text-muted">Something else</span> </div> <div class="col-xs-6 col-sm-3 placeholder"> <img src="data:image/gif;base64,R0lGODlhAQABAIAAAHd3dwAAACH5BAAAAAAALAAAAAABAAEAAAICRAEAOw==" class="img-responsive" alt="Generic placeholder thumbnail" width="200" height="200"> <h4>Label</h4> <span class="text-muted">Something else</span> </div> <div class="col-xs-6 col-sm-3 placeholder"> <img src="data:image/gif;base64,R0lGODlhAQABAIAAAHd3dwAAACH5BAAAAAAALAAAAAABAAEAAAICRAEAOw==" class="img-responsive" alt="Generic placeholder thumbnail" width="200" height="200"> <h4>Label</h4> <span class="text-muted">Something else</span> </div> <div class="col-xs-6 col-sm-3 placeholder"> <img src="data:image/gif;base64,R0lGODlhAQABAIAAAHd3dwAAACH5BAAAAAAALAAAAAABAAEAAAICRAEAOw==" class="img-responsive" alt="Generic placeholder thumbnail" width="200" height="200"> <h4>Label</h4> <span class="text-muted">Something else</span> </div> </div> <!--內容詳細數據--> <h2 class="sub-header">Section title</h2> <div class="table-responsive"> <table class="table table-striped"> <thead> <tr> <th>#</th> <th>Header</th> <th>Header</th> <th>Header</th> <th>Header</th> </tr> </thead> <tbody> <tr> <td>1,001</td> <td>Lorem</td> <td>ipsum</td> <td>dolor</td> <td>sit</td> </tr> <tr> <td>1,002</td> <td>amet</td> <td>consectetur</td> <td>adipiscing</td> <td>elit</td> </tr> <tr> <td>1,003</td> <td>Integer</td> <td>nec</td> <td>odio</td> <td>Praesent</td> </tr> <tr> <td>1,003</td> <td>libero</td> <td>Sed</td> <td>cursus</td> <td>ante</td> </tr> <tr> <td>1,004</td> <td>dapibus</td> <td>diam</td> <td>Sed</td> <td>nisi</td> </tr> <tr> <td>1,005</td> <td>Nulla</td> <td>quis</td> <td>sem</td> <td>at</td> </tr> <tr> <td>1,006</td> <td>nibh</td> <td>elementum</td> <td>imperdiet</td> <td>Duis</td> </tr> <tr> <td>1,007</td> <td>sagittis</td> <td>ipsum</td> <td>Praesent</td> <td>mauris</td> </tr> <tr> <td>1,008</td> <td>Fusce</td> <td>nec</td> <td>tellus</td> <td>sed</td> </tr> <tr> <td>1,009</td> <td>augue</td> <td>semper</td> <td>porta</td> <td>Mauris</td> </tr> <tr> <td>1,010</td> <td>massa</td> <td>Vestibulum</td> <td>lacinia</td> <td>arcu</td> </tr> <tr> <td>1,011</td> <td>eget</td> <td>nulla</td> <td>Class</td> <td>aptent</td> </tr> <tr> <td>1,012</td> <td>taciti</td> <td>sociosqu</td> <td>ad</td> <td>litora</td> </tr> <tr> <td>1,013</td> <td>torquent</td> <td>per</td> <td>conubia</td> <td>nostra</td> </tr> <tr> <td>1,014</td> <td>per</td> <td>inceptos</td> <td>himenaeos</td> <td>Curabitur</td> </tr> <tr> <td>1,015</td> <td>sodales</td> <td>ligula</td> <td>in</td> <td>libero</td> </tr> </tbody> </table> </div> {% endblock %} </div> </div> </div> </body> {% endblock %}
涉及知識點git