crm项目包含django创建虚拟环境:

时间:2022-12-23 18:54:36

CRM项目

  1. 业务
  2. 权限

CRM

客户关系管理系统(customer relationship management)

使用人员:

销售 财务 班主任 讲师 助教

业务:

  1. 登录
  2. 注册

销售:

  1. 客户信息管理
    展示 新增 编辑
  1. 跟进记录的管理

展示 新增 编辑

  1. 报名记录的管理

展示 新增 编辑

  1. 缴费记录的管理

展示 新增 编辑

班主任

  1. 班级的管理
    展示 新增 编辑
  2. 课程记录的管理
    展示 新增 编辑
  3. 学习记录的管理

表结构

  1. 用户表
  2. 客户表
    关联销售 可以为空 (为空 是公户 ,不为空是私户)
  3. 跟进记录表
  4. 报名记录表
  5. 缴费记录表
  6. 校区
  7. 班级表
  8. 课程记录表

 1、django创建虚拟环境:

show All:

crm项目包含django创建虚拟环境:

2、 +:

crm项目包含django创建虚拟环境:

 

crm项目包含django创建虚拟环境:

3、 创建中:

crm项目包含django创建虚拟环境:

4、 干净的虚拟环境:

crm项目包含django创建虚拟环境:

5、 下载django:

 

crm项目包含django创建虚拟环境:

 

 

crm项目包含django创建虚拟环境:

 

 

crm项目包含django创建虚拟环境:

 

 

crm项目包含django创建虚拟环境:

 

 

crm项目包含django创建虚拟环境:

 6、创建数据库:

crm项目包含django创建虚拟环境:

 7、pycharm配置git:

git init 

crm项目包含django创建虚拟环境:

 8、导入忽略文件:

crm项目包含django创建虚拟环境:

9、不要提交到git上并忽略再次出现:

crm项目包含django创建虚拟环境:

10、crm\__init__.py:

#默认使用mysqldb的模块 要使用pymysql替换mysqldb
import pymysql
pymysql.install_as_MySQLdb()
11、crm\models.py:
from django.db import models
#导入多选功能:
from multiselectfield import MultiSelectField

#定义哪些课程:
course_choices = (('Linux', 'Linux中高级'),
('PythonFullStack', 'Python高级全栈开发'),)

#定义哪些班级:
class_type_choices = (('fulltime', '脱产班',),
('online', '网络班'),
('weekend', '周末班',),)

#定义哪些来源:
source_type = (('qq', "qq群"),
('referral', "内部转介绍"),
('website', "官方网站"),
('baidu_ads', "百度推广"),
('office_direct', "直接上门"),
('WoM', "口碑"),
('public_class', "公开课"),
('website_luffy', "路飞官网"),
('others', "其它"),)

#定义状态:
enroll_status_choices = (('signed', "已报名"),
('unregistered', "未报名"),
('studying', '学习中'),
('paid_in_full', "学费已交齐"))

#定义跟进情况:
seek_status_choices = (('A', '近期无报名计划'), ('B', '1个月内报名'), ('C', '2周内报名'), ('D', '1周内报名'),
('E', '定金'), ('F', '到班'), ('G', '全款'), ('H', '无效'),)

#定义支付类型:
pay_type_choices = (('deposit', "订金/报名费"),
('tuition', "学费"),
('transfer', "转班"),
('dropout', "退学"),
('refund', "退款"),)

#定义上课情况:
attendance_choices = (('checked', "已签到"),
('vacate', "请假"),
('late', "迟到"),
('absence', "缺勤"),
('leave_early', "早退"),)

#定义哪些成绩选择:
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'),)


class Department(models.Model):
"""
部门表
"""
name = models.CharField(max_length=32, verbose_name="部门名称")
count = models.IntegerField(verbose_name="人数", default=0) #IntegerField、一个整数类型。数值的范围是 -2147483648 ~ 2147483647。
#定义返回页面字符串:
def __str__(self):
return self.name

class UserProfile(models.Model):
"""
用户表
"""
username = models.EmailField(max_length=255, unique=True, ) #EmailField字符串类型,Django Admin以及ModelForm中提供验证机制、unique数据库中字段是否可以建立唯一索引
password = models.CharField(max_length=128)
name = models.CharField('名字', max_length=32) #name真实姓名
department = models.ForeignKey('Department', default=None, blank=True, null=True) #default=None数据库中字段的默认值、blank=True是前端可以是空、null=True是数据库中字段是否可以为空
mobile = models.CharField('手机', max_length=32, default=None, blank=True, null=True)
memo = models.TextField('备注', blank=True, null=True, default=None) #TextField长文本
date_joined = models.DateTimeField(auto_now_add=True) #date_joined加入日期、DateTimeField日期字段、auto_now_add新创建对象时自动添加当前日期时间。
is_active = models.BooleanField(default=True) #is_active是否激活、BooleanField布尔值类型
   def __str__(self):
     return self.name

