16 后台站点二(热门文章)

后端功能实现

apps/admin/views.py

import json
import logging

from django.db.models import Count
from django.shortcuts import render
from django.views import View


# Create your views here.
from apps.news import models
from apps.admin import constants

from utils.json_fun import to_json_data
from utils.res_code import Code, error_map

logger = logging.getLogger('django')
class IndexView(View):
    """
    /admin/
    """
    def get(self,request):
        """

        :param request:
        :return:
        """
        return render(request,'admin/index/index.html')


class TagManagerView(View):
    """
    /admin/tag/
    """
    def get(self,request):
        """
        要返回给前端: tag_name news_name
        :param request:
        :return:
        """
        #分组查询 annotate 配合 values 使用     values 指定输出的内容(id: ,name: ),是字典格式
         #按标签名(tag_name)和 id(tag_id) 分组,统计每个标签(Tag)中 news(外键关联,
        # 通过 news的主键 id 统计) 的数量,并且按降序排列
        tags = models.Tag.objects.select_related('news').values('id','name').annotate(num_news = \
                  Count('news')).filter(is_delete=False).order_by('-num_news','update_time')
        return render(request,'admin/news/tag_manage.html',locals())

    def post(self,request):
        """
        get_or_create(defaults=None, **kwargs)

         一个通过给出的kwargs 来查询对象的便捷方法(如果你的模型中的所有字段都有默认值,可以为空),需要的话创建一个对象。
         返回一个由(object, created)组成的元组,元组中的object 是一个查询到的或者是被创建的对象,
         created 是一个表示是否创建了新的对象的布尔值。

        :param request:
        :return:
        """
        # 1. 获取参数
        json_data = request.body
        if not json_data:
            return to_json_data(errno=Code.PARAMERR,errmsg=error_map[Code.PARAMERR])
        dict_data = json.loads(json_data.decode('utf8'))
        #从前端传进来的要修改的标签名
        tag_name = dict_data.get('name')
        if tag_name:
            # tag_name = tag_name.strip()
            # a = tag_name
            #get_or_create 查名为 tag_name 的标签,无则增,有则查 得到的是元组类型    请确保只在 post 请求中使用它
            tag_tuple = models.Tag.objects.filter(is_delete=False).get_or_create(name=tag_name)
            #对得到的元组进行拆包
            tag_instance,tag_boolean = tag_tuple
            #如果 tag_boolean 为 True,即创建了名字为 tag_name 的标签
            # 否则就是查到了名字为 tag_name 的标签,即标签已存在,不创建
            if tag_boolean:
                news_tag_dict = {
                    'id':'tag_instance.id',
                    'name':'tag_instance.name',
                }
                return to_json_data(errmsg='标签创建成功!',data=news_tag_dict)
            else:
                return to_json_data(errno=Code.DATAEXIST,errmsg='标签已存在!')
        else:
            return to_json_data(errno=Code.PARAMERR,errmsg='标签不能为空!')


#传参:
class TagEditView(View):
    """
    /admin/tag/<tag_id>/
    """
    def delete(self,request,tag_id):
        """

        :param request:
        :param tag_id:
        :return:
        """
        tag = models.Tag.objects.only('id').filter(id=tag_id).first()
        if tag:
            tag.is_delete = True
            #只改 is_delete 字段,用于优化
            tag.save(update_fields=['is_delete'])
            #删除后局部刷新,用 ajax,返回给前端 json 格式
            return to_json_data(errmsg='标签删除成功!')
        else:
            return to_json_data(errno=Code.PARAMERR,errmsg='标签不存在!')

    def put(self,request,tag_id):
        """

        :param request:
        :param tag_id:
        :return:
        """
        #修改之后的 name 通过 ajax 获取  只有一个参数,用 ajax 即可
        # 1. 获取参数
        json_data = request.body    #byte str
        if not json_data:
            return to_json_data(errno=Code.PARAMERR,errmsg=error_map[Code.PARAMERR])
        dict_data = json.loads(json_data.decode('utf8'))
        # 从前端传进 要修改的 tag
        tag_name = dict_data.get('name')
        # 从数据库中拿到 tag
        tag = models.Tag.objects.only('name').filter(id=tag_id).first()
        if tag:
            #去掉两边的空格
            tag_name = tag_name.strip()
            #如果不加 is_delete 删除的标签再创建或者修改无法实现
            if tag.name == tag_name:
                return to_json_data(errno=Code.PARAMERR,errmsg='标签未变化!')
            if not models.Tag.objects.only('id').filter(name=tag_name, is_delete=False).exists():
            #如果标签没变化,提示报错
                # if tag.name == tag_name:
                #     return to_json_data(errno=Code.PARAMERR,errmsg='标签未变化!')
                tag.name = tag_name
                tag.save(update_fields=['name', 'update_time'])
                return to_json_data(errmsg='标签更新成功!')
            else:
                return to_json_data(errno=Code.PARAMERR,errmsg='标签已经存在!')
        else:
            #有异常的一定会用到 errno
            return to_json_data(errno=Code.PARAMERR,errmsg='标签不存在!')


