Django+前端+MySQL 案例

一.项目演示

演示视频

二.代码层级

三.部分代码示例

account.py(登录视图函数)

from django.shortcuts import HttpResponse, render, redirect
from django import forms
from io import BytesIO

from app01 import models
from app01.utils.bootstrap import BootstrapForm
from app01.utils.encrypt import md5
from app01.utils.code import check_code


class LoginForm(BootstrapForm):
    username = forms.CharField(
        label="用户名",
        widget=forms.TextInput,
        required=True
    )
    password = forms.CharField(
        label="密码",
        widget=forms.PasswordInput(render_value=True),
        required=True  # 默认不为空
    )
    code = forms.CharField(
        label="验证码",
        widget=forms.TextInput,
        required=True
    )

    def clean_password(self):
        pwd = self.cleaned_data.get('password')
        return md5(pwd)


def login(request):
    """ 登录 """
    if request.method == 'GET':
        form = LoginForm()
        return render(request, 'login.html', {"form": form})
    else:
        form = LoginForm(data=request.POST)
        if form.is_valid():
            # 验证成功后,获取的提交信息
            # {'username': 'linke', 'password': '123'}
            # print(form.cleaned_data)

            # 去数据库校验,获取用户对象 存在则有对象,不存在则None
            # admin_object = models.Admin.objects.filter(username=form.cleaned_data['username'],
            #                                            password=form.cleaned_data["password"]).first()

            # 验证码的校验
            user_image_code = form.cleaned_data.pop('code')
            code = request.session.get('image_code', '')
            if code.upper() != user_image_code.upper():
                form.add_error("code", "验证码错误")
                return render(request, 'login.html', {"form": form})

            admin_object = models.Admin.objects.filter(**form.cleaned_data).first()
            if not admin_object:
                # 主动给标签添加错误信息
                form.add_error('password', "用户名或密码错误!")
                return render(request, 'login.html', {"form": form})
            else:
                # 网站随机生成一个字符现串,写到用户浏览器的cookie中,再写入到session中
                request.session["info"] = {"id": admin_object.id, "name": admin_object.username}
                # 登陆成功,重新设置session超时失效时间,保存7天
                request.session.set_expiry(60 * 60 * 24 * 7)
                return redirect('/admin/list/')
        else:
            return render(request, 'login.html', {"form": form})


def image_code(request):
    """ 生成图片验证码 """
    # 调用pillow函数,生成图片
    img, code_string = check_code()

    # 写入到自己的session中,以便后续获取验证码再进行校验
    request.session['image_code'] = code_string
    # 给session设置60s超时 ,60s之后失效 【注意:登陆成功后,重新设置session失效时间】
    request.session.set_expiry(60)

    stream = BytesIO()
    img.save(stream, format='png')
    return HttpResponse(stream.getvalue())


def logout(request):
    """ 注销 """
    request.session.clear()
    return redirect('/login/')

auth.py(页面访问限制)

from django.utils.deprecation import MiddlewareMixin
from django.shortcuts import HttpResponse, render, redirect


class AuthMiddleWare(MiddlewareMixin):
    """ 中间件 """

    def process_request(self, request):
        # 如果方法中没有返回值,则继续往后走
        # 如果有返回值 HttpResponse render redirect

        # 1.排除那些不需要走该中间件的url
        # request.path_info 获取当前访问的url
        exclude_url_list = ['/login/', '/image/code/']
        if request.path_info in exclude_url_list:
            return

        # 2.读取当前访问的用户的session信息,如果能读取到,说明已登录过,然后继续往后走逻辑
        info_dict = request.session.get("info")
        if info_dict:
            return  # 直接return None 继续往后走
        else:
            # 重新回到登录页面
            return redirect('/login/')

bootstrap.py(封装bootstrap样式类)

from django import forms


class Bootstrap:
    bootstrap_exclude_fields = []

    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        # 循环ModelForm中的所有字段,给每个字段插件添加属性值
        for name, field in self.fields.items():
            if name in self.bootstrap_exclude_fields:
                continue
            # 字段中有其他属性,保留其他原来属性,没有再添加
            if field.widget.attrs:
                field.widget.attrs["class"] = "form-control"
                field.widget.attrs["placeholder"] = field.label
            else:
                # 字段中没有其他属性,直接批量添加
                field.widget.attrs = {
                    "class": "form-control",
                    "placeholder": field.label
                }


class BootstrapModelForm(Bootstrap, forms.ModelForm):
    pass


