项目一:CRM(客户关系管理系统)--1

Djangoadmin已经为我们做好了,很完善的后台管理体系,但页面过于丑陋,自定义的能力还是有局限性的。特此,重写admin后台管理体系,同时也是考虑到其他轻量级框架并没有类似Django这么完善的admin!写成独立的app,便宜更好的进行复用迁移。

1. 创建工程和项目

命名根据自己的喜好吧,推荐使用PyCharm进行创建,减少一些配置操作,当然不要忘记在settings.py的一些配置!

目录结构如下:

├─consultant  #销售
│  ├─migrations
│  │  └─__pycache__
│  └─__pycache__
├─CRM    #主app
│  ├─migrations
│  │  └─__pycache__
│  └─__pycache__
├─king_admin #重构的admin
│  ├─migrations
│  │  └─__pycache__
│  ├─templatetags
│  │  └─__pycache__
│  └─__pycache__
├─PrefectCRM_new #工程
│  └─__pycache__
├─statics
│  ├─css
│  ├─imgs
│  ├─js
│  └─plugins
├─student  #学生
│  ├─migrations
│  │  └─__pycache__
│  └─__pycache__
├─templates
│  ├─consultant
│  ├─king_admin
│  └─student
└─utils
由于在数据库表中,绑定了一些路由映射关系,顺便将路由的结构也显示一下:
 1 #这是总的urls.py中的配置,独立将在下面一次贴出来
 2 from django.conf.urls import url,include
 3 from django.contrib import admin
 4 urlpatterns = [
 5     url(r'^admin/', admin.site.urls),
 6     url(r'^crm/', include('CRM.urls')),
 7     url(r'^student/', include('student.urls')),
 8     url(r'^consultant/', include('consultant.urls')),
 9     url(r'^king_admin/', include('king_admin.urls')),
10 ]

 

2. 表结构设计

表结构设计是非常关键的步骤,也是最难点!这会影响你以后的程序设计,稍有疏漏,很可能会导致你要进行代码重构或者一路填坑...

由于要做的是CRM系统,这里就以XXX公司作为案例。

在进行具体的代码之前,我们先进行一些数据关系的处理,这里推荐大家使用ER图(mac上我使用MindNode)。我这里是通过先前搞好的数据结构和ER图,就不在重复赘述,直接上处理好后的图和代码: 

ER思维导图:

数据关系图:

 在主appCRM中的models.py中创建数据结构:

  1 from django.db import models
  2 from django.contrib.auth.models import User
  3 # Create your models here.
  4 class Customer(models.Model):
  5     '''客户信息表'''
  6     name = models.CharField(max_length=32,blank=True,null=True)
  7     qq = models.CharField(max_length=64,unique=True)
  8     qq_name = models.CharField(max_length=64,blank=True,null=True)
  9     phone = models.CharField(max_length=64,blank=True,null=True)
 10     source_choices = ((0,'转介绍'),
 11                       (1,'QQ群'),
 12                       (2,'官网'),
 13                       (3,'百度推广'),
 14                       (4,'51CTO'),
 15                       (5,'知乎'),
 16                       (6,'市场推广')
 17                       )
 18     source = models.SmallIntegerField(choices=source_choices)
 19     referral_from = models.CharField(verbose_name="转介绍人qq",max_length=64,blank=True,null=True)
 20     consult_course = models.ForeignKey("Course",verbose_name="咨询课程")
 21     content = models.TextField(verbose_name="咨询详情")
 22     tags = models.ManyToManyField("Tag",blank=True)
 23     status_choices = ((0,'已报名'),
 24                       (1,'未报名'),
 25                       )
 26     status = models.SmallIntegerField(choices=status_choices,default=1)
 27     consultant = models.ForeignKey("UserProfile")
 28     memo = models.TextField(blank=True,null=True)
 29     date = models.DateTimeField(auto_now_add=True)
 30     def __str__(self):
 31         return self.qq
 32     class Meta:
 33         verbose_name ="客户表"
 34         verbose_name_plural ="客户表"
 35 class Tag(models.Model):
 36     name = models.CharField(unique=True,max_length=32)
 37     def __str__(self):
 38         return self.name
 39     class Meta:
 40         verbose_name = "标签"
 41         verbose_name_plural = "标签"
 42 class CustomerFollowUp(models.Model):
 43     '''客户跟进表'''
 44     customer = models.ForeignKey("Customer")
 45     content = models.TextField(verbose_name="跟进内容")
 46     consultant = models.ForeignKey("UserProfile")
 47     intention_choices  = ((0,'2周内报名'),
 48                           (1,'1个月内报名'),
 49                           (2,'近期无报名计划'),
 50                           (3,'已在其它机构报名'),
 51                           (4,'已报名'),
 52                           (5,'已拉黑'),
 53                           )
 54     intention = models.SmallIntegerField(choices=intention_choices)
 55     date = models.DateTimeField(auto_now_add=True)
 56     def __str__(self):
 57         return "<%s : %s>" %(self.customer.qq,self.intention)
 58     class Meta:
 59         verbose_name = '客户追踪'
 60         verbose_name_plural = "客户追踪"
 61 class Course(models.Model):
 62     '''课程表'''
 63     name = models.CharField(max_length=64,unique=True)
 64     price = models.PositiveSmallIntegerField()
 65     period = models.PositiveSmallIntegerField(verbose_name="周期(月)")
 66     outline = models.TextField()
 67     def __str__(self):
 68         return self.name
 69     class Meta:
 70         verbose_name = "课程表"
 71         verbose_name_plural = "课程表"
 72 class Branch(models.Model):
 73     '''校区'''
 74     name = models.CharField(max_length=128,unique=True)
 75     addr = models.CharField(max_length=128)
 76     def __str__(self):
 77         return self.name
 78     class Meta:
 79         verbose_name = "校区"
 80         verbose_name_plural = "校区"
 81 class ClassList(models.Model):
 82     '''班级表'''
 83     branch = models.ForeignKey("Branch",verbose_name="校区")
 84     course = models.ForeignKey("Course")
 85     class_type_choices = ((0,'面授(脱产)'),
 86                           (1,'面授(周末)'),
 87                           (2,'网络班')
 88                           )
 89     class_type = models.SmallIntegerField(choices=class_type_choices,verbose_name="班级类型")
 90     semester = models.PositiveSmallIntegerField(verbose_name="学期")
 91     teachers = models.ManyToManyField("UserProfile")
 92     start_date = models.DateField(verbose_name="开班日期")
 93     end_date = models.DateField(verbose_name="结业日期",blank=True,null=True)
 94     def __str__(self):
 95         return "%s %s %s" %(self.branch,self.course,self.semester)
 96     class Meta:
 97         unique_together = ('branch','course','semester')
 98         verbose_name_plural = "班级"
 99         verbose_name = "班级"
