CRM項目css
業務html
權限前端
CRMpython
客戶關係管理系統(customer relationship management)mysql
使用人員:jquery
銷售 財務 班主任 講師 助教git
業務:github
登陸web
註冊sql
銷售:
客戶信息管理
展現 新增 編輯
跟進記錄的管理
展現 新增 編輯
報名記錄的管理
展現 新增 編輯
繳費記錄的管理
展現 新增 編輯
班主任
班級的管理
展現 新增 編輯
課程記錄的管理
展現 新增 編輯
學習記錄的管理
表結構
用戶表
客戶表
關聯銷售 能夠爲空 (爲空 是公戶 ,不爲空是私戶)
跟進記錄表
報名記錄表
繳費記錄表
校區
班級表
課程記錄表
學習記錄表
day53 永亮 正常 60
day53 安瑞超 遲到 61
day54 永亮 正常 60
day54 安瑞超 遲到 61
一、django建立虛擬環境:
show All:
二、 +:
三、 建立中:
四、 乾淨的虛擬環境:
五、 下載django:
六、建立數據庫:
七、pycharm配置git:
git init
八、導入忽略文件:
九、不要提交到git上並忽略再次出現:
十、crm\__init__.py:
#默認使用mysqldb的模塊 要使用pymysql替換mysqldb
import pymysql
pymysql.install_as_MySQLdb()
十一、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')
十二、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",
}
}
1三、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
1四、忽略文件.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/
1五、結構圖:
1六、數據庫遷移命令:
python manage.py makemigrations
python manage.py migrate
1七、建立超級用戶命令:
python manage.py createsuperuser
用戶名:root
郵箱:能夠不填
密碼(不能純數字和純英文):root1234
1八、註冊admin:
from django.contrib import admin
#導入crm下面的models模塊:
from crm import models
# Register your models here.
# 註冊model類到admin
admin.site.register(models.UserProfile)
1九、運行django打開頁面:
20、進入管理後臺:
2一、admin登陸:用戶名:root、密碼:root1234
2二、路由分發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")),
]
2三、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"), #使用反向解析
]
2四、設置登陸視圖函數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":"用戶名或密碼錯誤"})
2五、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" id="loginForm" 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>
2六、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" id="registerForm" 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"#}
{# id="number"/>#}
{{ 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 id="submit" 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>
2七、定義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})
2八、定義展現客戶列表功能:
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"), #使用反向解析
]
2九、定義展現頁面模板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})
3一、客戶列表頁面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 %}
3二、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)
3三、http://127.0.0.1:8000/admin/、
3四、保存: