CRM系统-----学员管理系统

1.需求分析

2.使用组件

django2.0+bootstrap3.37+jquery1.12+mysql8.0

django2.1:https://www.djangoproject.com/

3.表结构设计

 

models.py

  1 from django.db import models
  2 from django.contrib.auth.models import User
  3 from django.contrib.auth.models import (
  4     BaseUserManager, AbstractBaseUser,PermissionsMixin
  5 )
  6 from django.utils.translation import gettext_lazy as _
  7 from django.utils.safestring import mark_safe
  8 
  9 # Create your models here.
 10 
 11 
 12 class Customer(models.Model):
 13     """客户信息表"""
 14     name = models.CharField(max_length=32,blank=True,null=True,help_text="用户注册后更改")
 15     qq = models.CharField(max_length=64,unique=True)
 16     qq_name = models.CharField(max_length=64,blank=True,null=True)
 17     phone = models.CharField(max_length=64,blank=True,null=True)
 18     id_num = models.CharField(max_length=64,blank=True,null=True)
 19     email = models.EmailField(verbose_name="常用邮箱",blank=True,null=True)
 20     source_choices = ((0,"转介绍"),
 21                       (1,"QQ群"),
 22                       (2,"官网"),
 23                       (3,"百度推广"),
 24                       (4,"51CTO"),
 25                       (5,"知乎"),
 26                       (6,"市场推广")
 27                       )
 28     source = models.SmallIntegerField(choices=source_choices)
 29     referral_form = models.CharField(max_length=64,verbose_name="转介绍人QQ",blank=True,null=True)
 30 
 31     consult_course = models.ForeignKey("Course",verbose_name="咨询课程",on_delete=models.CASCADE)
 32     content = models.TextField(verbose_name="咨询详情")
 33     tags = models.ManyToManyField("Tag",blank=True)
 34     status_choices = ((0,'已报名'),(1,'未报名'),)
 35     status = models.SmallIntegerField(choices=status_choices,default=1)
 36     consultant = models.ForeignKey("UserProfile",on_delete=models.CASCADE)
 37     memo = models.TextField(blank=True,null=True)
 38     date = models.DateTimeField(auto_now_add=True)
 39 
 40     def __str__(self):
 41         return self.qq
 42 
 43     class Meta:
 44         verbose_name = "客户信息表"
 45         verbose_name_plural = "客户信息表"
 46 
 47 class Tag(models.Model):
 48     """标签表"""
 49     name = models.CharField(unique=True,max_length=32)
 50 
 51     def __str__(self):
 52         return self.name
 53 
 54     class Meta:
 55         verbose_name = "标签表"
 56         verbose_name_plural = "标签表"
 57 
 58 class CustomerFollowUp(models.Model):
 59     """客户跟踪表"""
 60     customer = models.ForeignKey("Customer",on_delete=models.CASCADE)
 61     content = models.TextField(verbose_name="跟进内容")
 62     consultant = models.ForeignKey("UserProfile",on_delete=models.CASCADE)
 63     intention_choices = ((0,"2周内报名"),
 64                          (1,"1个月内报名"),
 65                          (2,"近期无报名计划"),
 66                          (3,"已在其他机构报名"),
 67                          (4,"已报名"),
 68                          (5,"已拉黑"),
 69                          )
 70     intention = models.SmallIntegerField(choices=intention_choices)
 71     date = models.DateTimeField(auto_now_add=True)
 72 
 73     def __str__(self):
 74         return "<%s:%s>"%(self.customer.qq,self.intention)
 75 
 76     class Meta:
 77         verbose_name = "客户跟踪表"
 78         verbose_name_plural = "客户跟踪表"
 79 
 80 class Course(models.Model):
 81     """课程表"""
 82     name = models.CharField(max_length=64,unique=True)
 83     price = models.PositiveSmallIntegerField()
 84     period = models.PositiveSmallIntegerField(verbose_name="周期(月)")
 85     outline = models.TextField()
 86 
 87     def __str__(self):
 88         return self.name
 89     class Meta:
 90         verbose_name = "课程表"
 91         verbose_name_plural ="课程表"
 92 
 93 class Branch(models.Model):
 94     """校区表"""
 95     name = models.CharField(max_length=128,unique=True)
 96     addr = models.CharField(max_length=128)
 97     def __str__(self):
 98         return self.name
 99     class Meta:
100         verbose_name = "校区表"
101         verbose_name_plural ="校区表"
102 
103 class ClassList(models.Model):
104     """班级表"""
105     branch = models.ForeignKey("Branch",on_delete=models.CASCADE)
106     course = models.ForeignKey("Course",on_delete=models.CASCADE)
107     class_type_choices = ((0,"面授(脱产)"),
108                           (1, "面授(周末)"),
109                           (2, "网络班"))
110     contract = models.ForeignKey("ContractTemplate",on_delete=models.CASCADE,blank=True,null=True)
111     class_type = models.SmallIntegerField(choices=class_type_choices,verbose_name="班级类型")
112     semester = models.PositiveSmallIntegerField(verbose_name="学期")
113     teachers = models.ManyToManyField("UserProfile")
114     start_date = models.DateField(verbose_name="开班日期")
115     end_date = models.DateField(verbose_name="结业日期",blank=True,null=True)
116 
117     def __str__(self):
118         return "%s %s %s" %(self.branch,self.course,self.semester)
119 
120     class Meta:
121         unique_together = ("branch","course","semester")
122         verbose_name = "班级表"
123         verbose_name_plural = "班级表"
124 
125 class CourseRecord(models.Model):
126     """上课记录表"""
127     from_class = models.ForeignKey("ClassList",verbose_name="班级",on_delete=models.CASCADE)
128     day_num = models.PositiveSmallIntegerField(verbose_name="第几节(天)")
129     teacher = models.ForeignKey("UserProfile",on_delete=models.CASCADE)
130     has_homework = models.BooleanField(default=True)
131     homework_title = models.CharField(max_length=128,blank=True,null=True)
132     homework_content = models.TextField(blank=True,null=True)
133     out_line = models.TextField(verbose_name="本节课大纲")
134     date =models.DateField(auto_now_add=True)
135 
136     def __str__(self):
137         return "%s %s" %(self.from_class,self.day_num)
138     class Meta:
139         unique_together = ("from_class","day_num")
140         verbose_name = "上课记录表"
141         verbose_name_plural = "上课记录表"
142 
143 class StudyRecord(models.Model):
144     """学习记录"""
145     student = models.ForeignKey("Enrollment",on_delete=models.CASCADE)
146     course_record = models.ForeignKey("CourseRecord",on_delete=models.CASCADE)
147     attendance_choices = ((0,"已签到"),
148                           (1,"迟到"),
149                           (2,"缺勤"),
150                           (3,"早退"),
151                           )
152     attendance = models.SmallIntegerField(choices=attendance_choices,default=0)
153     score_choices = ((100,"A+"),
154                      (90,"A"),
155                      (85,"B+"),
156                      (80,"B"),
157                      (75,"B-"),
158                      (70,"C+"),
159                      (60,"C"),
160                      (40,"C-"),
161                      (-50,"D"),
162                      (-100,"copy"),
163                      (0,"N/A"),
164                      )
165     score = models.SmallIntegerField(choices=score_choices,default=0)
166     memo = models.TextField(blank=True,null=True)
167     date = models.DateField(auto_now_add=True)
168 
169     def __str__(self):
170         return "%s %s %s" %(self.student,self.course_record,self.score)
171     class Meta:
172         unique_together = ("student","course_record")
173         verbose_name = "学习记录"
174         verbose_name_plural = "学习记录"
175 
176 class Enrollment(models.Model):
177     """报名表"""
178     customer = models.ForeignKey("Customer",on_delete=models.CASCADE)
179     enrolled_class =models.ForeignKey("ClassList",verbose_name="所报班级",on_delete=models.CASCADE)
180     consultant = models.ForeignKey("UserProfile",verbose_name="课程顾问",on_delete=models.CASCADE)
181     contract_agreed = models.BooleanField(default=False,verbose_name="学员已同意合同条款")
182     contract_approved = models.BooleanField(default=False,verbose_name="合同已审核")
183     date =models.DateTimeField(auto_now_add=True)
184 
185     def __str__(self):
186         return "%s %s"%(self.customer,self.enrolled_class)
187     class Meta:
188         unique_together = ("customer","enrolled_class")
189         verbose_name = "报名表"
190         verbose_name_plural = "报名表"
191 
192 class Payment(models.Model):
193     """缴费记录"""
194     customer = models.ForeignKey("Customer",on_delete=models.CASCADE)
195     course = models.ForeignKey("Course",verbose_name="所报课程",on_delete=models.CASCADE)
196     amount = models.PositiveIntegerField(verbose_name="数额",default=500)
197     consultant = models.ForeignKey("UserProfile",on_delete=models.CASCADE)
198     date = models.DateTimeField(auto_now_add=True)
199     def __str__(self):
200         return "%s %s"%(self.customer,self.amount)
201     class Meta:
202         verbose_name = "缴费记录"
203         verbose_name_plural = "缴费记录"
204 
205 # class UserProfile(models.Model):
206 #     """账号表"""
207 #     user = models.OneToOneField(User,on_delete=models.CASCADE)
208 #     name = models.CharField(max_length=32)
209 #     roles = models.ManyToManyField("Role",blank=True)
210 #
211 #     def __str__(self):
212 #         return self.name
213 #     class Meta:
214 #         verbose_name = "账号表"
215 #         verbose_name_plural = "账号表"
216 
217 
218 class UserProfileManager(BaseUserManager):
219     def create_user(self, email, name, password=None):
220         """
221         Creates and saves a User with the given email, date of
222         birth and password.
223         """
224         if not email:
225             raise ValueError('Users must have an email address')
226 
227         user = self.model(
228             email=self.normalize_email(email),
229             name=name,
230         )
231 
232         user.set_password(password)
233         self.is_active = True
234         user.save(using=self._db)
235         return user
236 
237     def create_superuser(self, email, name, password):
238         """
239         Creates and saves a superuser with the given email, date of
240         birth and password.
241         """
242         user = self.create_user(
243             email,
244             password=password,
245             name=name,
246         )
247         user.is_admin = True
248         user.save(using=self._db)
249         return user
250 
251 
252 class UserProfile(AbstractBaseUser,PermissionsMixin):
253     email = models.EmailField(
254         verbose_name='email address',
255         max_length=255,
256         unique=True,
257     )
258     name =models.CharField(max_length=32)
259     password = models.CharField(_('password'), max_length=128,help_text=mark_safe("""<a href='password/'>修改密码</a>"""))
260     is_active = models.BooleanField(default=True)
261     is_admin = models.BooleanField(default=False)
262     roles = models.ManyToManyField("Role",blank=True)
263     objects = UserProfileManager()
264     stu_amount = models.ForeignKey("Customer",on_delete=models.CASCADE,verbose_name="关联客户信息",blank=True,null=True)
265 
266     USERNAME_FIELD = 'email'
267     REQUIRED_FIELDS = ['name']
268 
269     def __str__(self):
270         return self.email
271 
272     # def has_perm(self, perm, obj=None):
273     #     "Does the user have a specific permission?"
274     #     # Simplest possible answer: Yes, always
275     #     return True
276     #
277     # def has_module_perms(self, app_label):
278     #     "Does the user have permissions to view the app `app_label`?"
279     #     # Simplest possible answer: Yes, always
280     #     return True
281 
282     @property
283     def is_staff(self):
284         "Is the user a member of staff?"
285         # Simplest possible answer: All admins are staff
286         return self.is_active
287 
288 
289     class Meta:
290         permissions = (
291             ("can_access_my_course","可以访问我的课程"),
292             ("can_access_studyrecord","可以访问我的学习记录"),
293             ("can_access_homework_detail","可以访问上交作业"),
294         )
295 
296 class Role(models.Model):
297     """角色表"""
298     name = models.CharField(max_length=64,unique=True)
299     menus = models.ManyToManyField("Menu",blank=True)
300     def __str__(self):
301         return self.name
302     class Meta:
303         verbose_name = "角色表"
304         verbose_name_plural = "角色表"
305 
306 class Menu(models.Model):
307     """菜单表"""
308     name = models.CharField(max_length=32)
309     url_type_choice = ((0,"alias"),(1,"absolute_url"))
310     url_type = models.SmallIntegerField(choices=url_type_choice,default=0)
311     url_name = models.CharField(max_length=64)
312 
313     def __str__(self):
314         return self.name
315 
316     class Meta:
317         verbose_name = "菜单表"
318         verbose_name_plural = "菜单表"
319 
320 class ContractTemplate(models.Model):
321     """合同模板"""
322     name = models.CharField(verbose_name="合同名称",max_length=64,unique=True)
323     template = models.TextField()
324 
325     def __str__(self):
326         return self.name
models

 

 备注:

1.使用mysql数据库在setting.py中的设置

DATABASES = {
    'default': {
        'ENGINE': 'django.db.backends.mysql',
        'NAME': 'PerfectCRM',
        'USER': 'root',
        'PASSWORD': "12345",
        'HOST': '127.0.0.1',
        'PORT': '3306',
    }
}

2.Django默认使用MySQLdb模块链接MySQL,主动修改为pymysql,在project同名文件夹下的__init__文件中添加如下代码

import pymysql
pymysql.install_as_MySQLdb()

 

4.django admin的登录

首先设置admin的账号和密码

python manage.py createsuperuser

 在admin.py中添加一下代码:

 1 from django.contrib import admin
 2 from crm import models
 3 # Register your models here.
 4 
 5 admin.site.register(models.Customer)
 6 admin.site.register(models.CustomerFollowUp)
 7 admin.site.register(models.Enrollment)
 8 admin.site.register(models.Course)
 9 admin.site.register(models.ClassList)
10 admin.site.register(models.CourseRecord)
11 admin.site.register(models.Branch)
12 admin.site.register(models.Payment)
13 admin.site.register(models.StudyRecord)
14 admin.site.register(models.Tag)
15 admin.site.register(models.Role)
16 admin.site.register(models.UserProfile)
View Code

 最后效果:

 5.django中使用bootstrap