class BootstrapForm(Bootstrap, forms.Form):
    pass

code.py (生成验证码)

"""
 安装pillow pip3 install pillow
"""
import random
from PIL import Image, ImageDraw, ImageFont, ImageFilter


def check_code(width=120, height=30, char_length=5, font_file='Monaco.ttf', font_size=28):
    code = []
    img = Image.new(mode='RGB', size=(width, height), color=(255, 255, 255))
    draw = ImageDraw.Draw(img, mode='RGB')

    def rndChar():
        """
        生成随机字母
        :return:
        """
        return chr(random.randint(65, 90))

    def rndColor():
        """
        生成随机颜色
        :return:
        """
        return (random.randint(0, 255), random.randint(10, 255), random.randint(64, 255))

    # 写文字
    font = ImageFont.truetype(font_file, font_size)
    for i in range(char_length):
        char = rndChar()
        code.append(char)
        h = random.randint(0, 4)
        draw.text([i * width / char_length, h], char, font=font, fill=rndColor())

    # 写干扰点
    for i in range(40):
        draw.point([random.randint(0, width), random.randint(0, height)], fill=rndColor())

    # 写干扰圆圈
    for i in range(40):
        draw.point([random.randint(0, width), random.randint(0, height)], fill=rndColor())
        x = random.randint(0, width)
        y = random.randint(0, height)
        draw.arc((x, y, x + 4, y + 4), 0, 90, fill=rndColor())

    # 画干扰线
    for i in range(5):
        x1 = random.randint(0, width)
        y1 = random.randint(0, height)
        x2 = random.randint(0, width)
        y2 = random.randint(0, height)

        draw.line((x1, y1, x2, y2), fill=rndColor())

    img = img.filter(ImageFilter.EDGE_ENHANCE_MORE)
    return img, ''.join(code)


if __name__ == '__main__':
    img, img_str = check_code()
    with open('code.png', 'wb') as f:
        img.save(f,format='png')
    print(img_str)

encrypt.py(加密密码)

import hashlib

from django.conf import settings


def md5(data_string):
    # 加盐 settings.SECRET_KEY
    obj = hashlib.md5(settings.SECRET_KEY.encode('utf-8'))
    obj.update(data_string.encode('utf-8'))
    return obj.hexdigest()

 models.py(创建数据库表)

from django.db import models


# Create your models here.

class Admin(models.Model):
    """管理员"""
    username = models.CharField(verbose_name="用户名", max_length=32)
    password = models.CharField(verbose_name="密码", max_length=64)

    def __str__(self):
        return self.username


class Department(models.Model):
    """ 部门表 """
    title = models.CharField(verbose_name='标题', max_length=32)

    def __str__(self):
        return self.title


class UserInfo(models.Model):
    """ 员工表 """
    name = models.CharField(verbose_name='姓名', max_length=16)
    password = models.CharField(verbose_name='密码', max_length=64)
    age = models.IntegerField(verbose_name='年龄')
    # DecimalField带精度的浮点数
    account = models.DecimalField(verbose_name="账户余额", max_digits=10, decimal_places=2, default=0)
    # create_time = models.DateTimeField(verbose_name='入职时间')
    create_time = models.DateField(verbose_name='入职时间')
    # 无约束mg
    # depart_id = models.BigIntegerField(verbose_name='部门id')

    # 1.有约束
    # to: 与哪张表关联
    # to_field 关联表中的哪个字段
    # 2.djano自动
    #   写的depart
    #   生成数据库列的时候 depart_id
    # 3.1 CASCADE 级联删除 (当部门表中的数据删除,id不存在时,user表中的数据跟着删除)
    depart = models.ForeignKey(verbose_name="部门", to="Department", to_field='id', on_delete=models.CASCADE)
    # 3.2 不删除置空(前提该字段允许为空,部门表中id删除时,user表中的字段置空)
    # depart = models.ForeignKey(to="Department", to_field='id', bull=True,blank=True,on_delete=models.SET_NULL)

    # django中做的约束
    gender_choices = (
        (1, "男"), (2, "女")
    )
    gender = models.SmallIntegerField(verbose_name="性别", choices=gender_choices)


