Django-CRM後臺管理系統

crm總體流程

表結構css

from django.db import models # Create your models here.
from django.contrib.auth.models import AbstractUser from django.db import models from django.contrib import auth from django.core.exceptions import PermissionDenied from django.contrib.auth.models import AbstractBaseUser, PermissionsMixin, BaseUserManager, User from django.utils.translation import ugettext_lazy as _ from multiselectfield import MultiSelectField #安裝:pip install django-multiselectfield,針對choices多選用的

from django.utils.safestring import mark_safe course_choices = (('LinuxL', '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 UserInfo(AbstractUser): #銷售,班主任,講師,三哥
    telephone = models.CharField(max_length=32,null=True) roles = models.ManyToManyField('Role') def __str__(self): return self.username # 角色表
class Role(models.Model): title = models.CharField(max_length=32) permissions = models.ManyToManyField('Permission') def __str__(self): return self.title # 系統全部的url
class Permission(models.Model): title = models.CharField(max_length=32) url = models.CharField(max_length=128) def __str__(self): return self.title class Customer(models.Model): """ 客戶表(最開始的時候你們都是客戶,銷售就不停的撩你,你還沒交錢就是個客戶) """ qq = models.CharField(verbose_name='QQ', max_length=64, unique=True, help_text='QQ號必須惟一') qq_name = models.CharField('QQ暱稱', max_length=64, blank=True, null=True) name = models.CharField('姓名', max_length=32, blank=True, null=True, help_text='學員報名後,請改成真實姓名') sex_type = (('male', ''), ('female', '')) sex = models.CharField("性別", choices=sex_type, max_length=16, default='male', blank=True, null=True) #存的是male或者female,字符串
    birthday = models.DateField('出生日期', default=None, help_text="格式yyyy-mm-dd", blank=True, null=True) phone = models.CharField('手機號', blank=True, null=True,max_length=32) # phone = models.CharField('手機號', blank=True, null=True)
    source = models.CharField('客戶來源', max_length=64, choices=source_type, default='qq') introduce_from = models.ForeignKey('self', verbose_name="轉介紹自學員", blank=True, null=True)  #self指的就是本身這個表,和下面寫法是同樣的效果


    # introduce_from = models.ForeignKey('Customer', verbose_name="轉介紹自學員", blank=True, null=True,on_delete=models.CASCADE)
    course = MultiSelectField("諮詢課程", choices=course_choices) #多選,而且存成一個列表的格式
    # course = models.CharField("諮詢課程", choices=course_choices) #若是你不想用上面的多選功能,可使用Charfield來存
    class_type = models.CharField("班級類型", max_length=64, choices=class_type_choices, default='fulltime') customer_note = models.TextField("客戶備註", blank=True, null=True, ) status = models.CharField("狀態", choices=enroll_status_choices, max_length=64, default="unregistered",help_text="選擇客戶此時的狀態") #help_text這種參數基本都是針對admin應用裏面用的
 date = models.DateTimeField("諮詢日期", auto_now_add=True) last_consult_date = models.DateField("最後跟進日期", auto_now_add=True) #考覈銷售的跟進狀況,若是多天沒有跟進,會影響銷售的績效等
    next_date = models.DateField("預計再次跟進時間", blank=True, null=True) #銷售本身大概記錄一下本身下一次會何時跟進,也沒啥用

    #用戶表中存放的是本身公司的全部員工。
    consultant = models.ForeignKey('UserInfo', verbose_name="銷售", blank=True, null=True) #一個客戶能夠報多個班,報個脫產班,再報個週末班等,因此是多對多。
    class_list = models.ManyToManyField('ClassList', verbose_name="已報班級", ) def __str__(self): return "%s:%s"%(self.name,self.qq)  #主要__str__最好是個字符串昂,否則你會遇到不少的坑,還有咱們返回的這兩個字段填寫數據的時候必須寫上數據,必然相加會報錯,null類型和str類型不能相加等錯誤信息。

    def get_classlist(self):  #當咱們經過self.get_classlist的時候,就拿到了全部的班級信息,前端顯示的時候用
 l=[] for cls in self.class_list.all(): l.append(str(cls)) # return mark_safe(",".join(l)) #純文本,不用mark_safe也能夠昂
        return ",".join(l) #純文本,不用mark_safe也能夠昂

class Campuses(models.Model): """ 校區表 """ name = models.CharField(verbose_name='校區', max_length=64) address = models.CharField(verbose_name='詳細地址', max_length=512, blank=True, null=True) def __str__(self): return self.name class ClassList(models.Model): """ 班級表 """ course = models.CharField("課程名稱", max_length=64, choices=course_choices) semester = models.IntegerField("學期") #python20期等
    campuses = models.ForeignKey('Campuses', verbose_name="校區",on_delete=models.CASCADE) 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) #不必定何時結業,哈哈,因此可爲空

    #contract = models.ForeignKey('ContractTemplate', verbose_name="選擇合同模版", blank=True, null=True,on_delete=models.CASCADE)
    teachers = models.ManyToManyField('UserInfo', verbose_name="老師") #對了,還有一點,若是你用的django2版本的,那麼外鍵字段都須要自行寫上on_delete=models.CASCADE
 class_type = models.CharField(choices=class_type_choices, max_length=64, verbose_name='班額及類型', blank=True,null=True) class Meta: unique_together = ("course", "semester", 'campuses') def __str__(self): return "{}{}({})".format(self.get_course_display(), self.semester, self.campuses) class ConsultRecord(models.Model): """ 跟進記錄表 """ customer = models.ForeignKey('Customer', verbose_name="所諮詢客戶") note = models.TextField(verbose_name="跟進內容...") status = models.CharField("跟進狀態", max_length=8, choices=seek_status_choices, help_text="選擇客戶此時的狀態") consultant = models.ForeignKey("UserInfo", verbose_name="跟進人", related_name='records') date = models.DateTimeField("跟進日期", auto_now_add=True) delete_status = models.BooleanField(verbose_name='刪除狀態', default=False) # def __str__(self):
    # return self.consultant
model

一、繼承django內置的user表並擴展字段

django內置的user表中給咱們提供了username,passwordhtml

from django.contrib.auth.models import AbstractUser # 用戶表
class UserInfo(AbstractUser): telephone = models.CharField(max_length=32,null=True)  # 該字段不能夠爲空

二、基於form組件實現註冊

定義form組件的驗證規則並生成標籤前端

from django import forms # form組件
from app01 import models from django.core.exceptions import ValidationError # 錯誤信息
from django.core.validators import RegexValidator # django內置的正則

# 用戶註冊form
class Myform(forms.Form): username=forms.CharField( max_length=32, min_length=6, label="用戶名", error_messages={ "required": "用戶名不能爲空", "min_length": "用戶名不能少於6位", "max_length":"用戶名不能超過32位", }, widget=forms.widgets.TextInput(attrs={"placeholder": "請輸入用戶名"}) ) password=forms.CharField( max_length=10, min_length=6, label="密碼", error_messages={ "required": "密碼不能爲空", "min_length": "密碼不能少於6位", "max_length": "密碼不能超過32位", }, widget=forms.widgets.PasswordInput(attrs={"placeholder":"請輸入密碼"}) ) r_password = forms.CharField( max_length=10, min_length=6, label="確認密碼", error_messages={ "required": "確認密碼不能爲空", "min_length": "確認密碼不能少於6位", "max_length": "確認密碼不能超過32位", }, widget=forms.widgets.PasswordInput(attrs={"placeholder":"請確認密碼"}) ) # 給手機號定義校驗規則
    telephone = forms.CharField( max_length=11, label="電話", error_messages={ "required": "電話不能爲空", "max_length": "電話不能超過11位", }, widget=forms.widgets.TextInput(attrs={"placeholder": "請輸入11位的手機號"}), validators=[RegexValidator(r'^(13[0-9]|15[012356789]|17[678]|18[0-9]|14[57])[0-9]{8}$', '電話必須以13/15/17/18/14/開頭,且必須知足11位')], ) # 批量添加樣式
    def __init__(self,*args,**kwargs): super().__init__(*args,**kwargs) for field in self.fields: # 取每一個字段,給每一個字段添加樣式
            self.fields[field].widget.attrs.update({"class": "form-control"}) # 局部鉤子判斷用戶名是否存在
    def clean_username(self): username=self.cleaned_data.get("username") # 判斷用戶名是否存在
        if models.UserInfo.objects.filter(username=username).exists(): raise ValidationError("用戶名已經存在") else: # 將驗證經過的信息返回
            return username # 局部鉤子判斷手機號是否已經註冊
    def clean_phone(self): phone=self.cleaned_data.get("phone") # 判斷手機號是否已經註冊
        if models.UserInfo.objects.filter(phone=phone).exists(): raise ValidationError("該手機號已經註冊!!!") else: # 將驗證經過的信息返回
            return phone # 全局鉤子判斷兩次輸入的密碼是否一致
    def clean(self): password_value = self.cleaned_data.get('password') r_password_value = self.cleaned_data.get('r_password') if password_value == r_password_value: return self.cleaned_data  # 全局鉤子要返回全部的數據
        else: self.add_error('r_password', '兩次密碼不一致')
View Code

實例化Myform對象傳給前端進行渲染python

# 註冊
def register(request): # 實例化Myform對象
    form_obj = Myform() if request.method=="GET": return render(request,"register.html",{"form_obj":form_obj}) else: form_obj=Myform(data=request.POST) if form_obj.is_valid(): # 全部信息都驗證完,經過的認證信息都在cleaned_data裏面
            dic = form_obj.cleaned_data # 將不須要寫入數據庫的信息刪除
            dic.pop("r_password") # 用戶註冊信息寫入數據庫,(這種建立是密文密碼)
            models.UserInfo.objects.create_user(**dic) return redirect("login") else: return render(request,"register.html",{"form_obj":form_obj})
View Code

前端頁面jquery

{% load static %} <!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <link rel="stylesheet" href="{% static "bootstrap-3.3.7-dist/css/bootstrap.min.css" %}">
</head>
<body>
<div class="container">
    <div class="row">

        <div class="col-md-6 col-md-offset-3" style="margin-top: 150px">
            <div class="panel panel-primary">
                <div class="panel-heading">
                    <h3 class="panel-title">用戶註冊</h3>
                </div>
                <div class="panel-body">
                    <div>
                        <form action="{% url "register" %}" method="post" novalidate> {% csrf_token %} {% for foo in form_obj %} <div class="form-group {% if foo.errors.0 %} has-error {% endif %}">
                                    <label for="{{ foo.id_for_label }}">{{ foo.label }}</label> {{ foo }}{{ foo.errors.0 }} </div> {% endfor %} <input type="submit" value="註冊" class="btn btn-success pull-right">
                        </form>

                    </div>
                </div>
            </div>

        </div>

    </div>

</div>
</body>
</html>
View Code

三、登陸認證基於ajax請求發送|附加驗證碼

驗證碼:生成的驗證碼保存在session中,方便校驗web

from io import BytesIO  # 在內存中開闢空間
from PIL import Image,ImageDraw,ImageFont # 驗證碼模塊 # 生成驗證碼
def code(request): f = BytesIO() # 建立圖片
    img = Image.new(mode="RGB", size=(120, 30), color=(random.randint(0, 255), random.randint(0, 255), random.randint(0, 255))) # 建立畫筆
    draw = ImageDraw.Draw(img, mode='RGB') draw.arc((0, 0, 30, 30), 0, 360, fill="red") # 隨機生成4位驗證碼
    str_code = ''
    for i in range(4): a1 = chr(random.randint(65, 90)) a2 = chr(random.randint(97, 122)) a3 = random.randint(0, 9) str_num = random.choice([a1, a2, str(a3)]) # 每次生成的隨機數保存在列表中
        str_code+=str_num # 選擇字體
        font = ImageFont.truetype("Monaco.ttf", 28) # 寫字
        draw.text([i * 35, 0], str_num, (random.randint(0, 255), random.randint(0, 255), random.randint(0, 255)), font=font) print(str_code) # 將驗證碼存在session中,方便後面取出來與用戶輸入的進行驗證
    request.session["str_code"] = str_code # 將圖片保存在內存中
    img.save(f, format="png") # 讀取內存中的圖片
    data = f.getvalue() return HttpResponse(data)
View Code

登陸認證ajax

# 登陸認證
def login(request): if request.method=="GET": return render(request, "login.html") else: username = request.POST.get("name") password = request.POST.get("pwd") str_code = request.POST.get('code') # 從session中取出事先咱們保存好的驗證碼
        code = request.session['str_code'] # 驗證碼錯誤
        if str_code.upper()!=code.upper(): dic = {"status":"code"} # 驗證碼錯誤直接給ajax回覆一個json格式的字符串
            return JsonResponse(dic) else: # 判斷用戶輸入的用戶名和密碼與數據庫中的是否匹配
            user_obj = auth.authenticate(username=username, password=password) if user_obj and str_code.upper()==code.upper(): # 登陸成功設置session
 auth.login(request, user_obj) # 獲取該用戶的全部權限並保存在session中,並去重
                permissions = models.Permission.objects.filter(role__userinfo__username=user_obj.username).distinct() # 將該用戶能夠訪問的全部url都添加到session中
                permisson_list = [i.url for i in permissions] request.session["permisson_list"] = permisson_list # print(permisson_list)
                # ['/home/', '/customers/', '/my_customers/', '/add_customers/', '/edit_customers/', '/delete_customers/(\\d+)/', '/show_file/', '/update_file/(\\d+)/', '/update_add/(\\d+)/', '/update_edit/(\\d+)/(\\d+)/']
                dic = {"status":"correct","url":reverse("home")} return JsonResponse(dic) else: # 帳號密碼錯誤
                dic = {"status":"userinfo"} return JsonResponse(dic)
View Code

ajax請求的頁面數據庫

驗證碼顯示是一個img標籤,咱們讓它單獨去請求一個視圖函數,並將圖片返回django

{% load static %} <!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <link rel="stylesheet" href="{% static "css/css.css" %}">
    <link rel="stylesheet" href="{% static "bootstrap-3.3.7-dist/css/bootstrap.min.css" %}">
</head>
<body>
<div class="change">
    <div class="container ">
    <div class="row">
        <div class="col-md-6 col-md-offset-3">

                <div class="panel panel-primary" style="margin-top: 150px">

                    <div class="panel-heading change_color">客戶關係管理系統</div>
                  <div class="panel-body ">
                    <form class="form-horizontal"> {% csrf_token %} <div class="form-group">
                        <h3 id="h3" style="color: red"></h3>
                        <label for="name" class="col-sm-3 control-label change_color">帳號</label>

                        <div class="col-sm-8">
                            <input type="text" class="form-control" id="name" placeholder="帳號" name="username">
                            <span id="in_span" style="color: red"></span>

                        </div>
                        <span class="col-sm-3 s1"></span>
                    </div>
                    <div class="form-group">
                        <label for="pwd" class="col-sm-3 control-label change_color">密碼</label>

                        <div class="col-sm-8">
                            <input type="password" class="form-control" id="pwd" placeholder="密碼" name="password">
                        </div>

                    </div>

                    <div class="form-group">
                        <label for="yzm" class="col-sm-3 control-label change_color">驗證碼</label>

                        <div class="col-sm-5">
                            <input type="text" class="form-control" id="yzm" placeholder="驗證碼" name="code">
                            <span id="in_yzm" style="color: red"></span>
                        </div>
                        <div >
                            <img src="{% url "code" %}" id="auth_code" alt="">
                        </div>
                    </div>


                    <div class="form-group">
                        <div class="col-sm-offset-3 col-sm-9">
                            <div class="checkbox">
                                <label class="change_color">
                                    <input type="checkbox"> 是否記住密碼 </label>
                            </div>
                        </div>
                    </div>
                    <div class="form-group">
                        <div class="col-md-8 col-sm-offset-3">
                            <button type="button" class="btn btn-success change_color" id="login_in">登陸</button>
                            <a href="{% url "register" %}" class="btn btn-danger pull-right change_color"
                               >註冊</a>
                        </div>
                    </div>

                </form>

                  </div>
                </div>

        </div>

    </div>

</div>
</div>

</body>
<script src="{% static "jquery-3.4.1.js" %}"></script>
<script src="{% static "bootstrap-3.3.7-dist/js/bootstrap.min.js" %}"></script>
<script>
    // 判斷用戶名密碼是否爲空
 $("#login_in").click(function () { var name = $("#name").val(); var pwd = $("#pwd").val(); var code = $("#yzm").val(); var csrf_data=$("[name=csrfmiddlewaretoken]").val(); if (!name.trim()){ $("#in_span").text("用戶名不能位空!"); return false; } $.ajax({ url:"{% url "login" %}", type:"post", data:{ name:name, pwd:pwd, code:code, csrfmiddlewaretoken:csrf_data, }, success:function (response) { if (response["status"]==="code"){ $("#in_yzm").text("驗證碼有誤!"); return false }else { if(response['status']==="correct"){ var href = location.search.slice(6); if (href){ location.href=href }else { location.href={% url "home" %} } }else { $("#h3").text("帳號或密碼有誤!") } } } }) }); // 點擊刷新驗證碼
 $("#auth_code").click(function () { $("#auth_code")[0].src+='?' }) </script>
</html>
View Code

 

登陸成功後顯示登陸用戶的信息:json

從request.user中取出先要展現的信息
{{ request.user.username }}

四、退出和修改密碼

退出登陸:

咱們爲了保存登陸狀態,因此咱們在登錄的時候經過django內置的anth模塊設置了session

因此咱們點擊退出按鈕就須要清除用戶的登陸狀態

from django.contrib import auth  # django認證 # 退出
def logout(request): # 清空session
 auth.logout(request) return redirect("login")

修改密碼:

一、判斷舊密碼是否正確;

二、判斷新密碼與確認密碼是否一致;

三、手機號碼咱們在form組件時已經作了認證,前兩項都判斷正確就須要咱們將數據庫中的舊密碼替換成咱們的修改密碼;

request中的user對象給咱們提供了校驗舊密碼和修改密碼以及保存密碼的方法

def set_password(request): if request.method == "GET": return render(request, "set_password.html") else: dic = request.POST.dict() dic.pop("csrfmiddlewaretoken") old_password = dic["old_password"] new_password = dic['new_password'] r_new_password = dic['r_new_password'] # 判斷用戶輸入的舊密碼是否與數據庫中的一致
        if request.user.check_password(old_password): if new_password != r_new_password: return render(request,"set_password.html",{"new_password":"兩次輸入的密碼不一致!"}) else: # 修改密碼
 request.user.set_password(new_password) request.user.save() return redirect("login") else: return render(request,"set_password.html",{"old_password":"舊密碼不正確!"})
View Code

五、自定義分頁器

能夠保存搜索條件

#自定義分頁 #官方推薦,頁碼數爲奇數
class PageNation: def __init__(self,base_url,current_page_num,total_counts,request,per_page_counts=10,page_number=5,): ''' :param base_url: 分頁展現信息的基礎路徑 :param current_page_num: 當前頁頁碼 :param total_counts: 總的數據量 :param per_page_counts: 每頁展現的數據量 :param page_number: 顯示頁碼數 ''' self.base_url = base_url self.current_page_num = current_page_num self.total_counts = total_counts self.per_page_counts = per_page_counts self.page_number = page_number self.request = request try: self.current_page_num = int(self.current_page_num) except Exception: self.current_page_num = 1
        if self.current_page_num < 1: self.current_page_num = 1 half_page_range = self.page_number // 2
        # 計算總頁數
        self.page_number_count, a = divmod(self.total_counts, self.per_page_counts) if a: self.page_number_count += 1


        if self.current_page_num > self.page_number_count: self.current_page_num = self.page_number_count if self.page_number_count <= self.page_number: self.page_start = 1 self.page_end = self.page_number_count else: if self.current_page_num <= half_page_range:  #2
                self.page_start = 1 self.page_end = page_number  #5
            elif self.current_page_num + half_page_range >= self.page_number_count: self.page_start = self.page_number_count - self.page_number + 1 self.page_end = self.page_number_count else: self.page_start = self.current_page_num - half_page_range self.page_end = self.current_page_num + half_page_range import copy from django.http.request import QueryDict self.params = copy.deepcopy(request.GET) # ?condition = qq & wd = 1 & page = 3
        # params['page'] = current_page_num
        # query_str = params.urlencode()
    #數據切片依據,起始位置
 @property def start_num(self): start_num = (self.current_page_num - 1) * self.per_page_counts return start_num #數據切片依據,終止位置
 @property def end_num(self): end_num = self.current_page_num * self.per_page_counts return end_num # 拼接HTMl標籤
    def page_html(self): tab_html = '' tab_html += '<nav aria-label="Page navigation" class="pull-right"><ul class="pagination">'
        #首頁
        self.params['page'] = 1 showye = '<li><a href="{0}?{1}" aria-label="Previous" ><span aria-hidden="true">首頁</span></a></li>'.format(self.base_url,self.params.urlencode()) tab_html += showye # 上一頁
        if self.current_page_num == 1: previous_page = '<li disabled><a href="#" aria-label="Previous" ><span aria-hidden="true">&laquo;</span></a></li>'
        else: self.params['page'] = self.current_page_num - 1 previous_page = '<li><a href="{0}?{1}" aria-label="Previous" ><span aria-hidden="true">&laquo;</span></a></li>'.format( self.base_url,self.params.urlencode()) tab_html += previous_page #循環生成頁碼標籤
        for i in range(self.page_start, self.page_end + 1): # request.GET {condition: qq, wd: 1,'page':1} request.GET.urlencode() condition=qq&wd=1&page=4
 self.params['page'] = i # {condition: qq, wd: 1,'page':1} urlencode() -- condition=qq&wd=1&page=4

            if self.current_page_num == i: one_tag = '<li class="active"><a href="{0}?{2}">{1}</a></li>'.format(self.base_url, i,self.params.urlencode()) #?condition=qq&wd=1&page=3
            else: one_tag = '<li><a href="{0}?{2}">{1}</a></li>'.format(self.base_url, i,self.params.urlencode()) tab_html += one_tag # 下一頁
        if self.current_page_num == self.page_number_count: next_page = '<li disabled><a href="#" aria-label="Next"><span aria-hidden="true">&raquo;</span></a></li>'
        else: self.params['page'] = self.current_page_num + 1 next_page = '<li><a href="{0}?{1}" aria-label="Next"><span aria-hidden="true">&raquo;</span></a></li>'.format(self.base_url, self.params.urlencode()) tab_html += next_page # 尾頁
        self.params['page'] = self.page_number_count weiye = '<li><a href="{0}?{1}" aria-label="Previous" ><span aria-hidden="true">尾頁</span></a></li>'.format( self.base_url, self.params.urlencode()) tab_html += weiye tab_html += '</ul></nav>'

        return tab_html
page

六、公有|私有客戶信息展現|搜索|批量處理

 樣式:

數據展現分公有和私有客戶的信息展現:

公有客戶銷售字段爲空;

私有客戶銷售字段爲當前登陸用戶;

由於數據展現和搜索都走get請求,因此咱們用同一個視圖函數便可;

搜索:

一、獲取用戶選擇的搜索條件及用戶輸入的搜索內容
二、去數據庫中查找匹配項,返回給前端頁面

select提交時咱們經過choice來獲取用戶選擇的內容:

搜索時記得作成模糊匹配__contains

choice = request.GET.get("choice",'')  # 用戶選擇的搜索條件
wd = request.GET.get("wd",'')       # 用戶輸入的搜索內容
print(choice,wd)    # qq 362    經過choice獲取用戶選擇的搜索條件

這裏注意一個Q查詢的高級用法:

from django.db.models import F,Q,Max,Min,Avg # 實例化一個Q對象
q = Q() # 必須是元組,由於只接收一個參數
q.children.append((choice,wd)) # choice是選擇條件,wd是搜索內容
 customers_obj = models.Customer.objects.filter(consultant__isnull=True).customers_obj.filter(q)

批量處理:

一、提取用戶發來的動做和批量選擇的id
二、提早定義好這些動做的函數,利用反射執行對應的操做

批量操做的js代碼:

$("#choice").click(function () {
    // 獲取當前選中的狀態true或false
    var state = $(this).prop("checked");
    $("[name=selected_id]").prop("checked",state)
    })

總體代碼:

# 公有和私有客戶信息展現
class CustomerView(View): # get請求
    def get(self,request): # 獲取用戶選擇的和用戶輸入的搜索內容,默認爲空,不選擇和不輸入get的返回結果爲None
        choice = request.GET.get("choice",'') wd = request.GET.get("wd",'') print(choice,wd)   # qq 362
        # 在查詢時設置成包含的狀況contains--->關鍵字
        choice = choice + '__contains'
        # 默認get第一次請求第一頁
        current_page_num = request.GET.get('page', 1) # 判斷請求的路徑是哪一個
        if request.path == reverse('customers'): # 公有客戶 銷售爲空
            customers_obj = models.Customer.objects.filter(consultant__isnull=True) else: # 私有客戶 銷售是當前登陸的用戶,字段名=對象--->字段_id=具體id
            customers_obj = models.Customer.objects.filter(consultant=request.user) # 判斷用戶是否輸入了搜索條件
        if wd: # 實例化一個Q對象
            q = Q() # 指定鏈接條件,默認是and
            # q.connector = "or"
            # 必須是元組,由於只接收一個參數
 q.children.append((choice,wd)) # q.children.append(('name__contains', '小'))
            # 名字中包含wd字段的全部信息 qq__contains 66 name__contains 小
            # models.Customer.objects.filter(name__contains=wd)
            # if request.path != reverse('customers'):
            # customers_obj = models.Customer.objects.filter(consultant=request.user)
            customers_obj = customers_obj.filter(q) # customers_obj = models.Customer.objects.filter(consultant__isnull=True).filter(q)
        else: # 全部銷售爲空的,就是公共客戶
            # customers_obj = models.Customer.objects.filter(consultant__isnull=True)
            customers_obj = customers_obj # 每頁展現的數據量
        page_counts = 5
        # 頁碼數
        page_number = 7
        # 總數據
        total_count = customers_obj.count() # 判斷查詢數據是否爲空
        if total_count: # 實列化分頁的類
            page_obj = page.PageNation(request.path, current_page_num, total_count, request,page_counts, page_number) # 切片:從總數據中每次切出多少條數據展現在頁面上
            customers_obj = customers_obj.order_by('-pk')[page_obj.start_num:page_obj.end_num] ret_html = page_obj.page_html() # 根據請求的路徑返回對應的頁面
            path = request.path if path == reverse("customers"): return render(request,"customers.html",{"customers_obj":customers_obj,"ret_html":ret_html,'path':path}) else: return render(request,'my_customers.html',{"my_customers_obj":customers_obj,"ret_html":ret_html,'path':path}) else: return render(request,"404.html") def post(self,request): # 提取用戶發來的動做和批量選擇的id
        action = request.POST.get("action") self.data = request.POST.getlist("selected_id") # 用getlist獲取用戶選擇的多條數據
        print(action,self.data)   # batch_delete ['107', '103']
        # 判斷這個動做是否在這個對象中
        if hasattr(self,action): func = getattr(self,action) if callable(func): func(request) # 判斷當前頁面是公戶仍是私護
                if request.path == reverse("customers"): return redirect("customers") else: return redirect("my_customers") else: return render(request, "404.html") else: return render(request, "404.html") # 批量刪除
    def batch_delete(self,request): # self.data值是一個範圍,pk值在這個範圍內的都刪除
        models.Customer.objects.filter(pk__in=self.data).delete() # 批量更新
    def batch_update(self,request): models.Customer.objects.filter(pk__in=self.data).update(status="已報名") # 批量公戶轉私護
    def batch_reverse_gs(self,request): batch_customer = models.Customer.objects.filter(pk__in=self.data) ret = [] for i in batch_customer: if i.consultant: ret.append(i) else: # 經過model對象更新數據
                i.consultant=request.user # 調用save纔會保存
 i.save() batch_customer.update(consultant=request.user) # 批量私護轉公戶
    def batch_reverse_sg(self,request): models.Customer.objects.filter(pk__in=self.data).update(consultant=None)
View Code

七、基於modelform客戶信息的增刪改

增:

一、獲取用戶輸入的信息
二、將用戶輸入的信息request.POST交給modelform作校驗
三、校驗成功經過save方法直接保存到數據庫

生成標籤

# modelform生成添加頁面
class MyModelForm(forms.ModelForm): class Meta: model = models.Customer    # 指定哪張表
        fields="__all__"
    def __init__(self,*args,**kwargs): super().__init__(*args,**kwargs) from multiselectfield.forms.fields import MultiSelectFormField for field in self.fields.values(): # 不給哪一個字段添加樣式
            if not isinstance(field, MultiSelectFormField): field.widget.attrs.update({ 'class': 'form-control', })

視圖函數

# 添加客戶信息
def add_customers(request): model_obj = MyModelForm() if request.method=="GET": return render(request,"add_customers.html",{"model_obj":model_obj}) else: # 將用戶輸入的信息交給Mymodel對象作校驗
        model_obj = MyModelForm(request.POST) # 若是校驗成功
        if model_obj.is_valid(): # 將用戶輸入的全部信息保存到數據庫,數據會一一對應保存
 model_obj.save() return redirect("customers") else: return render(request, "add_customers.html", {"model_obj": model_obj})

前端頁面

{% extends "template.html" %} {% load static %} {% block countent %} <div class="container">
    <div class="row">

        <div class="col-md-6 col-md-offset-3">
                <div class="panel-heading">
                    <h3 class="panel-title">添加信息</h3>
                </div>
                <div class="panel-body">
                    <form action="{% url "add_customers" %}" method="post" novalidate> {% csrf_token %} {% for filed in model_obj %} <label for="{{ filed.id_for_label }}">{{ filed.label }}</label> {{ filed }}{{ filed.errors.0 }} {% endfor %} <input type="submit" value="提交" class="btn btn-primary pull-right">
                    </form>
                </div>
        </div>
    </div>
</div> {% endblock %}
View Code

刪:

一、前端發送post請求時在請求的url後面攜帶要刪除數據的id
二、對應的視圖函數到數據庫中查到指定的id刪除便可
<a href="{% url "delete_customers" customers.pk %}"class="btn btn-danger btn-sm">刪除</a>
# 刪除客戶信息
def delete_customers(request,pk): models.Customer.objects.filter(pk=pk).delete() return redirect("customers")

改:

一、前端發送post請求時在請求的url後面攜帶要刪除數據的id
二、對應的視圖函數查找該id的對像,返回給前端頁面,
三、在前端修改完數據後走的post請求,直接將用戶輸入的傳給modelform並指定instance=要編輯的對象,若是不寫instance表明添加,
四、modelform校驗完數據經過save保存到數據庫
<a href="{% url "edit_customers" customers.pk %}"class="btn btn-primary btn-sm">編輯</a>
# 編輯客戶信息
def edit_customers(request,pk): if request.method=="GET": edit_obj = models.Customer.objects.filter(pk=pk).first() model_obj = MyModelForm(instance=edit_obj) # 指定編輯哪一個信息
        return render(request,"edit_customers.html",{"model_obj":model_obj}) else: edit_obj = models.Customer.objects.filter(pk=pk).first() # instance指定該字段是更新而不是添加,並將數據進行驗證
        model_obj = MyModelForm(request.POST,instance=edit_obj) if model_obj.is_valid(): # 更新數據
 model_obj.save() return redirect("customers") else: # 檢驗不經過
            return render(request,"edit_customers.html",{"model_obj":model_obj})
相關文章
相關標籤/搜索