class Customer(models.Model):
"""
客户表
"""
qq = models.CharField('QQ', max_length=64, unique=True, help_text='QQ号必须唯一')
qq_name = models.CharField('QQ昵称', max_length=64, blank=True, null=True) #qq_nameQQ昵称、
name = models.CharField('姓名', max_length=32, blank=True, null=True, help_text='学员报名后,请改为真实姓名') #name真实姓名
sex_type = (('male', '男'), ('female', '女'))
sex = models.CharField("性别", choices=sex_type, max_length=16, default='male', blank=True, null=True)
birthday = models.DateField('出生日期', default=None, help_text="格式yyyy-mm-dd", blank=True, null=True) #help_textAdmin中该字段的提示信息
phone = models.BigIntegerField('手机号', blank=True, null=True) #BigIntegerField长整型(有符号的) -9223372036854775808 ~ 9223372036854775807
source = models.CharField('客户来源', max_length=64, choices=source_type, default='qq') #source来源
introduce_from = models.ForeignKey('self', verbose_name="转介绍自学员", blank=True, null=True) #introduce_from介绍
course = MultiSelectField("咨询课程", choices=course_choices) #course课程
class_type = models.CharField("班级类型", max_length=64, choices=class_type_choices, default='fulltime')
customer_note = models.TextField("客户备注", blank=True, null=True, ) #customer_note客户备注
status = models.CharField("状态", choices=enroll_status_choices, max_length=64, default="unregistered",
help_text="选择客户此时的状态")
last_consult_date = models.DateField("最后跟进日期", auto_now_add=True) #last_consult_date最后跟进日期、DateField日期类型,日期格式为YYYY-MM-DD,相当于Python中的datetime.date的实例。
next_date = models.DateField("预计再次跟进时间", blank=True, null=True) #next_date预计再次跟进时间
consultant = models.ForeignKey('UserProfile', verbose_name="销售", related_name='customers', blank=True, null=True, ) #consultant课程顾问、verbose_nameAdmin中显示的字段名称、related_name反向操作时,使用的字段名,用于代替 【表名_set】 如: obj.表名_set.all()
class_list = models.ManyToManyField('ClassList', verbose_name="已报班级", blank=True) #class_list班级表多对多
   def __str__(self):
     return "{} - {}".format(self.qq,self.name)
class Campuses(models.Model):
"""
校区表
"""
name = models.CharField(verbose_name='校区', max_length=64)
address = models.CharField(verbose_name='详细地址', max_length=512, blank=True, null=True)


class ClassList(models.Model):
"""
班级表
"""
course = models.CharField("课程名称", max_length=64, choices=course_choices)
semester = models.IntegerField("学期") #semester学期
campuses = models.ForeignKey('Campuses', verbose_name="校区") #campuses校区
price = models.IntegerField("学费", default=10000)
memo = models.CharField('说明', blank=True, null=True, max_length=100)
start_date = models.DateField("开班日期")
graduate_date = models.DateField("结业日期", blank=True, null=True)
teachers = models.ManyToManyField('UserProfile', verbose_name="老师")
class_type = models.CharField(choices=class_type_choices, max_length=64, verbose_name='班额及类型', blank=True,
null=True)
class Meta: #Meta数据库中生成的表名称 默认 app名称 + 下划线 + 类名
unique_together = ("course", "semester", 'campuses') #unique_together联合唯一索引


class ConsultRecord(models.Model):
"""
跟进记录表
"""
customer = models.ForeignKey('Customer', verbose_name="所咨询客户") #customer客户
note = models.TextField(verbose_name="跟进内容...")
status = models.CharField("跟进状态", max_length=8, choices=seek_status_choices, help_text="选择客户此时的状态")
consultant = models.ForeignKey("UserProfile", verbose_name="跟进人", related_name='records') #consultant跟进的人
date = models.DateTimeField("跟进日期", auto_now_add=True)
delete_status = models.BooleanField(verbose_name='删除状态', default=False)