# 热门文章管理页面
#news.title,tag.name,hotnews.priority
class HotNewsManageView(View):
    """
    /admin/hotnews/
    """
    def get(self,request):
        hot_news = models.HotNews.objects.select_related('news__tag').only('news__title','news__tag__name','news__id').\
            filter(is_delete=False).order_by('priority','-news__clicks')[:constants.SHOW_HOTNEWS_COUNT]
        return render(request,'admin/news/news_hot.html',locals())



class HotNewsEditView(View):
    """
    /admin/hotnews/<int:tag_id>
    """
    def delete(self,request,hotnews_id):
        hotnews = models.HotNews.objects.only('id').filter(id=hotnews_id).first()
        if hotnews:
            hotnews.is_delete = True
            hotnews.save(update_fields = ['is_delete','update_time'])
            return to_json_data(errmsg='热门文章删除成功!')
        else:
            return to_json_data(errno=Code.PARAMERR,errmsg='需要删除的热门文章不存在!')

    def put(self,request,hotnews_id):
        """
        更新热门新闻
        #1. 获取参数
        :param request:
        :param hotnews_id:
        :return:
        """
        json_data = request.body
        if not json_data:
            return to_json_data(errno=Code.PARAMERR,errmsg=error_map[Code.PARAMERR])
        dict_data = json.loads(json_data.decode('utf8'))
        try:
            priority = int(dict_data.get('priority'))
            #列表生成式 对于不需要的可以用 _ 代替
            priority_list = [i for i,_ in models.HotNews.PRI_CHOICES]
            if priority not in priority_list:
                return to_json_data(errno=Code.PARAMERR,errmsg='热门文章优先级设置错误!')
        except Exception as e:
            logger.info('热门文章优先级异常:\n{}'.format(e))
            return to_json_data(errno=Code.PARAMERR,errmsg='热门文章优先级设置错误!')

        hotnews = models.HotNews.objects.only('id').filter(id=hotnews_id).first()
        if not hotnews:
            return to_json_data(errno=Code.PARAMERR,errmsg='需要更新的热门新闻不存在!')
        if hotnews.priority == priority:
            return to_json_data(errno=Code.PARAMERR,errmsg='热门新闻优先级未改变!')
        hotnews.priority = priority
        hotnews.save(update_fields=['priority','update_time'])
        return to_json_data(errmsg='热门新闻优先级更新成功!')


