首页 > 技术文章 > CMS知识点一

spf21 2018-09-06 21:38 原文

一、注册功能

  1.   ajax上传文件
    from django.shortcuts import render, HttpResponse
    def upload(request):
        """
        上传文件操作
        :param request: 
        :return: 
        """
        if request.method == "POST":
            # 从上传的文件数据中拿到 avatar对应的文件对象
            file_obj = request.FILES.get("avatar")
            # 在服务端新建一个和上传文件同名的新文件
            with open(file_obj.name, "wb") as f:
                # 从上传文件对象中一点一点读数据
                for i in file_obj:
                    # 写入服务端新建的文件
                    f.write(i)
            return HttpResponse("上传成功")
    
        return render(request, "upload.html")
    
    
    def upload_ajax(request):
        """
        使用ajax方式上传
        :param request:
        :return:
        """
        return render(request, "upload_ajax.html")
    views.py
    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>上传文件</title>
    </head>
    <body>
    <form action="" method="post" enctype="multipart/form-data"> // 必须加 enctype="multipart/form-data"
        {% csrf_token %}
        <label>
            <input type="file" name="avatar">
        </label>
        <label>
            <input type="submit" value="上传">
        </label>
    </form>
    </body>
    </html>
    upload.html
    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>上传文件</title>
    </head>
    <body>
    {% csrf_token %}
    <input type="file" name="avatar" class="f1">
    <input type="button" class="b1" value="上传">  // 使用ajax时候不要用submit
    <script src="https://cdn.bootcss.com/jquery/3.3.1/jquery.js"></script>
    <script>
        $(".b1").click(function () {
            // 先生成一个FromData对象
            var fd = new FormData();
            // 将要提交的数据
            fd.append("csrfmiddlewaretoken", $("[name='csrfmiddlewaretoken']").val());
            fd.append("avatar", $(".f1")[0].files[0]);
            $.ajax({
                url: "/upload/",
                type: "post",
                data: fd,
                contentType: false,
                processData: false,
                success: function (res) {
                    console.log(res)
                }
            })
        });
    </script>
    </body>
    </html>
    upload_ajax.html
  2.   头像预览
    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>上传文件</title>
    </head>
    <body>
    {% csrf_token %}
    {#style="width: 40px; border-radius: 50% 设置图片大小并修改成圆头像#}
    {#accept="image/*" 只显示图片类型的文件#}
    <label><img src="/static/images/default.png" alt="" style="width: 40px; border-radius: 50%">
        <input type="file" name="avatar" class="f1" style="display: none;" accept="image/*">
    </label>
    <input type="button" class="b1" value="上传">
    <script src="https://cdn.bootcss.com/jquery/3.3.1/jquery.js"></script>
    <script>
        // Ajax上传头像
        $(".b1").click(function () {
            // 先生成一个FromData对象
            var fd = new FormData();
            // 将要提交的数据
            fd.append("csrfmiddlewaretoken", $("[name='csrfmiddlewaretoken']").val());
            fd.append("avatar", $(".f1")[0].files[0]);
            $.ajax({
                url: "/upload/",
                type: "post",
                data: fd,
                contentType: false,
                processData: false,
                success: function (res) {
                    console.log(res)
                }
            })
        });
        // 预览头像
        $(".f1").change(function () {
           // 取到用户选中的头像文件
           var fileobj = this.files[0];
           // 新新建一个FileReader对象, 从本地磁盘加载文件数据
            var fr = new FileReader();
            fr.readAsDataURL(fileobj);
            // 读取文件需要时间
            fr.onload=function () {
                // 找到预览头像的img标签,把踏的src属性设置成读取的用户选中的图片
                $("img").attr("src", fr.result)
            }
        });
    </script>
    </body>
    </html>
    头像预览
  3.   Django项目上传文件之后怎么查看
    1. 配置上传的文件保存在哪里
        settings.py中 MEDIA_ROOT = os.path.join(BASE_DIR, "media")
        上传文件需要注意两点:
            1. 前端使用form表单上传需要配置 enctype="multipart/form-data"
                <form class="form-horizontal" action="" method="post" novalidate enctype="multipart/form-data">
            2. 后端接收
                avatar_obj = request.FILES.get("avatar")
                
    2. 如何查看上传的文件
        /media/xx/oo.jpg
        1. settings.py中设置 MEDIA_URL="/media/"(别名)
        2. urls.py中设置 media开头的路径用什么视图函数处理
            url(r'^media/(?P<path>.*)', serve, {"document_root": settings.MEDIA_ROOT}),

二、CMS表结构设计

from django.db import models
from django.contrib.auth.models import AbstractUser


# Create your models here.


class UserInfo(AbstractUser):
    """
    用户表,
        新增手机号字段
        新增头像字段
        verbose_name 在admin中显示的字段名称
    """
    phone = models.CharField(max_length=11, verbose_name="手机号")
    avatar = models.FileField(upload_to="avatars", default="avatars/default.png", verbose_name="头像")

    class Meta:
        """
        verbose_name 在admin中显示的表名称
        """
        verbose_name = "用户管理"
        verbose_name_plural = verbose_name


class Fault(models.Model):
    """
    故障表
    """
    title = models.CharField(max_length=50, verbose_name="故障标题")
    summary = models.TextField(max_length=100, verbose_name="故障概述")
    create_time = models.DateTimeField(auto_now_add=True, verbose_name="发布时间")
    modify_time = models.DateTimeField(auto_now=True, verbose_name="最后修改时间")
    tags = models.ManyToManyField(to="Tag",
                                  through="Fault2Tag",  # 指定第三张关系表
                                  through_fields=("fault", "tag"),  # 通过哪些字段建立多对多关系
                                  verbose_name="标签")
    classify = models.ForeignKey(to="Classify", verbose_name="分类", null=True)
    user = models.ForeignKey(to="UserInfo", verbose_name="发布用户")

    comment_count = models.IntegerField(default=0, verbose_name="评论总数")
    up_count = models.IntegerField(default=0, verbose_name="点赞总数")
    down_count = models.IntegerField(default=0, verbose_name="反正总数")

    def __str__(self):
        return self.title

    class Meta:
        verbose_name = "故障管理"
        verbose_name_plural = verbose_name


class Tag(models.Model):
    """
    标签表
    """
    name = models.CharField(max_length=30, verbose_name="标签名称", unique=True)

    def __str__(self):
        return self.name

    class Meta:
        verbose_name = "标签管理"
        verbose_name_plural = verbose_name


class Classify(models.Model):
    """
    分类表
    """
    name = models.CharField(max_length=30, verbose_name="业务线名称", unique=True)

    def __str__(self):
        return self.name

    class Meta:
        verbose_name = "业务线管理"
        verbose_name_plural = verbose_name


class Comment(models.Model):
    """
    评论表
    """
    content = models.CharField(max_length=100, verbose_name="评论内容")
    comment_date = models.DateTimeField(auto_now_add=True, verbose_name="评论时间")
    fault = models.ForeignKey(to="Fault", verbose_name="故障总结")
    user = models.ForeignKey(to="UserInfo", verbose_name="评论用户")
    parent_comment = models.ForeignKey(to="self", null=True, blank=True, verbose_name="父级评论")  # 自己关联自己,用户可以评论其他人的评论

    def __str__(self):
        return self.content

    class Meta:
        verbose_name = "评论管理"
        verbose_name_plural = verbose_name


class UpDown(models.Model):
    """
    点赞表
    同一个用户只能对一篇文章进行点赞或者反对,如果点赞了就不能反对,二选一
    """
    user = models.ForeignKey(to="UserInfo", verbose_name="用户")
    fault = models.ForeignKey(to="Fault", verbose_name="故障总结")
    is_up = models.BooleanField(default=True, verbose_name="支持/反对")

    def __str__(self):
        return "{}-{}-{}".format(self.user.username, self.fault.title, "支持" if self.is_up else "反对")

    class Meta:
        """
        unique_together联合唯一,限制一用户只能对一篇文章进行点赞或者反对
        """
        unique_together = (("user", "fault"),)
        verbose_name = "支持/反对"
        verbose_name_plural = verbose_name


class Fault2Tag(models.Model):
    """
    故障报告和标签多对多关联表
    手动生产第三张表,可以在第三张表增加新的字段
    """
    fault = models.ForeignKey(to="Fault", verbose_name="故障总结")
    tag = models.ForeignKey(to="Tag", verbose_name="标签名称")

    def __str__(self):
        return "{}-{}".format(self.fault.title, self.tag.name)

    class Meta:
        unique_together = (("fault", "tag"),)
        verbose_name = "故障-标签"
        verbose_name_plural = verbose_name


class FaultDetail(models.Model):
    """
    故障内容表
    为什么不和故障表放到一起?
        故障内容可能多,用户每次请求页面的时候都请求故障内容,就会很慢。
    """
    content = models.TextField(verbose_name="故障内容")
    fault = models.ForeignKey(to="Fault", verbose_name="故障总结")

    def __str__(self):
        return self.content

    class Meta:
        verbose_name = "故障详情"
        verbose_name_plural = verbose_name

三、CMS首页和个人中心页面实现

ORM 高阶用法都在 --> https://www.cnblogs.com/liwenzhou/p/8660826.html
1. ORM分组和聚合查询 
    聚合内置函数:from django.db.models import Avg, Sum, Max, Min, Count
    
    annotate()
        annotate()前面查的是什么就按照什么分组
        .values("dept").annotate()就表示按照dept分组
    
2. 时间格式化函数
        1. MySQL
            DATE_FORMAT(字段, '格式')
            示例:models.Fault.objects.all().extra(select={"ym": "date_format(create_time, '%%Y-%%m')"}).values("ym").annotate(num=Count("id")).values("ym", "num")
        2. sqlite
            strftime('格式', 字段)
            示例:models.Fault.objects.all().extra(select={"ym": "strftime('%%Y-%%m', create_time)"}).values("ym").annotate(num=Count("id")).values("ym", "num")
3. Django ORM执行原生SQL语句 1. 使用extra()执行部分sql语句 示例:models.Fault.objects.all().extra(select={"ym": "date_format(create_time, '%%Y-%%m')"}).values("ym").annotate(num=Count("id")).values("ym", "num") 2. 类似pymysql执行方式
4. 二级路由 1. 保障系统4合1 代码示例: CMS urls.py: from fault_reporting import urls as fault_urls urlpatterns = [ url(r'^fault-report/', include(fault_urls)) ] fault_reporting urls.py: urlpatterns = [ # 根据产品线,标签,日期归档分类 ()在正则是分组的意思,这里分2个组传了2个参数 url(r'(class|tag|archive)/(.*)/$', views.index) ]

 

推荐阅读