100 class CourseRecord(models.Model):
101     '''上课记录'''
102     from_class = models.ForeignKey("ClassList",verbose_name="班级")
103     day_num = models.PositiveSmallIntegerField(verbose_name="第几节(天)")
104     teacher = models.ForeignKey("UserProfile")
105     has_homework = models.BooleanField(default=True)
106     homework_title = models.CharField(max_length=128,blank=True,null=True)
107     homework_content = models.TextField(blank=True,null=True)
108     outline = models.TextField(verbose_name="本节课程大纲")
109     date = models.DateField(auto_now_add=True)
110     def __str__(self):
111         return "%s %s" %(self.from_class,self.day_num)
112     class Meta:
113         unique_together = ("from_class", "day_num")
114         verbose_name_plural = "上课记录"
115 class StudyRecord(models.Model):
116     '''学习记录'''
117     student = models.ForeignKey("Enrollment")
118     course_record = models.ForeignKey("CourseRecord")
119     attendance_choices = ((0,'已签到'),
120                           (1,'迟到'),
121                           (2,'缺勤'),
122                           (3,'早退'),
123                           )
124     attendance = models.SmallIntegerField(choices=attendance_choices,default=0)
125     score_choices = ((100,"A+"),
126                      (90,"A"),
127                      (85,"B+"),
128                      (80,"B"),
129                      (75,"B-"),
130                      (70,"C+"),
131                      (60,"C"),
132                      (40,"C-"),
133                      (-50,"D"),
134                      (-100,"COPY"),
135                      (0,"N/A"),
136                      )
137     score = models.SmallIntegerField(choices=score_choices,default=0)
138     memo = models.TextField(blank=True,null=True)
139     date = models.DateField(auto_now_add=True)
140     def __str__(self):
141         return "%s %s %s" %(self.student,self.course_record,self.score)
142     class Meta:
143         unique_together = ('student','course_record')
144         verbose_name_plural = "学习记录"
145 class Enrollment(models.Model):
146     '''报名表'''
147     customer = models.ForeignKey("Customer")
148     enrolled_class = models.ForeignKey("ClassList",verbose_name="所报班级")
149     consultant = models.ForeignKey("UserProfile",verbose_name="课程顾问")
150     contract_agreed = models.BooleanField(default=False,verbose_name="学员已同意合同条款")
151     contract_approved = models.BooleanField(default=False,verbose_name="合同已审核")
152     date = models.DateTimeField(auto_now_add=True)
153     def __str__(self):
154         return "%s %s" %(self.customer,self.enrolled_class)
155     class Meta:
156         unique_together = ("customer","enrolled_class")
157         verbose_name_plural = "报名表"
158 class Payment(models.Model):
159     '''缴费记录'''
160     customer = models.ForeignKey("Customer")
161     course = models.ForeignKey("Course",verbose_name="所报课程")
162     amount = models.PositiveIntegerField(verbose_name="数额",default=500)
163     consultant = models.ForeignKey("UserProfile")
164     date = models.DateTimeField(auto_now_add=True)
165     def __str__(self):
166         return "%s %s" %(self.customer,self.amount)
167     class Meta:
168         verbose_name_plural = "缴费记录"
169 class UserProfile(models.Model):
170     '''账号表'''
171     user = models.OneToOneField(User)
172     name = models.CharField(max_length=32)
173     roles = models.ManyToManyField("Role",blank=True)
174     def __str__(self):
175         return self.name
176     class Meta:
177         verbose_name_plural = '用户账号'
178 class Role(models.Model):
179     '''角色表'''
180     name = models.CharField(max_length=32,unique=True)
181     menus = models.ManyToManyField("Menu",blank=True)
182     def __str__(self):
183         return self.name
184     class Meta:
185         verbose_name_plural = "角色"
186 class Menu(models.Model):
187     '''菜单'''
188     name = models.CharField(max_length=32)
189     url_name = models.CharField(max_length=64)
190     def __str__(self):
191         return self.name
192     class Meta:
193         verbose_name_plural = '菜单栏'