class HotNewsAddView(View):
    """
    添加热门新闻,先选标签,才能选标签下的文章,选择优先级不受他们影响
    /addmin/hotnews/add/
    """
    def get(self,request):
        #选择标签和优先级
        #有排序
        tags = models.Tag.objects.values('id','name').annotate(num_news = Count('news')).filter(is_delete=False).\
                order_by('-num_news','update_time')
        #将列表嵌套个元组转换成字典
        priority_dict = dict(models.HotNews.PRI_CHOICES)
        return render(request,'admin/news/news_hot_add.html',locals())

    def post(self,request):
        #添加热门新闻
        #1.获取参数
        json_data = request.body
        if not json_data:
            return to_json_data(errno=Code.PARAMERR,errmsg=error_map[Code.PARAMERR])
        dict_data = json.loads(json_data.decode('utf8'))
        #news_id priority
        try:
            news_id = int(dict_data.get('news_id'))
        except Exception as e:
            logger.info('热门文章:\n{}'.format(e))
            return to_json_data(errno=Code.PARAMERR,errmsg='参数错误')
        if not models.News.objects.filter(id=news_id).exists():
            return to_json_data(errno=Code.PARAMERR,errmsg='文章不存在!')
        try:
            priority = int(dict_data.get('priority'))
            priority_list = [i for i,_ in models.HotNews.PRI_CHOICES]
            if priority not in priority_list:
                return to_json_data(errno=Code.PARAMERR,errmsg='热门文章优先级设置错误!')
        except Exception as e:
            logger.info('热门文章优先级异常:\n{}'.format(e))
            return to_json_data(errno=Code.PARAMERR,errmsg='热门文章优先级设置错误')
        hotnews_tuple = models.HotNews.objects.get_or_create(news_id=news_id)
        hotnews,is_created = hotnews_tuple
        hotnews.priority = priority
        hotnews.save(update_fields=['priority','update_time'])
        return to_json_data(errmsg='热门文章创建成功!')


class NewsByTagIdView(View):
    """
    选完标签后进行这步,选标签下的文章
    不用展示 tag_id
    /admin/tags/<int:tag_id>/news/
    """
    def get(self,request,tag_id):
        news = models.News.objects.filter(is_delete=False,tag_id=tag_id).values('id','title')
        #将字典嵌套进列表
        news_list = [i for i in news]
        return to_json_data(data={
            'news':news_list
        })

apps/admin/urls.py

from apps.admin import views
from django.urls import path


app_name = 'admin'

urlpatterns = [
    path('',views.IndexView.as_view(),name='index'),
    path('tags/',views.TagManagerView.as_view(),name='tags'),
    path('tags/<int:tag_id>/',views.TagEditView.as_view(),name='tag_edit'),
    path('hotnews/',views.HotNewsManageView.as_view(),name='hotnews'),
    path('hotnews/<int:hotnews_id>/',views.HotNewsEditView.as_view(),name='hotnews_edit'),
    path('hotnews/add/',views.HotNewsAddView.as_view(),name='hotnews_add'),
    path('tags/<int:tag_id>/news/',views.NewsByTagIdView.as_view(),name='hotnews_by_tagid'),

]

前端功能实现

templates/admin/news/news_hot.html


{% extends 'admin/base/base.html' %}
{% load static %}
{% block title %}
  热门文章管理页面
{% endblock %}


{% block content_header %}
  热门文章管理
{% endblock %}

{% block header_option_desc %}
  正确的决策来自众人的智慧
{% endblock %}