登录bootstrap的网站下载一个模板(网页+css+js)

创建static目录下面创建css、js、img、fonts、plugins文件存放下载下来的文件

在templates中创建html文件,复制模板文件

修改模板文件中的css和js的路径,就OK了

注意:设置urls和views

后续在修改html模板来制作自己需求的html。

 我的模板

js+css

 1 <!DOCTYPE html>
 2 <!-- saved from url=(0042)https://v3.bootcss.com/examples/dashboard/ -->
 3 <html lang="zh-CN">
 4   <head>
 5     <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
 6 
 7     <meta http-equiv="X-UA-Compatible" content="IE=edge">
 8     <meta name="viewport" content="width=device-width, initial-scale=1">
 9     <!-- 上述3个meta标签*必须*放在最前面,任何其他内容都*必须*跟随其后! -->
10     <meta name="description" content="">
11     <meta name="author" content="">
12     <!--link rel="icon" href="https://v3.bootcss.com/favicon.ico"-->
13 
14     <title>PerfectCRM</title>
15 
16     <!-- Bootstrap core CSS -->
17     <link href="/static/css/bootstrap_3.3.7_css_bootstrap.min.css" rel="stylesheet">
18 
19     <!-- IE10 viewport hack for Surface/desktop Windows 8 bug -->
20     <link href="/static/css/ie10-viewport-bug-workaround.css" rel="stylesheet">
21 
22     <!-- Custom styles for this template -->
23     <link href="/static/css/dashboard.css" rel="stylesheet">
24 
25     <!-- Just for debugging purposes. Don't actually copy these 2 lines! -->
26     <!--[if lt IE 9]><script src="../../assets/js/ie8-responsive-file-warning.js"></script><![endif]-->
27     <script src="/static/js/ie-emulation-modes-warning.js"></script>
28 
29 
30   </head>
31 
32 {% block body %}
33 
34 {% endblock %}
35 
36     <!-- Bootstrap core JavaScript
37     ================================================== -->
38     <!-- Placed at the end of the document so the pages load faster -->
39     <script src="/static/js/jquery_1.12.4_jquery.min.js"></script>
40     <script>window.jQuery || document.write('<script src="../../assets/js/vendor/jquery.min.js"><\/script>')</script>
41     <script src="/static/js/bootstrap_3.3.7_js_bootstrap.min.js"></script>
42     <!-- Just to make our placeholder images work. Don't actually copy the next line! -->
43     <script src="/static/js/holder.min.js"></script>
44     <!-- IE10 viewport hack for Surface/desktop Windows 8 bug -->
45     <script src="/static/js/ie10-viewport-bug-workaround.js"></script>
46 
47 
48 
49 </html>
base.html
  1 {% extends "base.html" %}
  2 {% block body %}
  3 <body>
  4 
  5     <nav class="navbar navbar-inverse navbar-fixed-top">
  6       <div class="container-fluid">
  7         <div class="navbar-header">
  8           <button type="button" class="navbar-toggle collapsed" data-toggle="collapse" data-target="#navbar" aria-expanded="false" aria-controls="navbar">
  9             <span class="sr-only">Toggle navigation</span>
 10             <span class="icon-bar"></span>
 11             <span class="icon-bar"></span>
 12             <span class="icon-bar"></span>
 13           </button>
 14           <a class="navbar-brand" href="https://v3.bootcss.com/examples/dashboard/#">Project name</a>
 15         </div>
 16         <div id="navbar" class="navbar-collapse collapse">
 17           <ul class="nav navbar-nav navbar-right">
 18             <li><a href="https://v3.bootcss.com/examples/dashboard/#">Dashboard</a></li>
 19             <li><a href="https://v3.bootcss.com/examples/dashboard/#">Settings</a></li>
 20             <li><a href="https://v3.bootcss.com/examples/dashboard/#">Profile</a></li>
 21             <li><a href="https://v3.bootcss.com/examples/dashboard/#">Help</a></li>
 22           </ul>
 23           <form class="navbar-form navbar-right">
 24             <input type="text" class="form-control" placeholder="Search...">
 25           </form>
 26         </div>
 27       </div>
 28     </nav>
 29 
 30     <div class="container-fluid">
 31       <div class="row">
 32         <div class="col-sm-3 col-md-2 sidebar">
 33           <ul class="nav nav-sidebar">
 34             <li class="active"><a href="https://v3.bootcss.com/examples/dashboard/#">Overview <span class="sr-only">(current)</span></a></li>
 35             <li><a href="https://v3.bootcss.com/examples/dashboard/#">Reports</a></li>
 36             <li><a href="https://v3.bootcss.com/examples/dashboard/#">Analytics</a></li>
 37             <li><a href="https://v3.bootcss.com/examples/dashboard/#">Export</a></li>
 38           </ul>
 39           <ul class="nav nav-sidebar">
 40             <li><a href="https://v3.bootcss.com/examples/dashboard/">Nav item</a></li>
 41             <li><a href="https://v3.bootcss.com/examples/dashboard/">Nav item again</a></li>
 42             <li><a href="https://v3.bootcss.com/examples/dashboard/">One more nav</a></li>
 43             <li><a href="https://v3.bootcss.com/examples/dashboard/">Another nav item</a></li>
 44             <li><a href="https://v3.bootcss.com/examples/dashboard/">More navigation</a></li>
 45           </ul>
 46           <ul class="nav nav-sidebar">
 47             <li><a href="https://v3.bootcss.com/examples/dashboard/">Nav item again</a></li>
 48             <li><a href="https://v3.bootcss.com/examples/dashboard/">One more nav</a></li>
 49             <li><a href="https://v3.bootcss.com/examples/dashboard/">Another nav item</a></li>
 50           </ul>
 51         </div>
 52         <div class="col-sm-9 col-sm-offset-3 col-md-10 col-md-offset-2 main">
 53           <h1 class="page-header">Dashboard</h1>
 54 
 55           <div class="row placeholders">
 56             <div class="col-xs-6 col-sm-3 placeholder">
 57               <img src="data:image/gif;base64,R0lGODlhAQABAIAAAHd3dwAAACH5BAAAAAAALAAAAAABAAEAAAICRAEAOw==" width="200" height="200" class="img-responsive" alt="Generic placeholder thumbnail">
 58               <h4>Label</h4>
 59               <span class="text-muted">Something else</span>
 60             </div>
 61             <div class="col-xs-6 col-sm-3 placeholder">
 62               <img src="data:image/gif;base64,R0lGODlhAQABAIAAAHd3dwAAACH5BAAAAAAALAAAAAABAAEAAAICRAEAOw==" width="200" height="200" class="img-responsive" alt="Generic placeholder thumbnail">
 63               <h4>Label</h4>
 64               <span class="text-muted">Something else</span>
 65             </div>
 66             <div class="col-xs-6 col-sm-3 placeholder">
 67               <img src="data:image/gif;base64,R0lGODlhAQABAIAAAHd3dwAAACH5BAAAAAAALAAAAAABAAEAAAICRAEAOw==" width="200" height="200" class="img-responsive" alt="Generic placeholder thumbnail">
 68               <h4>Label</h4>
 69               <span class="text-muted">Something else</span>
 70             </div>
 71             <div class="col-xs-6 col-sm-3 placeholder">
 72               <img src="data:image/gif;base64,R0lGODlhAQABAIAAAHd3dwAAACH5BAAAAAAALAAAAAABAAEAAAICRAEAOw==" width="200" height="200" class="img-responsive" alt="Generic placeholder thumbnail">
 73               <h4>Label</h4>
 74               <span class="text-muted">Something else</span>
 75             </div>
 76           </div>
 77 
 78           <h2 class="sub-header">Section title</h2>
 79           <div class="table-responsive">
 80             <table class="table table-striped">
 81               <thead>
 82                 <tr>
 83                   <th>#</th>
 84                   <th>Header</th>
 85                   <th>Header</th>
 86                   <th>Header</th>
 87                   <th>Header</th>
 88                 </tr>
 89               </thead>
 90               <tbody>
 91                 <tr>
 92                   <td>1,001</td>
 93                   <td>Lorem</td>
 94                   <td>ipsum</td>
 95                   <td>dolor</td>
 96                   <td>sit</td>
 97                 </tr>
 98                 <tr>
 99                   <td>1,002</td>