1.以上内容只是作为参考,并不一定能够作为生产上的应用,若要上生产还要考虑更多的因素,这里是为写CRM提供一种通用的思路。
2.如果你考虑到以后的数据会很大,那建议你对数据进行拆分,每个独立的app中进行独自的表结构设计,然后在主app中进行处理

 

3. 原生Django的admin分析

在进行分析之前,我们需要创建超级用户,然后登陆到后台中,添加一些测试数据。

3.1 admin初始化操作

 

 

3.1.1. 创建超级用户

1 >>> python  manage.py  createsuperuser
2 #下面的用户名和密码自己耍吧!

 

3.1.2. 注册admin

其实,创建完用户我们就已经可以进入到后台了,将写好数据表models.py里面的类注册CRM项目的admin.py中,并进行一些简单的自定义操作:

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

 

3.1.3. 登陆admin后台

以下是将数据库表结构设计好后的显示效果,其中添加了一些测试数据:

 

3.2 自定义显示样式

 

我们在上面看到客户表中显示的内容太过稀少,而且功能也是少的可怜,好在Django为我们提供了自定义功能。

同样在admin.py中进行自定义操作:

支持中文:

1 'django.contrib.sessions.middleware.SessionMiddleware',
2 'django.middleware.locale.LocaleMiddleware',    # 设置admin为中文,必须放在django.contrib.sessions....之后

 

修改时区:

1 LANGUAGE_CODE = 'en-us'
2 
3 TIME_ZONE = 'Asia/Shanghai'    # 设置为东八区的时区
4 
5 USE_I18N = True
6 
7 USE_L10N = True
8 
9 USE_TZ = True

 

 1 from django.contrib import admin
 2 from CRM import models
 3 # Register your models here.
 4 #自定义操作
 5 class CustomerAdmin(admin.ModelAdmin):
 6     list_display = ('name', 'id','qq','source','consultant','content','status','date')
 7     list_filter = ('source','consultant','date')
 8     search_fields = ('qq','name')
 9     raw_id_fields = ('consult_course',)
10     filter_horizontal = ('tags',)
11     list_editable = ('status',)
12 class UserProfileAdmin(admin.ModelAdmin):
13     list_display = ('user','name')
14 #注册操作
15 #注册操作
16 admin.site.register(models.Branch)
17 admin.site.register(models.ClassList)
18 admin.site.register(models.Course)
19 admin.site.register(models.CourseRecord)
20 admin.site.register(models.Customer, CustomerAdmin)  #这里要添加自定义操作
21 admin.site.register(models.CustomerFollowUp)
22 admin.site.register(models.Enrollment)
23 admin.site.register(models.Payment)
24 admin.site.register(models.Role)
25 admin.site.register(models.StudyRecord)
26 admin.site.register(models.UserProfile, UserProfileAdmin)  #这里要添加自定义操作
27 admin.site.register(models.Tag)
28 admin.site.register(models.Menu)

 

 

 

在这里我们能看到很多功能,搜索,过滤,自定义操作action,排序,分页(数据量多时),添加等等。下面的文章中,就进行重构这些功能!

 1. 显示内容定制:list_display

2. 过滤功能 list_filter

 

3. 搜索功能 search_fields

4. 字段搜索功能 raw_id_fields

 

5. 字段过滤功能  filter_horizontal

6. 可编辑字段 list_editable

 



posted @ 2017-12-23 20:32  EagleSour  阅读(6109)  评论(3编辑  收藏  举报