class Enrollment(models.Model):
"""
报名表
"""
why_us = models.TextField("为什么报名", max_length=1024, default=None, blank=True, null=True)
your_expectation = models.TextField("学完想达到的具体期望", max_length=1024, blank=True, null=True)
contract_agreed = models.BooleanField("我已认真阅读完培训协议并同意全部协议内容", default=False)
contract_approved = models.BooleanField("审批通过", help_text="在审阅完学员的资料无误后勾选此项,合同即生效", default=False)
enrolled_date = models.DateTimeField(auto_now_add=True, verbose_name="报名日期") #enrolled_date报名日期
memo = models.TextField('备注', blank=True, null=True)
delete_status = models.BooleanField(verbose_name='删除状态', default=False)
customer = models.ForeignKey('Customer', verbose_name='客户名称')
school = models.ForeignKey('Campuses')
enrolment_class = models.ForeignKey("ClassList", verbose_name="所报班级") #enrolment_class注册班级
class Meta:
unique_together = ('enrolment_class', 'customer')


class PaymentRecord(models.Model):
"""
缴费记录表
"""
pay_type = models.CharField("费用类型", choices=pay_type_choices, max_length=64, default="deposit")
paid_fee = models.IntegerField("费用数额", default=0)
note = models.TextField("备注", blank=True, null=True)
date = models.DateTimeField("交款日期", auto_now_add=True)
course = models.CharField("课程名", choices=course_choices, max_length=64, blank=True, null=True, default='N/A')
class_type = models.CharField("班级类型", choices=class_type_choices, max_length=64, blank=True, null=True,
default='N/A')
enrolment_class = models.ForeignKey('ClassList', verbose_name='所报班级', blank=True, null=True)
customer = models.ForeignKey('Customer', verbose_name="客户")
consultant = models.ForeignKey('UserProfile', verbose_name="销售")
delete_status = models.BooleanField(verbose_name='删除状态', default=False)
status_choices = (
(1, '未审核'),
(2, '已审核'),
)
status = models.IntegerField(verbose_name='审核', default=1, choices=status_choices)
confirm_date = models.DateTimeField(verbose_name="确认日期", null=True, blank=True)
confirm_user = models.ForeignKey(verbose_name="确认人", to='UserProfile', related_name='confirms', null=True,
blank=True) #to="UserProfile"关联用户信息表

class CourseRecord(models.Model):
"""课程记录表"""
day_num = models.IntegerField("节次", help_text="此处填写第几节课或第几天课程...,必须为数字")
date = models.DateField(auto_now_add=True, verbose_name="上课日期")
course_title = models.CharField('本节课程标题', max_length=64, blank=True, null=True)
course_memo = models.TextField('本节课程内容', max_length=300, blank=True, null=True)
has_homework = models.BooleanField(default=True, verbose_name="本节有作业")
homework_title = models.CharField('本节作业标题', max_length=64, blank=True, null=True)
homework_memo = models.TextField('作业描述', max_length=500, blank=True, null=True)
scoring_point = models.TextField('得分点', max_length=300, blank=True, null=True)
re_class = models.ForeignKey('ClassList', verbose_name="班级")
teacher = models.ForeignKey('UserProfile',related_name="course_records", verbose_name="讲师")
recorder = models.ForeignKey('UserProfile', verbose_name="记录者")
class Meta:
unique_together = ('re_class', 'day_num')

class StudyRecord(models.Model):
"""
学习记录
"""

attendance = models.CharField("考勤", choices=attendance_choices, default="checked", max_length=64)
score = models.IntegerField("本节成绩", choices=score_choices, default=-1)
homework_note = models.CharField(max_length=255, verbose_name='作业批语', blank=True, null=True)
date = models.DateTimeField(auto_now_add=True)
note = models.CharField("备注", max_length=255, blank=True, null=True)
homework = models.FileField(verbose_name='作业文件', blank=True, null=True, default=None)
course_record = models.ForeignKey('CourseRecord', verbose_name="某节课程")
student = models.ForeignKey('Customer', verbose_name="学员")
class Meta:
unique_together = ('course_record', 'student')
12、old_crm\local_settings.py:
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.mysql',
'NAME': "old_crm",
'HOST': "127.0.0.1",
'PORT': 3306,
'USER': "root",
'PASSWORD': "123",
}
}
13、old_crm\settings.py:
"""
Django settings for old_crm project.

Generated by 'django-admin startproject' using Django 1.11.27.

For more information on this file, see
https://docs.djangoproject.com/en/1.11/topics/settings/

For the full list of settings and their values, see
https://docs.djangoproject.com/en/1.11/ref/settings/
"""