{% block content %}
  <div class="row">
    <div class="col-md-12 col-xs-12 col-sm-12">
      <div class="box box-primary">
        <div class="box-header">
          <a href="{% url 'admin:hotnews_add' %}" class="btn btn-primary pull-right"
{#          <a href="#" class="btn btn-primary pull-right"#}
{#          <a href="#" class="btn btn-primary pull-right"#}
             id="btn-add-news-recommend">添加热门文章</a>
        </div>
        <div class="box-body">
          <table class="table table-bordered table-hover">
            <thead>
            <tr>
              <th>文章名称</th>
              <th>文章分类</th>
              <th>优先级</th>
              <th>操作</th>
            </tr>
            </thead>

            <tbody>

            {% for hot_new in hot_news %}
              <tr data-id="{{ hot_new.id }}" data-name="{{ hot_new.news.title }}">
                <td>
                  <a href="{% url 'news:news_detail' hot_new.news_id %}" data-news-id="{{ hot_new.news_id }}">
                    {{ hot_new.news.title }}
                  </a>
                </td>

                <td>{{ hot_new.news.tag.name }}</td>
{#                <td>{{ hot_new.priority }}</td>#}
                <td>{{ hot_new.get_priority_display }}</td>
                <td>
                  <button class="btn btn-xs btn-warning btn-edit"
                    data-priority="{{ hot_new.priority }}">编辑</button>
                  <button class="btn btn-xs btn-danger btn-del">删除</button>

                </td>
              </tr>
            {% endfor %}

            </tbody>
          </table>
        </div>
        <div class="box-footer"></div>
      </div>
    </div>
  </div>
{% endblock %}


{% block script %}
  <script src="/static/js/admin/news/news_hot.js"></script>
{% endblock %}

static/js/admin/news/news_hot.js

// 创建static/js/admin/news/news_hot.js文件

$(function () {
  // 添加热门文章
  let $tagAdd = $("#btn-add-tag");  // 1. 获取添加按钮
  $tagAdd.click(function () {   	// 2. 点击事件
    fAlert.alertOneInput({
      title: "请输入文章标签",
      text: "长度限制在20字以内",
      placeholder: "请输入文章标签",
      confirmCallback: function confirmCallback(inputVal) {
        console.log(inputVal);

        if (inputVal === "") {
          swal.showInputError('标签不能为空');
          return false;
        }

        let sDataParams = {
          "name": inputVal
        };

        $.ajax({
          // 请求地址
          url: "/admin/tags/",  // url尾部需要添加/
          // 请求方式
          type: "POST",
          data: JSON.stringify(sDataParams),
          // 请求内容的数据类型(前端发给后端的格式)
          contentType: "application/json; charset=utf-8",
          // 响应数据的格式(后端返回给前端的格式)
          dataType: "json",
        })
          .done(function (res) {
            if (res.errno === "0") {

              fAlert.alertSuccessToast(inputVal + " 标签添加成功");
              setTimeout(function () {
                window.location.reload();
              }, 1000)
            } else {
              swal.showInputError(res.errmsg);
            }
          })
          .fail(function () {
            message.showError('服务器超时,请重试!');
          });

      }
    });
  });


  // 编辑热门文章
  let $HotNewsEdit = $(".btn-edit");  // 1. 获取编辑按钮
  $HotNewsEdit.click(function () {    // 2. 点击触发事件
    let _this = this;
    let sHotNewsId = $(this).parents('tr').data('id');
    // let sHotNewsTitle = $(this).parents('tr').data('name');
    let sPriority = $(this).data('priority');

    fAlert.alertOneInput({
      title: "编辑热门文章优先级",
      text: "你正在编辑热门文章的优先级",
      placeholder: "请输入文章优先级",
      value: sPriority,
      confirmCallback: function confirmCallback(inputVal) {
        if (!inputVal.trim()) {
          swal.showInputError('输入框不能为空!');
          return false;
        } else if (inputVal == sPriority) {
          swal.showInputError('优先级未修改');
          return false;
        } else if (!jQuery.inArray(inputVal, ['1', '2', '3'])) {
          swal.showInputError('优先级只能取1,2,3中的一个');
          return false;
        }

        let sDataParams = {
          "priority": inputVal
        };

        $.ajax({
          // 请求地址
          url: "/admin/hotnews/" + sHotNewsId + "/",  // url尾部需要添加/
          // 请求方式
          type: "PUT",
          data: JSON.stringify(sDataParams),
          // 请求内容的数据类型(前端发给后端的格式)
          contentType: "application/json; charset=utf-8",
          // 响应数据的格式(后端返回给前端的格式)
          dataType: "json",
        })
          .done(function (res) {
            if (res.errno === "0") {
              swal.close();
              message.showSuccess("标签修改成功");
              // $(_this).parents('tr').find('td:nth-child(3)').text(inputVal);

              setTimeout(function () {
                // window.location.href = '../../../../apps/admin/hotnews/';
                window.location.href = '../../../../admin/hotnews/';
              }, 800)
            } else {
              swal.showInputError(res.errmsg);
            }
          })

          .fail(function () {
            message.showError('服务器超时,请重试!');
          });

      }
    });

  });


  // 删除热门文章
  let $HotNewsDel = $(".btn-del");  // 1. 获取删除按钮
  $HotNewsDel.click(function () {   // 2. 点击触发事件
    let _this = this;
    let sHotNewsId = $(this).parents('tr').data('id');
    fAlert.alertConfirm({
      title: "确定删除热门文章吗?",
      type: "error",
      confirmText: "确认删除",
      cancelText: "取消删除",
      confirmCallback: function confirmCallback() {

        $.ajax({
          url: "/admin/hotnews/" + sHotNewsId + "/",  // url尾部需要添加/
          type: "DELETE",
          dataType: "json",
        })
          .done(function (res) {
            if (res.errno === "0") {
              message.showSuccess("删除热门文章成功");
              $(_this).parents('tr').remove();
                setTimeout(function () {
                    window.location.reload();
                }, 1000)
            } else {
              swal.showInputError(res.errmsg);
            }
          })
          .fail(function () {
            message.showError('服务器超时,请重试!');
          });
      }
    });
  });


  // get cookie using jQuery
  function getCookie(name) {
    let cookieValue = null;
    if (document.cookie && document.cookie !== '') {
      let cookies = document.cookie.split(';');
      for (let i = 0; i < cookies.length; i++) {
        let cookie = jQuery.trim(cookies[i]);
        // Does this cookie string begin with the name we want?
        if (cookie.substring(0, name.length + 1) === (name + '=')) {
          cookieValue = decodeURIComponent(cookie.substring(name.length + 1));
          break;
        }
      }
    }
    return cookieValue;
  }

  function csrfSafeMethod(method) {
    // these HTTP methods do not require CSRF protection
    return (/^(GET|HEAD|OPTIONS|TRACE)$/.test(method));
  }

  // Setting the token on the AJAX request
  $.ajaxSetup({
    beforeSend: function (xhr, settings) {
      if (!csrfSafeMethod(settings.type) && !this.crossDomain) {
        xhr.setRequestHeader("X-CSRFToken", getCookie('csrftoken'));
      }
    }
  });

});

templates/admin/news/news_hot_add.html

{% extends 'admin/base/base.html' %}
{% load static %}
{% block title %}
  添加热门文章
{% endblock %}

{% block content_header %}
  添加热门文章
{% endblock %}

{% block header_option_desc %}
  创建热门文章
{% endblock %}


{% block content %}
  <div class="box box-primary">
    <div class="box-body">
      <div class="form-horizontal">
        <div class="form-group">
          <label for="category-select" class="col-md-2 col-sm-2 control-label">选择文章</label>
          <div class="col-md-2 col-sm-3">
            <select name="category" id="category-select" class="form-control input-md">
              <option value="0">--请选择文章分类--</option>

              {% for one_tag in tags %}
                <option value="{{ one_tag.id }}">{{ one_tag.name }}</option>
              {% endfor %}

            </select>
          </div>
          <div class="col-md-8 col-sm-7">
            <label for="news-select" style="display: none;"></label>
            <select name="news" class="form-control input-md" id="news-select">
              <option value="0">--请选择文章--</option>
            </select>
          </div>
        </div>
        <div class="form-group">
          <label for="priority" class="col-md-2 col-sm-2 control-label">选择优先级</label>

          <div class="col-md-2 col-sm-3">
            <select name="priority" id="priority" class="form-control input-md">
              <option value="0">--请选择优先级--</option>

              {% for id, value in priority_dict.items %}
                <option value="{{ id }}">{{ value }}</option>
              {% endfor %}

            </select>

          </div>
        </div>
      </div>
      <div class="box-footer">
        <a href="javascript:void(0);" class="btn btn-primary pull-right" id="save-btn">保存</a>
      </div>
    </div>
  </div>
{% endblock %}


{% block script %}
  <script src="/static/js/admin/news/news_hot_add.js"></script>
{% endblock %}

static/js/admin/news/news_hot_add.js

// 创建static/js/admin/news/news_hot_add.js文件

$(function () {
  let $tagSelect = $("#category-select");   // 获取选择分类标签元素
  let $newsSelect = $("#news-select");      // 获取选择文章标签元素
  let $saveBtn = $('#save-btn');            // 获取保存按钮元素

  // 选择文章不同类别,获取相应的文章
  $tagSelect.change(function () {
    // 获取当前选中的下拉框的value
    let sTagId = $(this).val();
    if (sTagId === '0') {
      $newsSelect.children('option').remove();
      $newsSelect.append(`<option value="0">--请选择文章--</option>`);
      return
    }
    // 根据文章分类id向后端发起get请求
    $.ajax({
      url: "/admin/tags/" + sTagId + "/news/",  // url尾部需要添加/
      type: "GET",
      dataType: "json",
    })
      .done(function (res) {
        if (res.errno === "0") {

          $newsSelect.children('option').remove();
          $newsSelect.append(`<option value="0">--请选择文章--</option>`);
          res.data.news.forEach(function (one_news) {
            let content = `<option value="${one_news.id}">${one_news.title}</option>`;
            $newsSelect.append(content)
          });

        } else {
          // swal.showInputError(res.errmsg);
          fAlert.alertErrorToast(res.errmsg);
        }
      })
      .fail(function () {
        message.showError('服务器超时,请重试!');
      });

  });

  // 点击保存按钮执行的事件
  $saveBtn.click(function () {
    // 获取优先级
    let priority = $("#priority").val();
    // 获取下拉框中选中的文章标签id 和 文章id
    let sTagId = $tagSelect.val();
    let sNewsId = $newsSelect.val();
    // 打印值
    console.log(`
          priority(优先级): ${priority}
          tagId(文章标签id): ${sTagId}
          newsId(文章id): ${sNewsId}
    `);
    // 判断是否为 0, 表示在第一个 未选择
    if (sTagId !== '0' && sNewsId !== '0' && priority !== '0') {

      let sDataParams = {
        "priority": priority,
        "news_id": sNewsId
      };

      $.ajax({
        // 请求地址
        url: "/admin/hotnews/add/",  // url尾部需要添加/
        // 请求方式
        type: "POST",
        data: JSON.stringify(sDataParams),
        // 请求内容的数据类型(前端发给后端的格式)
        contentType: "application/json; charset=utf-8",
        // 响应数据的格式(后端返回给前端的格式)
        dataType: "json",
      })
        .done(function (res) {
          if (res.errno === "0") {
            message.showSuccess("热门文章创建成功");

            setTimeout(function () {
              // window.location.href = '../../../../apps/admin/hotnews/';
              window.location.href = '../../../../admin/hotnews/';
            }, 800)
          } else {
            // swal.showInputError(res.errmsg);
            message.showError(res.errmsg);
          }
        })

        .fail(function () {
          message.showError('服务器超时,请重试!');
        });

    } else {
      message.showError("文章分类、文章以及优先级都要选!");
    }
  });


    // get cookie using jQuery
  function getCookie(name) {
    let cookieValue = null;
    if (document.cookie && document.cookie !== '') {
      let cookies = document.cookie.split(';');
      for (let i = 0; i < cookies.length; i++) {
        let cookie = jQuery.trim(cookies[i]);
        // Does this cookie string begin with the name we want?
        if (cookie.substring(0, name.length + 1) === (name + '=')) {
          cookieValue = decodeURIComponent(cookie.substring(name.length + 1));
          break;
        }
      }
    }
    return cookieValue;
  }

  function csrfSafeMethod(method) {
    // these HTTP methods do not require CSRF protection
    return (/^(GET|HEAD|OPTIONS|TRACE)$/.test(method));
  }

  // Setting the token on the AJAX request
  $.ajaxSetup({
    beforeSend: function (xhr, settings) {
      if (!csrfSafeMethod(settings.type) && !this.crossDomain) {
        xhr.setRequestHeader("X-CSRFToken", getCookie('csrftoken'));
      }
    }
  });




});
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值