class PrettyNum(models.Model):
    """ 靓号表 """
    mobile = models.CharField(verbose_name="手机号", max_length=11)
    price = models.IntegerField(verbose_name="价格", default=0, null=True, blank=True)
    level_choices = ((1, "一级"),
                     (2, "二级"),
                     (3, "三级"),
                     (4, "四级"))
    level = models.SmallIntegerField(verbose_name="等级", choices=level_choices, default=1)
    status_choices = ((1, "已售"), (2, "在售"))
    status = models.SmallIntegerField(verbose_name="状态", choices=status_choices, default=2)


class Task(models.Model):
    """ 任务 """
    level_choices = ((1, "紧急"), (2, "重要"), (3, "临时"))
    level = models.SmallIntegerField(verbose_name="级别", choices=level_choices, default=1)
    title = models.CharField(verbose_name="标题", max_length=64)
    detail = models.TextField(verbose_name="详细信息")
    user = models.ForeignKey(verbose_name="负责人", to="Admin", on_delete=models.CASCADE)


class Order(models.Model):
    """ 订单 """
    oid = models.CharField(verbose_name="订单号", max_length=64)
    title = models.CharField(verbose_name="名称", max_length=32)
    price = models.IntegerField(verbose_name="价格")

    status_choices = (
        (1, "待支付"), (2, "已支付")
    )
    status = models.SmallIntegerField(verbose_name="状态", choices=status_choices, default=1)
    admin = models.ForeignKey(verbose_name="用户", to="Admin", on_delete=models.CASCADE)


class Boss(models.Model):
    """ 老板 """
    name = models.CharField(verbose_name="姓名", max_length=32)
    age = models.IntegerField(verbose_name="年龄")
    img = models.CharField(verbose_name="头像", max_length=128)


class City(models.Model):
    """ 城市 """
    name = models.CharField(verbose_name="名称", max_length=32)
    count = models.IntegerField(verbose_name="人口")

    # 本质上也是Charfield,自动保存数据
    img = models.FileField(verbose_name="Logo", max_length=128, upload_to='city/')

order.py(订单视图函数)

import random
from datetime import datetime
from django.http import JsonResponse
from django.shortcuts import render, redirect
from django.views.decorators.csrf import csrf_exempt
from app01 import models
from app01.utils.pagination import PagInation
from app01.utils.bootstrap import BootstrapModelForm
from app01.utils.pagination import PagInation


class OrderModelForm(BootstrapModelForm):
    class Meta:
        model = models.Order
        fields = "__all__"
        exclude = ["oid", 'admin']


def order_list(request):
    """ 订单列表 """
    queryset = models.Order.objects.all().order_by('-id')
    form = OrderModelForm()
    page_object = PagInation(request, queryset)

    content = {
        "form": form,
        "queryset": page_object.page_queryset,  # 获取分完页的数据
        "page_string": page_object.html()  # 生成页码
    }
    return render(request, 'order_list.html', content)


@csrf_exempt
def order_add(request):
    """ 新建订单 (Ajax请求) """
    form = OrderModelForm(data=request.POST)
    if form.is_valid():
        # 生成oid 订单号
        oid = datetime.now().strftime('%Y%m%d%H%M%S') + str(random.randint(1000, 9999))
        # 获取当前用户姓名 对应数据库中的id
        admin_id = request.session["info"]["id"]

        # 在保存数据库时 需要将oid,admin_id添加进去
        form.instance.oid = oid
        form.instance.admin_id = admin_id
        form.save()
        return JsonResponse({"status": True})
    else:
        return JsonResponse({"status": False, "error": form.errors})


def order_delete(request):
    """ 删除订单 """
    uid = request.GET.get('uid')
    exists = models.Order.objects.filter(id=uid).exists()
    if exists:
        models.Order.objects.filter(id=uid).delete()
        return JsonResponse({"status": True})
    else:
        return JsonResponse({"status": False, "error": "删除失败,数据不存在!"})


def order_detail(request):
    ''' 根据id获取订单详情 '''
    uid = request.GET.get('uid')
    # 方式一
    # row_object = models.Order.objects.filter(id=uid).first()
    # if not row_object:
    #     return JsonResponse({"status": False, "error": "数据不存在"})
    # else:
    #     row_dict = {
    #         "status": True,
    #         "data": {
    #             "title": row_object.title,
    #             "price": row_object.price,
    #             "status": row_object.status
    #         }
    #     }
    #     return JsonResponse(row_dict)

    # 方式二
    row_dict = models.Order.objects.filter(id=uid).values("title", "price", "status").first()
    if not row_dict:
        return JsonResponse({"status": False, "error": "数据不存在"})
    else:
        return JsonResponse({"status": True, "data": row_dict})