import os

# Build paths inside the project like this: os.path.join(BASE_DIR, ...)
BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))


# Quick-start development settings - unsuitable for production
# See https://docs.djangoproject.com/en/1.11/howto/deployment/checklist/

# SECURITY WARNING: keep the secret key used in production secret!
SECRET_KEY = 'g15q%*@$fgj%t9-7)c7v#rg**latgcz7_7#p(f7+u)h0&%dob6'

# SECURITY WARNING: don't run with debug turned on in production!
DEBUG = True

ALLOWED_HOSTS = []


# Application definition

INSTALLED_APPS = [
'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
'crm.apps.CrmConfig', #检测注册的app
]

MIDDLEWARE = [
'django.middleware.security.SecurityMiddleware',
'django.contrib.sessions.middleware.SessionMiddleware',
'django.middleware.common.CommonMiddleware',
'django.middleware.csrf.CsrfViewMiddleware', #不需要注释
'django.contrib.auth.middleware.AuthenticationMiddleware',
'django.contrib.messages.middleware.MessageMiddleware',
'django.middleware.clickjacking.XFrameOptionsMiddleware',
]

ROOT_URLCONF = 'old_crm.urls'

TEMPLATES = [
{
'BACKEND': 'django.template.backends.django.DjangoTemplates',
'DIRS': [os.path.join ( BASE_DIR, 'templates' )] #模板存放的路径
,
'APP_DIRS': True,
'OPTIONS': {
'context_processors': [
'django.template.context_processors.debug',
'django.template.context_processors.request',
'django.contrib.auth.context_processors.auth',
'django.contrib.messages.context_processors.messages',
],
},
},
]

WSGI_APPLICATION = 'old_crm.wsgi.application'


# Database
# https://docs.djangoproject.com/en/1.11/ref/settings/#databases
#配置数据库信息
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.mysql',
'NAME': "old_crm",
'HOST': "127.0.0.1",
'PORT': 3306,
'USER': "root",
'PASSWORD': "123",
}
}


# Password validation
# https://docs.djangoproject.com/en/1.11/ref/settings/#auth-password-validators

AUTH_PASSWORD_VALIDATORS = [
{
'NAME': 'django.contrib.auth.password_validation.UserAttributeSimilarityValidator',
},
{
'NAME': 'django.contrib.auth.password_validation.MinimumLengthValidator',
},
{
'NAME': 'django.contrib.auth.password_validation.CommonPasswordValidator',
},
{
'NAME': 'django.contrib.auth.password_validation.NumericPasswordValidator',
},
]


# Internationalization
# https://docs.djangoproject.com/en/1.11/topics/i18n/

LANGUAGE_CODE = 'zh-hans' #更改语言

TIME_ZONE = 'Asia/Shanghai' #更改时区

USE_I18N = True

USE_L10N = True

USE_TZ = True


# Static files (CSS, JavaScript, Images)
# https://docs.djangoproject.com/en/1.11/howto/static-files/

STATIC_URL = '/static/'

STATICFILES_DIRS = [
os.path.join(BASE_DIR,'static') #配置文件路径
]

#导入本地设置文件的所有功能并捕获异常以防止不报错:
try:
from .local_settings import *
except ModuleNotFoundError:
pass
14、忽略文件.gitignore:
# Byte-compiled / optimized / DLL files
.idea/
__pycache__/
*.py[cod]
*$py.class

# C extensions
*.so

# Distribution / packaging
.Python
build/
develop-eggs/
dist/
downloads/
eggs/
.eggs/
lib/
lib64/
parts/
sdist/
var/
wheels/
pip-wheel-metadata/
share/python-wheels/
*.egg-info/
.installed.cfg
*.egg
MANIFEST

# PyInstaller
# Usually these files are written by a python script from a template
# before PyInstaller builds the exe, so as to inject date/other infos into it.
*.manifest
*.spec

# Installer logs
pip-log.txt
pip-delete-this-directory.txt

# Unit test / coverage reports
htmlcov/
.tox/
.nox/
.coverage
.coverage.*
.cache
nosetests.xml
coverage.xml
*.cover
*.py,cover
.hypothesis/
.pytest_cache/

# Translations
*.mo
*.pot

# Django stuff:
*.log
local_settings.py
db.sqlite3
db.sqlite3-journal