100                   <td>amet</td>
101                   <td>consectetur</td>
102                   <td>adipiscing</td>
103                   <td>elit</td>
104                 </tr>
105                 <tr>
106                   <td>1,003</td>
107                   <td>Integer</td>
108                   <td>nec</td>
109                   <td>odio</td>
110                   <td>Praesent</td>
111                 </tr>
112                 <tr>
113                   <td>1,003</td>
114                   <td>libero</td>
115                   <td>Sed</td>
116                   <td>cursus</td>
117                   <td>ante</td>
118                 </tr>
119                 <tr>
120                   <td>1,004</td>
121                   <td>dapibus</td>
122                   <td>diam</td>
123                   <td>Sed</td>
124                   <td>nisi</td>
125                 </tr>
126                 <tr>
127                   <td>1,005</td>
128                   <td>Nulla</td>
129                   <td>quis</td>
130                   <td>sem</td>
131                   <td>at</td>
132                 </tr>
133                 <tr>
134                   <td>1,006</td>
135                   <td>nibh</td>
136                   <td>elementum</td>
137                   <td>imperdiet</td>
138                   <td>Duis</td>
139                 </tr>
140                 <tr>
141                   <td>1,007</td>
142                   <td>sagittis</td>
143                   <td>ipsum</td>
144                   <td>Praesent</td>
145                   <td>mauris</td>
146                 </tr>
147                 <tr>
148                   <td>1,008</td>
149                   <td>Fusce</td>
150                   <td>nec</td>
151                   <td>tellus</td>
152                   <td>sed</td>
153                 </tr>
154                 <tr>
155                   <td>1,009</td>
156                   <td>augue</td>
157                   <td>semper</td>
158                   <td>porta</td>
159                   <td>Mauris</td>
160                 </tr>
161                 <tr>
162                   <td>1,010</td>
163                   <td>massa</td>
164                   <td>Vestibulum</td>
165                   <td>lacinia</td>
166                   <td>arcu</td>
167                 </tr>
168                 <tr>
169                   <td>1,011</td>
170                   <td>eget</td>
171                   <td>nulla</td>
172                   <td>Class</td>
173                   <td>aptent</td>
174                 </tr>
175                 <tr>
176                   <td>1,012</td>
177                   <td>taciti</td>
178                   <td>sociosqu</td>
179                   <td>ad</td>
180                   <td>litora</td>
181                 </tr>
182                 <tr>
183                   <td>1,013</td>
184                   <td>torquent</td>
185                   <td>per</td>
186                   <td>conubia</td>
187                   <td>nostra</td>
188                 </tr>
189                 <tr>
190                   <td>1,014</td>
191                   <td>per</td>
192                   <td>inceptos</td>
193                   <td>himenaeos</td>
194                   <td>Curabitur</td>
195                 </tr>
196                 <tr>
197                   <td>1,015</td>
198                   <td>sodales</td>
199                   <td>ligula</td>
200                   <td>in</td>
201                   <td>libero</td>
202                 </tr>
203               </tbody>
204             </table>
205           </div>
206         </div>
207       </div>
208     </div>
209 
210     </body>
211 {% endblock %}
index.html

 实际效果:

 6.crm中的动态菜单的功能

 目的:红线部分为动态生成的菜单部分

