CRM目录结构

from django.shortcuts import  HttpResponse,render,redirect
from django.conf.urls import url
from django.utils.safestring import mark_safe
from django.urls import reverse
from django.forms import ModelForm
from stark.utils.my_page import Pagination
from django.db.models import Q class ShowList(object):
def __init__(self,config_obj,queryset,request):
self.config_obj = config_obj
self.queryset = queryset
self.request = request
self.page_obj = Pagination(self.request.GET.get('page',1),self.queryset.count(),self.request.GET)
self.page_queryset = self.queryset[self.page_obj.start:self.page_obj.end] def get_header(self):
# 表头数据 [str1,str2,]
head_list = []
for head_field in self.config_obj.get_new_list_display():
if isinstance(head_field, str):
if head_field == '__str__':
val = self.config_obj.model._meta.model_name.upper()
else:
val = self.config_obj.model._meta.get_field(head_field).verbose_name
else:
val = head_field(self.config_obj, is_header=True)
head_list.append(val)
return head_list def get_body(self):
# 表单数据 [[attr1,attr2,],[attr1,attr2,],[]]
body_list = []
for data in self.page_queryset:
tmp = []
for field in self.config_obj.get_new_list_display():
if isinstance(field, str):
val = getattr(data, field)
if field != '__str__':
field_obj = self.config_obj.model._meta.get_field(field)
if field_obj.choices:
val = getattr(data,'get_'+field+'_display')
if field in self.config_obj.list_display_links:
_url = self.config_obj.get_reverse_url('edit', data)
val = mark_safe('<a href="%s">%s</a>' % (_url, val))
else:
val = field(self.config_obj, obj=data)
tmp.append(val)
body_list.append(tmp)
return body_list def get_action(self):
# action标签渲染
tmp = []
for action in self.config_obj.actions:
tmp.append({
'name': action.__name__,
'desc': action.desc
})
return tmp def get_filter(self):
tmp_dict = {}
for field in self.config_obj.list_filter:
rel_model = self.config_obj.model._meta.get_field(field).rel.to
rel_queryset = rel_model.objects.all()
click_id = self.request.GET.get(field)
tmp = [] import copy
params1 = copy.deepcopy(self.request.GET)
if field in params1:
params1.pop(field)
s = mark_safe("<a href='?%s'>All</a>"%params1.urlencode())
else:
s = mark_safe("<a href=''>All</a>")
tmp.append(s) for data in rel_queryset:
import copy
params = copy.deepcopy(self.request.GET)
params[field] = data.pk
if click_id == str(data.pk):
s = mark_safe('<a href="?%s" class="active">%s</a>'%(params.urlencode(),str(data)))
else:
s = mark_safe('<a href="?%s">%s</a>'%(params.urlencode(),str(data)))
tmp.append(s)
tmp_dict[field] = tmp
return tmp_dict class ModelStark(object):
list_display = ['__str__',]
list_display_links = []
model_form_class = None
search_fields = []
actions = []
list_filter = [] def __init__(self,model):
self.model = model
self.app_label = self.model._meta.app_label
self.model_name = self.model._meta.model_name
self.key_word = '' def cho_col(self,is_header=False,obj=None):
if is_header:
return '选择'
return mark_safe("<input type='checkbox' value='%s' name='selected_actions'>"%obj.pk) def edit_col(self,is_header=False,obj=None):
if is_header:
return '编辑'
_url = self.get_reverse_url('edit',obj)
return mark_safe('<a href="%s">编辑</a>'%_url) def del_col(self,is_header=False,obj=None):
if is_header:
return '删除'
_url = self.get_reverse_url('delete',obj)
return mark_safe('<a href="%s">删除</a>'%_url) def get_reverse_url(self,type,obj=None):
if obj:
_url = reverse('%s_%s_%s'%(self.app_label,self.model_name,type),args=(obj.pk,))
else:
_url = reverse('%s_%s_%s'%(self.app_label,self.model_name,type))
return _url def get_new_list_display(self):
tmp = []
tmp.append(ModelStark.cho_col)
tmp.extend(self.list_display)
if not self.list_display_links:
tmp.append(ModelStark.edit_col)
tmp.append(ModelStark.del_col)
return tmp def get_search(self,request,queryset):
key_word = request.GET.get('q')
self.key_word = ''
if key_word:
self.key_word = key_word
q = Q()
q.connector = 'or'
for search_field in self.search_fields:
q.children.append((search_field + '__icontains', key_word))
queryset = queryset.filter(q)
return queryset def get_filter(self,request,queryset):
q = Q()
for field,field_id in request.GET.items():
if field in ['page','q']:
continue
field_id = request.GET.get(field)
q.children.append((field, field_id))
queryset = queryset.filter(q)
return queryset def list_view(self,request):
# action功能
if request.method == 'POST':
pk_list = request.POST.getlist('selected_actions')
action = request.POST.get('action')
if action:
action_func = getattr(self,action)
queryset = self.model.objects.filter(pk__in=pk_list)
action_func(request,queryset) queryset = self.model.objects.all()
# search功能
queryset = self.get_search(request,queryset)
# filter功能
queryset = self.get_filter(request,queryset) show_obj = ShowList(self,queryset,request) url = self.get_reverse_url('add')
return render(request, 'stark/list.html', locals()) def get_model_form_class(self):
if self.model_form_class:
return self.model_form_class
class ModelFormClass(ModelForm):
class Meta:
model = self.model
fields = '__all__'
return ModelFormClass def add_view(self,request):
model_form_class = self.get_model_form_class()
if request.method == 'POST':
model_form_obj = model_form_class(request.POST)
pop_back_id = request.GET.get('pop_back_id')
if model_form_obj.is_valid():
obj = model_form_obj.save()
print(obj)
if pop_back_id:
pk = obj.pk
text = str(obj)
return render(request, 'stark/pop.html', locals())
return redirect(self.get_reverse_url('list'))
model_form_obj = model_form_class()
for form_field in model_form_obj:
from django.forms.models import ModelChoiceField
if isinstance(form_field.field,ModelChoiceField):
form_field.is_pop = True
rel_model = self.model._meta.get_field(form_field.name).rel.to
rel_app_label = rel_model._meta.app_label
rel_model_name = rel_model._meta.model_name
url = reverse('%s_%s_add'%(rel_app_label,rel_model_name))
url = url + '?pop_back_id=' + form_field.auto_id
form_field.url = url
return render(request, 'stark/add.html', locals()) def edit_view(self,request,id):
model_form_class = self.get_model_form_class()
edit_obj = self.model.objects.filter(pk=id).first()
if request.method == 'POST':
model_form_obj = model_form_class(request.POST,instance=edit_obj)
if model_form_obj.is_valid():
model_form_obj.save()
return redirect(self.get_reverse_url('list'))
model_form_obj = model_form_class(instance=edit_obj)
return render(request, 'stark/edit.html', locals()) def delete_view(self,request,id):
delete_obj = self.model.objects.filter(pk=id).delete()
return redirect(self.get_reverse_url('list')) def get_urls(self):
tmp = [
url(r'^$',self.list_view,name='%s_%s_list'%(self.app_label,self.model_name)),
url(r'^add/',self.add_view,name='%s_%s_add'%(self.app_label,self.model_name)),
url(r'edit/(\d+)/',self.edit_view,name='%s_%s_edit'%(self.app_label,self.model_name)),
url(r'delete/(\d+)/',self.delete_view,name='%s_%s_delete'%(self.app_label,self.model_name))
]
tmp.extend(self.extra_url())
return tmp,None,None def extra_url(self):
return [] class AdminSite(object):
def __init__(self, name='admin'):
self._registry = {} # model_class class -> admin_class instance def register(self, model, admin_class=None, **options):
if not admin_class:
admin_class = ModelStark
self._registry[model] = admin_class(model) def get_urls(self):
tmp = []
for class_name,config_obj in self._registry.items():
app_label = class_name._meta.app_label
model_name = class_name._meta.model_name
tmp.append(
url(r'^%s/%s/'%(app_label,model_name),config_obj.get_urls())
)
return tmp @property
def urls(self):
return self.get_urls(), None, None site = AdminSite()