@csrf_exempt
def order_edit(request):
    """ 编辑订单 """
    uid = request.GET.get('uid')
    row_object = models.Order.objects.filter(id=uid).first()
    if not row_object:
        return JsonResponse({"status": False, "tips": "数据不存在,请刷新后重试!"})
    else:
        form = OrderModelForm(data=request.POST, instance=row_object)
        if form.is_valid():
            form.save()
            return JsonResponse({"status": True})
        else:
            return JsonResponse({"satus": False, "error": form.errors})

order_list.html(订单模版)

{% extends 'layout.html' %}

{% block content %}
    <div class="container">
        <div>
            <input class="btn btn-primary" type="button" value="新建订单 方式一"
                   data-toggle="modal" data-target="#myModal">
            <input id="btnAdd" class="btn btn-success" type="button" value="新建订单 方式二">
        </div>

        <div class="panel panel-default" style="margin-top: 10px">
            <!-- Default panel contents -->
            <div class="panel-heading">
                <span class="glyphicon glyphicon-list" aria-hidden="true"></span>
                任务列表
            </div>

            <!-- Table -->
            <table class="table table-bordered">
                <thead>
                <tr>
                    <th>ID</th>
                    <th>订单号</th>
                    <th>商品</th>
                    <th>价格</th>
                    <th>状态</th>
                    <th>客户</th>
                    <th>操作</th>
                </tr>
                </thead>
                <tbody>
                {% for obj in queryset %}
                    <tr uid="{{ obj.id }}">
                        <th>{{ obj.id }}</th>
                        <td>{{ obj.oid }}</td>
                        <td>{{ obj.title }}</td>
                        <td>{{ obj.price }}</td>
                        <td>{{ obj.get_status_display }}</td>
                        <td>{{ obj.admin }}</td>
                        <td>
                            <input uid="{{ obj.id }}" type="button" class="btn btn-primary btn-xs btn-edit"
                                   value="编辑">
                            <input uid="{{ obj.id }}" type="button" class="btn btn-danger btn-xs btn-delete"
                                   value="删除">
                        </td>
                    </tr>
                {% endfor %}

                </tbody>
            </table>
        </div>
        <ul class="pagination">
            {{ page_string }}
        </ul>

        {#    新建/编辑 对话框    #}
        <div class="modal fade" id="myModal" tabindex="-1" role="dialog" aria-labelledby="myModalLabel">
            <div class="modal-dialog" role="document">
                <div class="modal-content">
                    <div class="modal-header">
                        <button type="button" class="close" data-dismiss="modal" aria-label="Close"><span
                                aria-hidden="true">&times;</span></button>
                        <h4 class="modal-title" id="myModalLabel">新建</h4>
                    </div>
                    <div class="panel-body">
                        <form id="formModal">
                            <div class="clearfix">
                                {% for field in form %}
                                    <div class="col-xs-6">
                                        <div class="form-group" style="position: relative;margin-top: 15px">
                                            <label>{{ field.label }}</label>
                                            {{ field }}
                                            <span class="error-msg"
                                                  style="color: red;position: absolute"></span>
                                        </div>
                                    </div>
                                {% endfor %}
                            </div>
                        </form>
                    </div>
                    <div class="modal-footer">
                        <button type="button" class="btn btn-default" data-dismiss="modal">取 消</button>
                        <button id="btnSave" type="button" class="btn btn-primary">保 存</button>
                    </div>
                </div>
            </div>
        </div>
        <!-- 删除确认对话框 -->
        <div class="modal fade" id="deleteModal" tabindex="-1" role="dialog" aria-labelledby="myModalLabel">
            <div class="modal-dialog" role="document">
                <div class="alert alert-danger alert-dismissible fade in" role="alert">
                    <h4>请确认是否删除?</h4>
                    <p style="margin: 1px"> 删除后,所有关联相关数据都会被删除..</p>
                    <p style="text-align: right">
                        <button id="btn-confirm-delete" type="button" class="btn btn-danger">确 定</button>
                        <button type="button" class="btn btn-default" data-dismiss="modal">取 消</button>
                    </p>
                </div>
            </div>
        </div>
    </div>
{% endblock %}


{% block js %}
    <script type="text/javascript">
        var DELETE_ID;
        var EDIT_ID;
        $(function () {
            bindBtnAddEvent();
            bindBtnSaveEvent();
            bindBtnDeleteEvent();
            bindBtnConfirmDeleteEvent();
            bindBtnEditEvent();
        })

        function bindBtnAddEvent() {
            // 将 EDIT_ID 置空
            EDIT_ID = undefined;
            $("#btnAdd").click(function () {
                // 清除对话框中的数据
                $('#formModal')[0].reset();
                // 修改对话框的标题
                $('#myModalLabel').text("新建")
                // 点击新建按钮,显示对话框
                $("#myModal").modal('show');
            })
        }

        function bindBtnSaveEvent() {
            $("#btnSave").click(function () {
                // 清除错误信息
                $(".error-msg").empty();
                if (EDIT_ID) {
                    // 编辑
                    doEdit();
                } else {
                    // 新建
                    doAdd();
                }

            })
        }
        function doEdit() {
             $.ajax({
                url: "/order/edit/" + "?uid=" + EDIT_ID,
                type: 'post',
                data: $("#formModal").serialize(),
                dataType: "json",
                success: function (res) {
                    if (res.status) {
                        {#alert("编辑成功");#}
                        // 清空表单 $("#formModal") 是jQuery对象 -> $("#formModal")[0] DOM对象才有reset功能
                        $("#formModal")[0].reset();

                        // 关闭对话框
                        $("#myModal").modal('hide');

                        // 刷新页面
                        location.reload();
                    } else {
                        if(res.tips){
                            alert(res.tips)
                        }else{
                            $.each(res.error, function (name, errorList) {
                            $("#id_" + name).next().text(errorList[0])
                            })
                        }
                    }
                }
            })
        }

        function doAdd() {
            // 想后端发起请求 (添加数据的请求)
            $.ajax({
                url: '/order/add/',
                type: 'post',
                data: $("#formModal").serialize(),
                dataType: "json",
                success: function (res) {
                    if (res.status) {
                        {#alert("创建成功");#}
                        // 清空表单 $("#formModal") 是jQuery对象 -> $("#formModal")[0] DOM对象才有reset功能
                        $("#formModal")[0].reset();

                        // 关闭对话框
                        $("#myModal").modal('hide');

                        // 刷新页面
                        location.reload();
                    } else {
                        $.each(res.error, function (name, errorList) {
                            $("#id_" + name).next().text(errorList[0])
                        })
                    }
                }
            })
        }

        function bindBtnDeleteEvent() {
            $(".btn-delete").click(function () {
                // alert("点击删除");
                // 显示删除对话框
                $("#deleteModal").modal('show');

                // 取当前行的值并赋值给全局变量
                DELETE_ID = $(this).attr("uid");
            });
        }

        function bindBtnConfirmDeleteEvent() {
            $('#btn-confirm-delete').click(function () {
                // 点击确认按钮,将全局变量删除iD 发送后台
                $.ajax({
                    url: "/order/delete/",
                    type: "GET",
                    data: {
                        uid: DELETE_ID
                    },
                    dataType: 'JSON',
                    success: function (res) {
                        if (res.status) {
                            {#// 隐藏删除框#}
                            {#$('#deleteModal').modal('hide');#}
                            {#// 页面上删除这一行数据#}
                            {#location.reload()#}
                            {#$('tr[uid='+ DELETE_ID +']').remove();#}
                            {#// 将DELETE_ID 初始化#}
                            {#DELETE_ID = 0;#}

                            location.reload();

                        } else {
                            // 删除失败
                            alert(res.error)
                        }
                    }
                })
            })
        }

        function bindBtnEditEvent() {
            $(".btn-edit").click(function () {
                var uid = $(this).attr('uid');
                EDIT_ID = uid;
                // 清除对话框中的数据
                $('#formModal')[0].reset();
                // 发送 ajax 去后端获取当前行的数据 在编辑框中能看到当前要编辑的数据
                $.ajax({
                    url: '/order/detail/',
                    type: 'get',
                    data: {
                        uid: uid
                    },
                    dataType: "JSON",
                    success: function (res) {
                        if (res.status) {
                            // 将数据赋值到标签中
                            $.each(res.data, function (name, value) {
                                $('#id_' + name).val(value)
                            })
                            // 修改对话框的标题
                            $('#myModalLabel').text("编辑");
                            // 点击编辑显示对话框
                            $("#myModal").modal('show');
                            {#// 清除对话框中的数据#}
                            {#$('#formModal')[0].reset();#}

                        } else {
                            alert(res.error);
                        }
                    }
                })
            })
        }
    </script>

{% endblock %}

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值