1.需要在models中添加一张表menu表关联role

 1 class Role(models.Model):
 2     """角色表"""
 3     name = models.CharField(max_length=64,unique=True)
 4     menus = models.ManyToManyField("Menu",blank=True)
 5     def __str__(self):
 6         return self.name
 7     class Meta:
 8         verbose_name = "角色表"
 9         verbose_name_plural = "角色表"
10 
11 class Menu(models.Model):
12     """菜单表"""
13     name = models.CharField(max_length=32)
14     url_name = models.CharField(max_length=64)
15 
16     def __str__(self):
17         return self.name
18 
19     class Meta:
20         verbose_name = "菜单表"
21         verbose_name_plural = "菜单表"
View Code

 

 2.在账号表、角色表、菜单表中添加数据

3.新建html文件customer,在index文件中循环菜单

1 {% extends "index.html" %}
2 
3 {% block page-content %}
4 客户库
5 {% endblock %}
customer
 1    <div class="container-fluid">
 2       <div class="row">
 3         <div class="col-sm-3 col-md-2 sidebar">
 4           <ul class="nav nav-sidebar">
 5               {% for role in request.user.userprofile.roles.all %}
 6                 {% for menu in role.menus.all %}
 7                     <li class=""><a href="{% url menu.url_name %}">{{ menu.name }}</a></li>
 8                 {% endfor %}
 9               {% endfor %}
10           </ul>
index

 利用不同的url这样就实现了不同的角色登录不同的页面。

 

posted @ 2018-08-07 09:43  Garrett0220  阅读(858)  评论(0编辑  收藏  举报
levels of contents