# Flask stuff:
instance/
.webassets-cache

# Scrapy stuff:
.scrapy

# Sphinx documentation
docs/_build/

# PyBuilder
target/

# Jupyter Notebook
.ipynb_checkpoints

# IPython
profile_default/
ipython_config.py

# pyenv
.python-version

# pipenv
# According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control.
# However, in case of collaboration, if having platform-specific dependencies or dependencies
# having no cross-platform support, pipenv may install dependencies that don't work, or not
# install all needed dependencies.
#Pipfile.lock

# PEP 582; used by e.g. github.com/David-OConnor/pyflow
__pypackages__/

# Celery stuff
celerybeat-schedule
celerybeat.pid

# SageMath parsed files
*.sage.py

# Environments
.env
.venv
env/
venv/
ENV/
env.bak/
venv.bak/

# Spyder project settings
.spyderproject
.spyproject

# Rope project settings
.ropeproject

# mkdocs documentation
/site

# mypy
.mypy_cache/
.dmypy.json
dmypy.json

# Pyre type checker
.pyre/
15、结构图:

crm项目包含django创建虚拟环境:

 16、数据库迁移命令:

python manage.py makemigrations

python manage.py migrate

17、创建超级用户命令:

python manage.py createsuperuser

用户名:root

邮箱:可以不填

密码(不能纯数字和纯英文):root1234

crm项目包含django创建虚拟环境:

 18、注册admin:

from django.contrib import admin
#导入crm下面的models模块:
from crm import models

# Register your models here.
# 注册model类到admin
admin.site.register(models.UserProfile)
19、运行django打开页面:
20、进入管理后台:

crm项目包含django创建虚拟环境:

 21、admin登录:用户名:root、密码:root1234

crm项目包含django创建虚拟环境:

 

 

 22、路由分发old_crm\urls.py:

"""old_crm URL Configuration

The `urlpatterns` list routes URLs to views. For more information please see:
https://docs.djangoproject.com/en/1.11/topics/http/urls/
Examples:
Function views
1. Add an import: from my_app import views
2. Add a URL to urlpatterns: url(r'^$', views.home, name='home')
Class-based views
1. Add an import: from other_app.views import Home
2. Add a URL to urlpatterns: url(r'^$', Home.as_view(), name='home')
Including another URLconf
1. Import the include() function: from django.conf.urls import url, include
2. Add a URL to urlpatterns: url(r'^blog/', include('blog.urls'))
"""
from django.conf.urls import url,include
from django.contrib import admin

urlpatterns = [
url(r'^admin/', admin.site.urls),
url(r"^",include("crm.urls")),
]
23、crm\urls:
from django.conf.urls import url
#导入视图函数:
from django.conf.urls import url
#导入视图函数:
from crm import views
urlpatterns = [
url(r'^login/',views.Login.as_view(),name="login"), #使用反向解析
url(r'^reg/',views.reg,name="reg"), #使用反向解析
]
24、设置登录视图函数crm\views:
from django.shortcuts import render,HttpResponse
#导入视图:
from django.views import View
#导入models:
from crm import models
# Create your views here.

#定义登录类:
class Login(View):
#定义get的获取方式功能:
def get(self,request,*args,**kwargs):
return render(request,"login.html")