service/stark.py

class Pagination(object):
def __init__(self, current_page, all_count,params, per_page_num=10, pager_count=11):
"""
封装分页相关数据
:param current_page: 当前页
:param all_count: 数据库中的数据总条数
:param per_page_num: 每页显示的数据条数
:param pager_count: 最多显示的页码个数 用法:
queryset = model.objects.all()
page_obj = Pagination(current_page,all_count)
page_data = queryset[page_obj.start:page_obj.end]
获取数据用page_data而不再使用原始的queryset
获取前端分页样式用page_obj.page_html
"""
try:
current_page = int(current_page)
except Exception as e:
current_page = 1 if current_page < 1:
current_page = 1 self.current_page = current_page self.all_count = all_count
self.per_page_num = per_page_num # 总页码
all_pager, tmp = divmod(all_count, per_page_num)
if tmp:
all_pager += 1
self.all_pager = all_pager self.pager_count = pager_count
self.pager_count_half = int((pager_count - 1) / 2) import copy
self.params = copy.deepcopy(params) @property
def start(self):
return (self.current_page - 1) * self.per_page_num @property
def end(self):
return self.current_page * self.per_page_num def page_html(self):
# 如果总页码 < 11个:
if self.all_pager <= self.pager_count:
pager_start = 1
pager_end = self.all_pager + 1
# 总页码 > 11
else:
# 当前页如果<=页面上最多显示11/2个页码
if self.current_page <= self.pager_count_half:
pager_start = 1
pager_end = self.pager_count + 1 # 当前页大于5
else:
# 页码翻到最后
if (self.current_page + self.pager_count_half) > self.all_pager:
pager_end = self.all_pager + 1
pager_start = self.all_pager - self.pager_count + 1
else:
pager_start = self.current_page - self.pager_count_half
pager_end = self.current_page + self.pager_count_half + 1 page_html_list = []
# 添加前面的nav和ul标签
page_html_list.append('''
<nav aria-label='Page navigation>'
<ul class='pagination'>
''')
first_page = '<li><a href="?page=%s">首页</a></li>' % (1)
page_html_list.append(first_page) if self.current_page <= 1:
prev_page = '<li class="disabled"><a href="#">上一页</a></li>'
else:
prev_page = '<li><a href="?page=%s">上一页</a></li>' % (self.current_page - 1,) page_html_list.append(prev_page) res = self.params
for i in range(pager_start, pager_end):
res['page'] = i
if i == self.current_page:
temp = '<li class="active"><a href="?%s">%s</a></li>' % (res.urlencode(), i,)
else:
temp = '<li><a href="?%s">%s</a></li>' % (res.urlencode(), i,)
page_html_list.append(temp) if self.current_page >= self.all_pager:
next_page = '<li class="disabled"><a href="#">下一页</a></li>'
else:
next_page = '<li><a href="?page=%s">下一页</a></li>' % (self.current_page + 1,)
page_html_list.append(next_page) last_page = '<li><a href="?page=%s">尾页</a></li>' % (self.all_pager,)
page_html_list.append(last_page)
# 尾部添加标签
page_html_list.append('''
</nav>
</ul>
''')
return ''.join(page_html_list)

utils/my_page

templates/stark

{% extends 'stark/base.html' %}

{% block css %}
<link rel="stylesheet" href="/static/css/common.css">
{% endblock %}
{% block content %} <h3>添加数据</h3>
<form action="" method="post">
{% csrf_token %}
{% for foo in model_form_obj %}
<div class="form-inline fa-plus">
<p>{{ foo.label }}{{ foo }}</p>
{% if foo.is_pop %}
<span class="plus" onclick="openWindow('{{ foo.url }}')">+</span>
{% endif %}
</div>
{% endfor %}
<input type="submit" class="btn btn-info pull-right">
</form> <script>
function openWindow(url) {
window.open(url,'','width=800px,height=400px');
} function add_options(pop_back_id,pk,text) {
var opEle = document.createElement('option');
opEle.value = pk;
opEle.innerText = text;
opEle.selected = 'selected';
var seEle = document.getElementById(pop_back_id);
seEle.appendChild(opEle);
}
</script> {% endblock %}

add.html

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<meta name="viewport" content="width=device-width, initial-scale=1">
<script src="https://cdn.bootcss.com/jquery/3.3.1/jquery.min.js"></script>
<link href="https://cdn.bootcss.com/twitter-bootstrap/3.4.1/css/bootstrap.min.css" rel="stylesheet">
<script src="https://cdn.bootcss.com/twitter-bootstrap/3.4.1/js/bootstrap.min.js"></script>
<style>
.table {
margin-top: 10px;
}
.active {
color: red;
}
.fa-plus {
position: relative;
}
.plus {
font-size: 24px;
color: #336699;
position: absolute;
right: -31px;
top: 19px;
}
</style>
{% block css %} {% endblock %}
</head>
<body>
{# 导航条开始 #}
<nav class="navbar navbar-default">
<div class="container-fluid">
<!-- Brand and toggle get grouped for better mobile display -->
<div class="navbar-header">
<a class="navbar-brand" href="#">CRM</a>
</div>
<!-- Collect the nav links, forms, and other content for toggling -->
<div class="collapse navbar-collapse" id="bs-example-navbar-collapse-1">
<ul class="nav navbar-nav navbar-right">
<li>{% if request.session.user %}
<a href="">{{ request.session.user }}</a>
{% else %}
<a href="/login/">登陆</a>
{% endif %}</li>
<li class="dropdown">
<a href="#" class="dropdown-toggle" data-toggle="dropdown" role="button" aria-haspopup="true" aria-expanded="false">Dropdown <span class="caret"></span></a>
<ul class="dropdown-menu">
<li><a href="#">Action</a></li>
<li><a href="#">Another action</a></li>
<li><a href="#">Something else here</a></li>
<li role="separator" class="divider"></li>
<li><a href="/logout/">注销</a></li>
</ul>
</li>
</ul>
</div><!-- /.navbar-collapse -->
</div><!-- /.container-fluid -->
</nav>
{# 导航条结束 #} <div class="container">
<div class="row">
<div class="col-md-3">
<div class="menu">
<p><a href="/index">首页</a></p>
{% for foo in request.session.permission_menu_list %}
<p><a href="{{ foo.url }}">{{ foo.title }}</a></p>
{% endfor %}
</div>
</div>
<div class="col-md-9">
{% block content %} {% endblock %}
</div>
</div>
</div> </body>
</html>

base.html

{% extends 'stark/base.html' %}

{% block css %}
<link rel="stylesheet" href="/static/css/common.css">
{% endblock %}
{% block content %} <h3>编辑数据</h3>
<form action="" method="post">
{% csrf_token %}
{% for foo in model_form_obj %}
<p>{{ foo.label }}{{ foo }}</p>
{% endfor %}
<input type="submit" class="btn btn-success pull-right">
</form> {% endblock %}

edit.html

{% extends 'stark/base.html' %}

{% block content %}
<div class="jumbotron">
<h1>Hello, world!</h1>
<p>...</p>
<p><a class="btn btn-primary btn-lg" href="#" role="button">Learn more</a></p>
</div>
{% endblock %}

index

{% extends 'stark/base.html' %}

{% block css %}
<script src="/static/js/check.js"></script>
{% endblock %} {% block content %}
<h3>查看数据</h3>
<a href="{{ url }}" class="btn btn-primary">添加数据</a>
{# search功能开始#}
{% if show_obj.config_obj.search_fields %}
<form class="form-inline pull-right">
<div class="form-group">
<div class="input-group">
<input type="text" class="form-control" id="exampleInputAmount" placeholder="关键字" name="q"
value="{{ show_obj.config_obj.key_word }}">
</div>
</div>
<button type="submit" class="btn btn-danger">Search</button>
</form>
{% endif %}
{# search功能结束#}
{# action功能开始#}
<form action="" class="form-inline" method="post">
{% csrf_token %}
<select class="form-control" name="action">
<option value="">-------------------------</option>
{% for foo in show_obj.get_action %}
<option value="{{ foo.name }}">{{ foo.desc }}</option>
{% endfor %}
</select>
<input type="submit" value="Go!" class="btn btn-info">
<table class="table table-bordered table-striped table-hover">
<thead>
<tr>
{% for head in show_obj.get_header %}
<th>{{ head }}</th>
{% endfor %}
</tr>
</thead>
<tbody>
{% for data in show_obj.get_body %}
<tr>
{% for foo in data %}
<td>{{ foo }}</td>
{% endfor %}
</tr>
{% endfor %}
</tbody>
</table>
</form>
{{ show_obj.page_obj.page_html|safe }} {% if show_obj.config_obj.list_filter %}
<div class="col-md-3">
<div class="alert-info text-center">FILTER</div>
{% for foo,data_list in show_obj.get_filter.items %}
<div class="panel panel-default">
<div class="panel-heading">By {{ foo }}</div>
<div class="panel-body">
{% for data in data_list %}
<p>{{ data }}</p>
{% endfor %}
</div>
</div>
{% endfor %}
</div>
{% endif %} {% endblock %}

list.html

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<meta name="viewport" content="width=device-width, initial-scale=1">
</head>
<body>
<script>
window.opener.add_options('{{ pop_back_id }}','{{ pk }}','{{ text }}');
window.close(); </script> </body>
</html>

pop.html

permissionmiddle

from django.utils.deprecation import MiddlewareMixin
from django.shortcuts import redirect,HttpResponse
import re class PermissionMiddleWare(MiddlewareMixin):
def process_request(self,request):
# 当前用户访问路径
current_path = request.path
# 用户访问白名单
white_list = ['/login/','/admin/*']
for white_permission in white_list:
res = re.search(white_permission,current_path)
if res:
return None
# 校验是否登陆
if not request.session.get('user'):
return redirect('/login')
# 获取当前用户访问权限
permission_list = request.session.get('permission_list') # 判断是否有权访问 for permission_rex in permission_list:
permission_rex = '^%s$'%permission_rex
res = re.search(permission_rex,current_path)
if res:
return None
return HttpResponse('没有访问权限')

permission.py

static/js

window.onload = function () {
$('.xxx').change(function () {
var status = $(this).val();
var pk = $(this).attr('pk');
$.ajax({
url:'/stark/app01/studentstudyrecord/check_work/',
type:'post',
data:{
status:status,
pk:pk
},
success:function (data) {
console.log(data)
}
})
})
};

check.js

app01

from django.shortcuts import render,redirect
from app01 import models
# Create your views here.
def login(request):
if request.method == 'POST':
username = request.POST.get('username')
password = request.POST.get('password')
user_obj = models.User.objects.filter(name=username,pwd=password).first()
if user_obj:
# 记录登陆状态
request.session['user'] = username
# 记录权限列表
permission_list = []
permission_menu_list = []
res = user_obj.roles.values('permissions__url','permissions__title','permissions__code').distinct()
for permission in res:
permission_list.append(permission.get('permissions__url'))
if permission.get('permissions__code') == 'list':
permission_menu_list.append({
'url':permission.get('permissions__url'),
'title':permission.get('permissions__title'),
})
request.session['permission_menu_list'] = permission_menu_list
request.session['permission_list'] = permission_list
return redirect('/index')
return render(request,'login.html') def logout(request):
request.session.clear()
return redirect('/index') def index(request):
return render(request,'stark/index.html')

views.py

from app01 import models
from stark.service.stark import site,ModelStark
from django.utils.safestring import mark_safe
from django.conf.urls import url
from django.shortcuts import render,redirect,HttpResponse class UserConfig(ModelStark):
list_display = ['name','pwd','roles'] site.register(models.User,UserConfig)
site.register(models.Role)
class PermissionConfig(ModelStark):
list_display = ['title','url']
list_display_links = ['title']
site.register(models.Permission,PermissionConfig) # CRM相关表
site.register(models.School)
site.register(models.Course)
site.register(models.Department)
site.register(models.UserInfo)
site.register(models.ClassList) class CustomerConfig(ModelStark):
def show_consult_course(self,is_header=False,obj=None):
if is_header:
return '咨询课程'
course_list = []
for course in obj.course.all():
course_list.append('<a href="/stark/app01/customer/cancel_course/%s/%s/" style="border: 1px solid blue;padding: 3px 6px">%s</a>'%(obj.pk,course.pk,course.name))
return mark_safe(' '.join(course_list)) def cancel_course(self, request, customer_id, course_id):
customer_obj = models.Customer.objects.filter(pk=customer_id).first()
customer_obj.course.remove(course_id)
return redirect(self.get_reverse_url('list')) def extra_url(self):
tmp = []
tmp.append(
url(r'^cancel_course/(\d+)/(\d+)/', self.cancel_course)
)
return tmp
list_display = ['name','gender',show_consult_course] site.register(models.Customer,CustomerConfig) site.register(models.ConsultRecord)
site.register(models.Student) class ClassStudyRecordConfig(ModelStark):
def patch_init(self,request,queryset):
# queryset是选中的某个班级当天的课程记录
tmp = []
for course_record_obj in queryset:
student_list = models.Student.objects.filter(class_list=course_record_obj.class_obj.pk)
for student_obj in student_list:
obj = models.StudentStudyRecord(classstudyrecord=course_record_obj,student=student_obj)
tmp.append(obj)
models.StudentStudyRecord.objects.bulk_create(tmp)
patch_init.desc = '批量生成学生学习记录'
actions = [patch_init] def record(self,is_header=False,obj=None):
if is_header:
return '记录'
_url = '/stark/app01/studentstudyrecord/?classstudyrecord=%s'%obj.pk
return mark_safe("<a href='%s'>记录</a>"%_url) list_display = ['class_obj','day_num',record]
site.register(models.ClassStudyRecord,ClassStudyRecordConfig)
class StudentStudyRecordConfig(ModelStark):
def patch_late(self,request,queryset):
queryset.update(record='late')
patch_late.desc = '批量处理迟到'
actions = [patch_late] def work(self,is_header=False,obj=None):
if is_header:
return '考勤'
html = ''
for k in obj.record_choices:
if obj.record == k[0]:
s = "<option value='%s' selected>%s</option>"%k
else:
s = "<option value='%s' >%s</option>"%k
html += s
return mark_safe("<select class='xxx' pk=%s>%s</select>"%(obj.pk,html)) def check(self,request):
status = request.POST.get('status')
pk = request.POST.get('pk')
print(status,pk)
models.StudentStudyRecord.objects.filter(pk=pk).update(record=status)
return HttpResponse('ok') def extra_url(self):
tmp = []
tmp.append(
url(r'^check_work/',self.check)
)
return tmp list_display = ['classstudyrecord', 'student', 'record', 'score',work]
site.register(models.StudentStudyRecord,StudentStudyRecordConfig)

stark.py

from django.db import models

# Create your models here.
# rbac权限相关表格
class User(models.Model):
name = models.CharField(max_length=32)
pwd = models.CharField(max_length=32)
roles = models.ManyToManyField(to='Role') def __str__(self):
return self.name class Role(models.Model):
title = models.CharField(max_length=32)
permissions = models.ManyToManyField(to='Permission') def __str__(self):
return self.title class Permission(models.Model):
title = models.CharField(max_length=32)
url = models.CharField(max_length=32)
code = models.CharField(max_length=32,default='list') def __str__(self):
return self.title # CRM相关内部表
class School(models.Model):
"""
校区表
如:
北京沙河校区
上海校区 """
title = models.CharField(verbose_name='校区名称', max_length=32) def __str__(self):
return self.title class Course(models.Model):
"""
课程表
如:
Linux基础
Linux架构师
Python自动化开发精英班
Python自动化开发架构师班
Python基础班
go基础班
"""
name = models.CharField(verbose_name='课程名称', max_length=32) def __str__(self):
return self.name class Department(models.Model):
"""
部门表
市场部 1000
销售 1001 """
title = models.CharField(verbose_name='部门名称', max_length=16)
code = models.IntegerField(verbose_name='部门编号', unique=True, null=False) def __str__(self):
return self.title class UserInfo(models.Model):
"""
员工表
""" name = models.CharField(verbose_name='员工姓名', max_length=16)
email = models.EmailField(verbose_name='邮箱', max_length=64)
depart = models.ForeignKey(verbose_name='部门', to="Department",to_field="code")
user=models.OneToOneField("User",default=1)
def __str__(self):
return self.name class ClassList(models.Model):
"""
班级表
如:
Python全栈 面授班 5期 10000 2017-11-11 2018-5-11
"""
school = models.ForeignKey(verbose_name='校区', to='School')
course = models.ForeignKey(verbose_name='课程名称', to='Course')
semester = models.IntegerField(verbose_name="班级(期)") price = models.IntegerField(verbose_name="学费")
start_date = models.DateField(verbose_name="开班日期")
graduate_date = models.DateField(verbose_name="结业日期", null=True, blank=True)
memo = models.CharField(verbose_name='说明', max_length=256, blank=True, null=True, ) teachers = models.ManyToManyField(verbose_name='任课老师', to='UserInfo',limit_choices_to={'depart':1002})
tutor = models.ForeignKey(verbose_name='班主任', to='UserInfo',related_name="class_list",limit_choices_to={'depart':1006}) def __str__(self):
return "{0}({1}期)".format(self.course.name, self.semester) class Customer(models.Model):
"""
客户表
"""
qq = models.CharField(verbose_name='qq', max_length=64, unique=True, help_text='QQ号必须唯一') name = models.CharField(verbose_name='学生姓名', max_length=16)
gender_choices = ((1, '男'), (2, '女'))
gender = models.SmallIntegerField(verbose_name='性别', choices=gender_choices) education_choices = (
(1, '重点大学'),
(2, '普通本科'),
(3, '独立院校'),
(4, '民办本科'),
(5, '大专'),
(6, '民办专科'),
(7, '高中'),
(8, '其他')
)
education = models.IntegerField(verbose_name='学历', choices=education_choices, blank=True, null=True, )
graduation_school = models.CharField(verbose_name='毕业学校', max_length=64, blank=True, null=True)
major = models.CharField(verbose_name='所学专业', max_length=64, blank=True, null=True) experience_choices = [
(1, '在校生'),
(2, '应届毕业'),
(3, '半年以内'),
(4, '半年至一年'),
(5, '一年至三年'),
(6, '三年至五年'),
(7, '五年以上'),
]
experience = models.IntegerField(verbose_name='工作经验', blank=True, null=True, choices=experience_choices)
work_status_choices = [
(1, '在职'),
(2, '无业')
]
work_status = models.IntegerField(verbose_name="职业状态", choices=work_status_choices, default=1, blank=True,
null=True)
company = models.CharField(verbose_name="目前就职公司", max_length=64, blank=True, null=True)
salary = models.CharField(verbose_name="当前薪资", max_length=64, blank=True, null=True) source_choices = [
(1, "qq群"),
(2, "内部转介绍"),
(3, "官方网站"),
(4, "百度推广"),
(5, "360推广"),
(6, "搜狗推广"),
(7, "腾讯课堂"),
(8, "广点通"),
(9, "高校宣讲"),
(10, "渠道代理"),
(11, "51cto"),
(12, "智汇推"),
(13, "网盟"),
(14, "DSP"),
(15, "SEO"),
(16, "其它"),
]
source = models.SmallIntegerField('客户来源', choices=source_choices, default=1)
referral_from = models.ForeignKey(
'self',
blank=True,
null=True,
verbose_name="转介绍自学员",
help_text="若此客户是转介绍自内部学员,请在此处选择内部学员姓名",
related_name="internal_referral"
)
course = models.ManyToManyField(verbose_name="咨询课程", to="Course") status_choices = [
(1, "已报名"),
(2, "未报名")
]
status = models.IntegerField(
verbose_name="状态",
choices=status_choices,
default=2,
help_text=u"选择客户此时的状态"
) consultant = models.ForeignKey(verbose_name="课程顾问", to='UserInfo', related_name='consultanter',limit_choices_to={'depart':1001}) date = models.DateField(verbose_name="咨询日期", auto_now_add=True)
recv_date = models.DateField(verbose_name="当前课程顾问的接单日期", null=True)
last_consult_date = models.DateField(verbose_name="最后跟进日期", ) def __str__(self):
return self.name class ConsultRecord(models.Model):
"""
客户跟进记录
"""
customer = models.ForeignKey(verbose_name="所咨询客户", to='Customer')
consultant = models.ForeignKey(verbose_name="跟踪人", to='UserInfo',limit_choices_to={'depart':1001})
date = models.DateField(verbose_name="跟进日期", auto_now_add=True)
note = models.TextField(verbose_name="跟进内容...") def __str__(self):
return self.customer.name + ":" + self.consultant.name class Student(models.Model):
"""
学生表(已报名)
"""
customer = models.OneToOneField(verbose_name='客户信息', to='Customer')
class_list = models.ManyToManyField(verbose_name="已报班级", to='ClassList', blank=True) emergency_contract = models.CharField(max_length=32, blank=True, null=True, verbose_name='紧急联系人')
company = models.CharField(verbose_name='公司', max_length=128, blank=True, null=True)
location = models.CharField(max_length=64, verbose_name='所在区域', blank=True, null=True)
position = models.CharField(verbose_name='岗位', max_length=64, blank=True, null=True)
salary = models.IntegerField(verbose_name='薪资', blank=True, null=True)
welfare = models.CharField(verbose_name='福利', max_length=256, blank=True, null=True)
date = models.DateField(verbose_name='入职时间', help_text='格式yyyy-mm-dd', blank=True, null=True)
memo = models.CharField(verbose_name='备注', max_length=256, blank=True, null=True) def __str__(self):
return self.customer.name class ClassStudyRecord(models.Model):
"""
上课记录表 (班级记录)
"""
class_obj = models.ForeignKey(verbose_name="班级", to="ClassList")
day_num = models.IntegerField(verbose_name="节次", help_text=u"此处填写第几节课或第几天课程...,必须为数字")
teacher = models.ForeignKey(verbose_name="讲师", to='UserInfo',limit_choices_to={'depart':1002})
date = models.DateField(verbose_name="上课日期", auto_now_add=True) course_title = models.CharField(verbose_name='本节课程标题', max_length=64, blank=True, null=True)
course_memo = models.TextField(verbose_name='本节课程内容概要', blank=True, null=True)
has_homework = models.BooleanField(default=True, verbose_name="本节有作业")
homework_title = models.CharField(verbose_name='本节作业标题', max_length=64, blank=True, null=True)
homework_memo = models.TextField(verbose_name='作业描述', max_length=500, blank=True, null=True)
exam = models.TextField(verbose_name='踩分点', max_length=300, blank=True, null=True) def __str__(self):
return "{0} day{1}".format(self.class_obj, self.day_num) class StudentStudyRecord(models.Model):
'''
学生学习记录
'''
classstudyrecord = models.ForeignKey(verbose_name="第几天课程", to="ClassStudyRecord")
student = models.ForeignKey(verbose_name="学员", to='Student') record_choices = (('checked', "已签到"),
('vacate', "请假"),
('late', "迟到"),
('noshow', "缺勤"),
('leave_early', "早退"),
)
record = models.CharField("上课纪录", choices=record_choices, default="checked", max_length=64)
score_choices = ((100, 'A+'),
(90, 'A'),
(85, 'B+'),
(80, 'B'),
(70, 'B-'),
(60, 'C+'),
(50, 'C'),
(40, 'C-'),
(0, ' D'),
(-1, 'N/A'),
(-100, 'COPY'),
(-1000, 'FAIL'),
)
score = models.IntegerField("本节成绩", choices=score_choices, default=-1)
homework_note = models.CharField(verbose_name='作业评语', max_length=255, blank=True, null=True)
note = models.CharField(verbose_name="备注", max_length=255, blank=True, null=True) homework = models.FileField(verbose_name='作业文件', blank=True, null=True, default=None)
stu_memo = models.TextField(verbose_name='学员备注', blank=True, null=True)
date = models.DateTimeField(verbose_name='提交作业日期', auto_now_add=True) def __str__(self):
return "{0}-{1}".format(self.classstudyrecord, self.student)

models.py

 

CRM、用户管理权限的更多相关文章

  1. Linux_用户管理&权限管理

    2017年1月11日, 星期三 Linux_用户管理&权限管理 1.  Linux用户管理&权限管理 终端的概念: tty  查看登录的终端 类型  user group    oth ...

  2. Oracle 用户管理权限

    Oracle 用户管理权限 一.创建用户的Profile文件 SQL> create profile student limit // student为资源文件名 FAILED_LOGIN_AT ...

  3. Ubuntu 用户管理/权限管理

    Ubuntu 用户管理/权限管理 小小记录一下 Ubuntu 下用户/权限管理常用的一些命令 用户管理 组管理 文件权限 给用户添加 sudo 权限 给用户添加 sudo 权限 首先先给出几个文件 / ...

  4. mysql用户管理,权限管理

    mysql权限 相关操作: 授予的权限分为四组: 列权限:和表中的一个具体列相关,例如:使用update 语句更新test表中name 列的值 表权限:和一个具体的表的所有数据相关,例如:使用 sel ...

  5. mysql 用户管理 权限控制

    添加用户 insert into mysql.user(Host,User,Password) values("%","shenen",password(&qu ...

  6. Linux用户管理 权限管理 内存管理 网络管理命令 (第四天)

    默认添加的用户会自动加入和用户名一样的组中su 切换用户查看当前登陆的用户: whoami id`查看当前用户属于哪个组:groupsgroupadd 组名 添加组groupdel 组名 删除组gre ...

  7. jenkins 添加用户管理权限

    一.前言 小组开会通知 想把jenkins 构建的权限给开发,这样的话效率会增加.运维也不必每次帮助开发去构建发布. 1.规划 jenkins 四个项目分别对应三个人负责.项目下的只负责 CI.UAT ...

  8. MySQL 用户管理——权限表

    权限表 权限表存放在mysql数据库中 user表结构 用户列:Host.User.Password 权限列:*priv 资源控制列:max* 安全列:其余   db表 存储了用户对某个数据库的操作权 ...

  9. react_app 项目开发 (8)_角色管理_用户管理----权限管理 ---- shouldComponentUpdate

    角色管理 性能优化(前端面试) 需求:只要执行 setState(), 就会调用 render  重新渲染.由于有时调用了 setState,但是并没有发生状态的改变,以致于不必要的刷新 解决: 重写 ...

随机推荐

  1. C# IObservable与IObserver观察者模式

    C#中提供了IObservable<T>接口和IObserver<T>接口来实现观察者模式,IObservable<T>相当于Subject(主题)接口,下面我们就 ...

  2. java文件的写入和读取(按行)

    https://blog.csdn.net/Alexwym/article/details/81078417 https://blog.csdn.net/nickwong_/article/detai ...

  3. 大数据理论篇HDFS的基石——Google File System

    Google File System 但凡是要开始讲大数据的,都绕不开最初的Google三驾马车:Google File System(GFS), MapReduce,BigTable. 为这一切的基 ...

  4. consul、eureka、nacos对比

    consul.eureka.nacos对比 配置中心 eureka 不支持 consul 支持 但用起来偏麻烦,不太符合springBoot框架的命名风格,支持动态刷新 nacos 支持 用起来简单, ...

  5. Dubbo直连方式改造

    目录 一.dubbo 服务化最佳实践 1. 分包 2. 粒度 3. 版本 二.改造 dubbo 项目 三.link-interface 1. pom.xml 2. 实体类 3. 公共接口 四.提供者 ...

  6. Lombok插件有望被Intellij IDEA收编以改善兼容性问题

    1. 前言 最近两个版本的Intellij IDEA没有办法使用lombok插件了,这种问题已经出现了多次,导致胖哥依然使用2020.1的旧版本.其实很多人和我一样也回滚到了旧版本.我一直认为是lom ...

  7. CSS 选择器及优先级

    CSS 选择器及优先级 1.根据权值计算 div .class1 #people的权值等于1+10+100=111 .class2 li #age的权值等于10+1+100=111 2.权值相同,那么 ...

  8. Java BigDecimal使用指南

    提起BigDecimal,相信大家都使用过,之所以总结这篇呢,是因为最近发现项目中使用的不是太规范,在某些场景下甚至出现代码抛出异常的情况, 所以就总结了这篇,希望大家在使用时,可以少踩一些坑. 1. ...

  9. flutter 设置状态栏的背景与颜色

    flutter 设置状态栏的背景与颜色 导包 import 'dart:io'; import 'package:flutter/services.dart'; 在main()函数中添加以下函数, v ...

  10. 认识JavaScript中Let和Var的区别

    本文转载自:https://www.cnblogs.com/songzxblog/p/11137117.html