#定义post获取方式功能:
def post(self,request,*args,**kwargs):
username = request.POST.get("username")
password = request.POST.get("password")
#判断用户名、密码、激活状态、
obj = models.UserProfile.objects.filter(username=username,password=password,is_active=True).first()
if obj:
return HttpResponse("ok")
return render(request,"login.html",{"error":"用户名或密码错误"})
25、old_crm\templates\login.html:
<!DOCTYPE html>
<html lang="zh-CN">
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no">
<title>登陆丨Sharelink</title>
{% load static %}
<link rel="stylesheet" href="{% static 'css/style.css' %}">
<body>
<div class="login-container">
<h1>ShareLink</h1>
<div class="connect">
<p>Link the world. Share to world.</p>
</div>
<form action="" method="post" novalidate>
{# 重定向csrf_token:#}
{% csrf_token %}
<div>
{# autocomplete自动进行填充、#}
<input type="text" name="username" class="username" placeholder="用户名" autocomplete="off" value="admin"/>
</div>
<div>
{# oncontextmenu是否可以右键和复制:#}
<input type="password" name="password" class="password" placeholder="密码" oncontextmenu="return false"
onpaste="return false"/>
</div>
{# 定义登录错误提示:#}
<div>{{ error }}</div>
<button type="submit">登 陆</button>
</form>
<a href="register.html">
<button type="button" class="register-tis">还有没有账号?</button>
</a>
</div>
</body>
<script src="http://www.jq22.com/jquery/1.11.1/jquery.min.js"></script>
<script src="{% static 'js/common.js' %}"></script>

<script src="{% static 'js/supersized.3.2.7.min.js' %}"></script>
<script src="{% static 'js/supersized-init.js' %}"></script>

<script src="{% static 'js/jquery.validate.min.js' %}"></script>
</html>
26、old_crm\templates\reg.html:
<!DOCTYPE html>
<html lang="zh-CN">
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no">
<title>登陆丨Sharelink</title>
{% load static %}
<link rel="stylesheet" href="{% static 'css/style.css' %}">
<style>

select {
width: 302px;
height: 42px;
line-height: 42px;
margin-top: 25px;
padding: 0 15px;
background: #2d2d2d;
background: rgba(45, 45, 45, .15);
-moz-border-radius: 6px;
-webkit-border-radius: 6px;
border-radius: 6px;
border: 1px solid rgba(255, 255, 255, .15);
-moz-box-shadow: 0 2px 3px 0 rgba(0, 0, 0, .1) inset;
-webkit-box-shadow: 0 2px 3px 0 rgba(0, 0, 0, .1) inset;
box-shadow: 0 2px 3px 0 rgba(0, 0, 0, .1) inset;
font-family: microsoft yahei, Helvetica, Arial, sans-serif;
font-size: 14px;
color: #fff;
text-shadow: 0 1px 2px rgba(0, 0, 0, .1);
-o-transition: all .2s;
-moz-transition: all .2s;
-webkit-transition: all .2s;
}
{#定义背景颜色:#}
option {
background-color: #ff8adf;
}
</style>

<body>
<div class="register-container">
<h1>ShareLink</h1>
<div class="connect">
<p>Link the world. Share to world.</p>
</div>
{# novalidate是控制页面字段校验:#}
<form action="" method="post" novalidate>
{# 定义保护机制:#}
{% csrf_token %}
<div>
{# <input type="text" name="username" class="username" placeholder="您的用户名" autocomplete="off"/>#}
{{ form_obj.username }}
{{ form_obj.username.errors.0 }}

</div>
<div>
{# <input type="password" name="password" class="password" placeholder="输入密码" oncontextmenu="return false"#}
{# onpaste="return false"/>#}

{{ form_obj.password }}
{{ form_obj.password.errors.0 }}

</div>
<div>
{# <input type="password" name="confirm_password" class="confirm_password" placeholder="再次输入密码"#}
{# oncontextmenu="return false" onpaste="return false"/>#}
{{ form_obj.re_password }}
{{ form_obj.re_password.errors.0 }}

</div>
<div>
{# <input type="text" name="phone_number" class="phone_number" placeholder="输入手机号码" autocomplete="off"#}
{# />#}
{{ form_obj.mobile }}
{{ form_obj.mobile.errors.0 }}

</div>
<div>
{{ form_obj.name }}
{{ form_obj.name.errors.0 }}

</div>
<div>
{{ form_obj.department }}
{{ form_obj.department.errors.0 }}

</div>
<button type="submit">注 册</button>
</form>
<a href="{% url 'login' %}">
<button type="button" class="register-tis">已经有账号?</button>
</a>
</div>
</body>

<script src="http://www.jq22.com/jquery/1.11.1/jquery.min.js"></script>
<script src="{% static 'js/common.js' %}"></script>

<script src="{% static 'js/supersized.3.2.7.min.js' %}"></script>
<script src="{% static 'js/supersized-init.js' %}"></script>

<script src="{% static 'js/jquery.validate.min.js' %}"></script>
</html>
27、定义form组件、注册功能、抛出异常:
#导入forms:
from django import forms

#导入抛出异常:
from django.core.exceptions import ValidationError

#导入hashlib模块:
import hashlib

#定义form组件:
class RegForm(forms.ModelForm):
#重新定义密码:validators自定义错误验证(列表类型),从而定制想要的验证规则、min_length长度、label提示信息
re_password = forms.CharField(min_length=6,widget=forms.PasswordInput(attrs={"placeholder":"确认密码"}),label="确认密码")
password = forms.CharField(min_length=6,widget=forms.PasswordInput(attrs={"placeholder":"输入密码"}),label="密码")
#定义def clean方法:
def clean(self):
#校验字段的唯一性:
self._validate_unique = True
#默认密码:
password = self.cleaned_data.get("password")
#确认密码:
re_password = self.cleaned_data.get("re_password")
#两次密码进行判断:
if password == re_password:
#保存之前加密:
md5 = hashlib.md5()
#注意编码bytes类型:
md5.update(password.encode("utf-8"))
#加密结果:
self.cleaned_data["password"] = md5.hexdigest()
return self.cleaned_data
#抛出异常:
#自己制定:
self.add_error("re_password","两次密码不一致!!")
raise ValidationError("两次密码不一致")
#form做配置:
class Meta:
#根据UserProfile表生成一些字段:
model = models.UserProfile
#__all__是使用所有的字段:
# fields = "__all__"
fields = ["username","password"]
#定义排除的字段:
exclude = ["memo","is_active"]
#设置全局所有字段:
widgets = {
"username":forms.TextInput(attrs={"placeholder":"请输入邮箱"}),
# "password":forms.PasswordInput(attrs={"placeholder":"请输入密码"}),
"mobile":forms.TextInput(attrs={"placeholder":"请输入手机号"}),
"name":forms.TextInput(attrs={"placeholder":"请输入姓名"}),
}
#自定义修改错误信息:
error_messages = {
"username":{}
}
#定义提示:
# labels = {
# "username":"xxx"
# }

#定义注册功能:
def reg(request):
#实例化form:
form_obj = RegForm()
if request.method == "POST":
form_obj = RegForm(request.POST)
#校验数据:
if form_obj.is_valid():
# print(form_obj.cleaned_data)
form_obj.save()
return redirect("login")
return render(request,"reg.html",{"form_obj":form_obj})
28、定义展示客户列表功能:
from django.conf.urls import url
#导入视图函数:
from crm import views
urlpatterns = [
url(r'^login/',views.Login.as_view(),name="login"), #使用反向解析
url(r'^reg/',views.reg,name="reg"), #使用反向解析
url(r'^customers/',views.customers,name="customers"), #使用反向解析
]
29、定义展示页面模板layout:
{% load static %}
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>路飞学城</title>
<link rel="shortcut icon" href="{% static 'imgs/luffy-study-logo.png' %} ">
<link rel="stylesheet" href="{% static 'plugins/bootstrap/css/bootstrap.css' %} "/>
<link rel="stylesheet" href="{% static 'plugins/font-awesome/css/font-awesome.css' %} "/>
<link rel="stylesheet" href="{% static 'css/commons.css' %} "/>
<link rel="stylesheet" href="{% static 'css/nav.css' %} "/>
<style>
body {
margin: 0;
}

.no-radius {
border-radius: 0;
}

.no-margin {
margin: 0;
}

.pg-body > .left-menu {
background-color: #EAEDF1;
position: absolute;
left: 1px;
top: 48px;
bottom: 0;
width: 220px;
border: 1px solid #EAEDF1;
overflow: auto;
}

.pg-body > .right-body {
position: absolute;
left: 225px;
right: 0;
top: 48px;
bottom: 0;
overflow: scroll;
border: 1px solid #ddd;
border-top: 0;
font-size: 13px;
min-width: 755px;
}

.navbar-right {
float: right !important;
margin-right: -15px;
}

.luffy-container {
padding: 15px;
}

.left-menu .menu-body .static-menu {

}

.left-menu .menu-body .static-menu .icon-wrap {
width: 20px;
display: inline-block;
text-align: center;
}

.left-menu .menu-body .static-menu a {
text-decoration: none;
padding: 8px 15px;
border-bottom: 1px solid #ccc;
color: #333;
display: block;
background: #efefef;
background: -webkit-gradient(linear, left bottom, left top, color-stop(0, #efefef), color-stop(1, #fafafa));
background: -ms-linear-gradient(bottom, #efefef, #fafafa);
background: -o-linear-gradient(bottom, #efefef, #fafafa);
filter: progid:dximagetransform.microsoft.gradient(startColorStr='#e3e3e3', EndColorStr='#ffffff');
-ms-filter: "progid:DXImageTransform.Microsoft.gradient(startColorStr='#fafafa',EndColorStr='#efefef')";
box-shadow: inset 0 1px 1px white;
}

.left-menu .menu-body .static-menu a:hover {
color: #2F72AB;
border-left: 2px solid #2F72AB;
}

.left-menu .menu-body .static-menu a.active {
color: #2F72AB;
border-left: 2px solid #2F72AB;
}
</style>
{% block css %} {% endblock %}
</head>
<body>

<div class="pg-header">
<div class="nav">
<div class="logo-area left">
<a href="#">
<img class="logo" src="{% static 'imgs/logo.svg' %}">
<span style="font-size: 18px;">路飞学城 </span>
</a>
</div>

<div class="left-menu left">
<a class="menu-item">资产管理</a>
<a class="menu-item">用户信息</a>
<a class="menu-item">路飞管理</a>
<div class="menu-item">
<span>使用说明</span>
<i class="fa fa-caret-down" aria-hidden="true"></i>
<div class="more-info">
<a href="#" class="more-item">管他什么菜单</a>
<a href="#" class="more-item">实在是编不了</a>
</div>
</div>
</div>

<div class="right-menu right clearfix">

<div class="user-info right">
<a href="#" class="avatar">
<img class="img-circle" src="{% static 'imgs/default.png' %}">
</a>

<div class="more-info">
<a href="#" class="more-item">个人信息</a>
<a href="#" class="more-item">注销</a>
</div>
</div>

<a class="user-menu right">
消息
<i class="fa fa-commenting-o" aria-hidden="true"></i>
<span class="badge bg-success">2</span>
</a>

<a class="user-menu right">
通知
<i class="fa fa-envelope-o" aria-hidden="true"></i>
<span class="badge bg-success">2</span>
</a>

<a class="user-menu right">
任务
<i class="fa fa-bell-o" aria-hidden="true"></i>
<span class="badge bg-danger">4</span>
</a>
</div>

</div>
</div>
<div class="pg-body">
<div class="left-menu">
<div class="menu-body">
<div class="static-menu">
<a href="/crm/depart/list/"><span class="icon-wrap"><i class="fa fa-map-o" aria-hidden="true"></i></span> 部门管理</a>
<a href="/crm/user/list/"><span class="icon-wrap"><i class="fa fa-map-o" aria-hidden="true"></i></span> 用户管理</a>
</div>
</div>
</div>
<div class="right-body">
<div>
<ol class="breadcrumb no-radius no-margin" style="border-bottom: 1px solid #ddd;">

<li><a href="#">首页</a></li>
<li class="active">客户管理</li>

</ol>
</div>
{% block content %} {% endblock %}
</div>
</div>


<script src="{% static 'js/jquery-3.3.1.min.js' %} "></script>
<script src="{% static 'plugins/bootstrap/js/bootstrap.js' %} "></script>
{% block js %} {% endblock %}
</body>
</html>
30、定义展示功能函数customers:
#定义展示功能:
def customers(request):
#拿到所有的客户:
all_customers = models.Customer.objects.all()
return render(request,"customers.html",{"customers":customers})
31、客户列表页面customers.html
{#继承layout模板:#}
{% extends "layout.html" %}
{% block content %}
<tabke class="table table-hover table-bordered">
<thead>
<tr>
<th>序号</th>
<th>QQ</th>
<th>姓名</th>
<th>性别</th>
<th>手机号</th>
<th>客户来源</th>
<th>咨询课程</th>
<th>班级类型</th>
<th>状态</th>
<th>最后跟进日期</th>
<th>销售</th>
<th>已报班级</th>
</tr>
</thead>
<tbody>
{% for customer in all_customers %}
<tr>
<td>{{ forloop.counter }}</td>
<td>{{ customer.qq }}</td>
<td>{{ customer.name }}</td>
<td>{{ customer.sex }}</td>
<td>{{ customer.phone }}</td>
<td>{{ customer.source }}</td>
<td>{{ customer.course }}</td>
<td>{{ customer.class_type }}</td>
<td>{{ customer.status }}</td>
<td>{{ customer.last_consult_date }}</td>
<td>{{ customer.consultant }}</td>
<td>{{ customer.class_list }}</td>
</tr>
{% endfor %}
</tbody>
</tabke>
{% endblock %}
32、admin下注册Customer、已报班级、校区:
from django.contrib import admin
#导入crm下面的models模块:
from crm import models

# Register your models here.
# 注册model类到admin
admin.site.register(models.UserProfile)
#注册Customer:
admin.site.register(models.Customer)
#注册已报班级ClassList:
admin.site.register(models.ClassList)
#注册校区Campuses:
admin.site.register(models.Campuses)
33、http://127.0.0.1:8000/admin/、

 

 34、保存:

crm项目包含django创建虚拟环境: