搭建本身的博客(十八):添加熱門博客展現

一、變化的部分css

二、上代碼:html

from django.db import models
from django.contrib.auth.models import User
from django.contrib.contenttypes.fields import GenericRelation
from ckeditor_uploader.fields import RichTextUploadingField
from django.contrib.contenttypes.models import ContentType
from read_statistics.models import ReadNumExpandMethod, ReadDetail


# Create your models here.

# 博客分類
class BlogType(models.Model):
    type_name = models.CharField(max_length=15)  # 博客分類名稱

    def __str__(self):  # 顯示標籤名
        return self.type_name


# 博客
class Blog(models.Model, ReadNumExpandMethod):
    title = models.CharField(max_length=50)  # 博客標題
    blog_type = models.ForeignKey(BlogType, on_delete=models.DO_NOTHING)  # 博客分類
    content = RichTextUploadingField()  # 博客內容,使用富文本編輯
    author = models.ForeignKey(User, on_delete=models.DO_NOTHING)  # 博客做者
    read_details = GenericRelation(ReadDetail)  # 關聯到閱讀表
    created_time = models.DateTimeField(auto_now_add=True)  # 博客建立時間
    last_updated_time = models.DateTimeField(auto_now=True)  # 博客更新事件

    def __str__(self):  # 顯示標題名
        return "<Blog:{}>".format(self.title)

    class Meta:
        ordering = ['-created_time']  # 定義排序規則,按照建立時間倒序
models.py
"""
Django settings for myblog project.

Generated by 'django-admin startproject' using Django 2.1.3.

For more information on this file, see
https://docs.djangoproject.com/en/2.1/topics/settings/

For the full list of settings and their values, see
https://docs.djangoproject.com/en/2.1/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/2.1/howto/deployment/checklist/

# SECURITY WARNING: keep the secret key used in production secret!
SECRET_KEY = 'ea+kzo_5k^6r7micfg@lar1(rfdc08@b4*+w5d11=0mp1p5ngr'

# 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',
    'ckeditor',
    'ckeditor_uploader',
    'blog.apps.BlogConfig',  # 將本身建立的app添加到設置中
    'read_statistics.apps.ReadStatisticsConfig',  # 註冊閱讀統計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',
    'blog.middleware.mymiddleware.My404',  # 添加本身的中間件
]

ROOT_URLCONF = 'myblog.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 = 'myblog.wsgi.application'

# Database
# https://docs.djangoproject.com/en/2.1/ref/settings/#databases

DATABASES = {
    # 'default': {
    #     'ENGINE': 'django.db.backends.sqlite3',
    #     'NAME': os.path.join(BASE_DIR, 'db.sqlite3'),
    # }
    'default': {
        'ENGINE': 'django.db.backends.mysql',
        'NAME': 'myblogs',  # 要鏈接的數據庫,鏈接前須要建立好
        'USER': 'root',  # 鏈接數據庫的用戶名
        'PASSWORD': 'felixwang',  # 鏈接數據庫的密碼
        'HOST': '127.0.0.1',  # 鏈接主機,默認本級
        'PORT': 3306  # 端口 默認3306
    }
}

# Password validation
# https://docs.djangoproject.com/en/2.1/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/2.1/topics/i18n/

# LANGUAGE_CODE = 'en-us'
# 語言
LANGUAGE_CODE = 'zh-hans'

# TIME_ZONE = 'UTC'
# 時區
TIME_ZONE = 'Asia/Shanghai'

USE_I18N = True

USE_L10N = True

# 不考慮時區
USE_TZ = False

# Static files (CSS, JavaScript, Images)
# https://docs.djangoproject.com/en/2.1/howto/static-files/

STATIC_URL = '/static/'
STATICFILES_DIRS = [
    os.path.join(BASE_DIR, "static")
]

# media
MEDIA_URL = '/media/'
MEDIA_ROOT = os.path.join(BASE_DIR, 'media')

# 配置ckeditor
CKEDITOR_UPLOAD_PATH = 'upload/'

# 自定義參數
EACH_PAGE_BLOGS_NUMBER = 7


# 設置數據庫緩存
CACHES = {
    'default': {
        'BACKEND': 'django.core.cache.backends.db.DatabaseCache',
        'LOCATION': 'my_read_num_cache_table',
    }
}
settings.py
# -*- coding: utf-8 -*-
# @Time    : 18-11-7 下午4:12
# @Author  : Felix Wang

from django.shortcuts import render_to_response
from django.contrib.contenttypes.models import ContentType
from read_statistics.utils import get_seven_days_read_data, get_x_days_hot_data
from blog.models import Blog


def home(requests):
    blog_content_type = ContentType.objects.get_for_model(Blog)
    dates, read_nums = get_seven_days_read_data(blog_content_type)

    context = {
        'read_nums': read_nums,
        'dates': dates,
        'today_hot_data': get_x_days_hot_data(0),  # 獲取今日熱門
        'yesterday_hot_data': get_x_days_hot_data(1),  # 獲取昨日熱門
        'seven_days_hot_data': get_x_days_hot_data(7),  # 獲取周熱門
        'one_month_hot_data': get_x_days_hot_data(30),  # 獲取月熱門
    }
    return render_to_response('home.html', context)
views.py
# -*- coding: utf-8 -*-
# @Time    : 18-11-17 下午10:03
# @Author  : Felix Wang
import datetime
from django.contrib.contenttypes.models import ContentType
from django.db.models import Sum
from django.utils import timezone
from django.core.cache import cache
from .models import ReadNum, ReadDetail
from blog.models import Blog


def read_statistics_once_read(requests, obj):
    ct = ContentType.objects.get_for_model(obj)
    key = '{}_{}_read'.format(ct.model, obj.pk)

    # 獲取並處理閱讀計數
    if not requests.COOKIES.get(key):
        # 總閱讀量+1
        readnum, created = ReadNum.objects.get_or_create(content_type=ct, object_id=obj.pk)
        # 處理閱讀量
        readnum.read_num += 1
        readnum.save()

        # 當天閱讀量+1
        date = timezone.now().date()
        readDetail, created = ReadDetail.objects.get_or_create(content_type=ct, object_id=obj.pk, date=date)
        readDetail.read_num += 1
        readDetail.save()

    return key


def get_seven_days_read_data(content_type):
    today = timezone.now().date()
    dates = []
    read_nums = []
    for i in range(7, 0, -1):  # 統計7天的閱讀量
        date = today - datetime.timedelta(days=i)
        dates.append(date.strftime('%m/%d'))  # 將日期格式轉成字符串
        read_details = ReadDetail.objects.filter(content_type=content_type, date=date)
        result = read_details.aggregate(read_num_sum=Sum('read_num'))
        read_nums.append(result['read_num_sum'] or 0)  # 若是有閱讀量則閱讀量不然置0
    return dates, read_nums


# 獲取某天的閱讀量綜合
def get_x_days_hot_data(x_days):
    # 若是緩存有值,取緩存的值
    cache_data = cache.get('cache_data_for_{}_days'.format(x_days))
    if cache_data:
        return cache_data

    today = timezone.now().date()
    if x_days == 0:  # 表示今天
        date_blogs = Blog.objects.filter(read_details__date=today)
    else:  # 不等於0表示往前多少天
        date = today - datetime.timedelta(days=x_days)
        date_blogs = Blog.objects.filter(read_details__date__lt=today, read_details__date__gte=date)

    read_details = date_blogs.values('id', 'title').annotate(read_num_sum=Sum('read_details__read_num')).order_by(
        '-read_num_sum')[:7]  # 分組,求和

    cache.set('cache_data_for_{}_days'.format(x_days), read_details,
              3600 * 3 if x_days else 1800)  # 設置緩存,三小時更新一次,若是是當日閱讀量半小時更新一次
    return read_details
utils.py
.home-content {
    font-size: 222%;
    text-align: center;
    margin-top: 4em;
    margin-bottom: 2em;
}

div#container {
    margin: 0 auto;
    height: 20em;
    min-width: 20em;
    max-width: 30em;
}

div.hot-data {
    text-align: center;
    margin-top: 2em;
}

div.hot-data ul {
    list-style-type: none;
}
home.css
{% extends 'base.html' %}
{% load staticfiles %}


{% block header_extends %}
    <link rel="stylesheet" href="{% static 'css/home.css' %}">
    <script src="{% static 'Highcharts-6.2.0/code/highcharts.js' %}"></script>
{% endblock %}

{% block title %}
    個人博客|首頁
{% endblock %}

{% block content %}
    <h1 class="home-content">歡迎訪問個人博客</h1>
    <!-- 圖表容器 DOM -->
    <div id="container"></div>

    <div class="hot-data">
        <!-- 今天24小時內的熱門博客 -->
        <h3>今日熱門博客</h3>
        <ul>
            {% for hot_data in today_hot_data %}
                <li><a href="{% url 'blog_detail' hot_data.id %}">{{ hot_data.title }}</a>
                    ({{ hot_data.read_num_sum }})
                </li>
            {% empty %}
                <li>今日暫時沒有熱門博客</li>
            {% endfor %}
        </ul>
    </div>
    <div class="hot-data">
        <!-- 昨日的熱門博客 -->
        <h3>昨日熱門博客</h3>
        <ul>
            {% for hot_data in yesterday_hot_data %}
                <li><a href="{% url 'blog_detail' hot_data.id %}">{{ hot_data.title }}</a>
                    ({{ hot_data.read_num_sum }})
                </li>
            {% empty %}
                <li>昨日暫時沒有熱門博客</li>
            {% endfor %}
        </ul>
    </div>
    <div class="hot-data">
        <!-- 七日內的熱門博客 -->
        <h3>單週熱門博客</h3>
        <ul>
            {% for hot_data in seven_days_hot_data %}
                <li><a href="{% url 'blog_detail' hot_data.id %}">{{ hot_data.title }}</a>
                    ({{ hot_data.read_num_sum }})
                </li>
            {% empty %}
                <li>單週暫時沒有熱門博客</li>
            {% endfor %}
        </ul>
    </div>
    <div class="hot-data">
        <!-- 七日內的熱門博客 -->
        <h3>單月熱門博客</h3>
        <ul>
            {% for hot_data in one_month_hot_data %}
                <li><a href="{% url 'blog_detail' hot_data.id %}">{{ hot_data.title }}</a>
                    ({{ hot_data.read_num_sum }})
                </li>
            {% empty %}
                <li>單月暫時沒有熱門博客</li>
            {% endfor %}
        </ul>
    </div>
{% endblock %}

{% block js %}
    {# 表格操做 #}
    {#    <!-- 引入 highcharts.js -->#}
    <script>
        // 圖表配置
        let options = {
            chart: {
                type: 'line' //指定圖表的類型,默認是折線圖(line)
            },
            title: {
                text: null // 標題
            },
            xAxis: {
                categories: {{ dates|safe }}, // x 軸分類
                tickmarkPlacement: 'on',
                title: {
                    text: '前7日閱讀量'
                }
            },
            yAxis: {
                title: {
                    text: null // y 軸標題
                },
                labels: {
                    enabled: false
                },
                gridLineDashStyle: 'Dash',
            },
            plotOptions: {
                line: {
                    dataLabels: {
                        enabled: true
                    }
                }
            },
            credits: {
                enabled: false // 禁用版權信息
            },
            series: [{ // 數據列
                name: '閱讀量', // 數據列名
                data: {{ read_nums }},// 數據
                showInLegend: false, // 設置爲 false 即爲不顯示在圖例中
            },]
        };
        // 圖表初始化函數
        let chart = Highcharts.chart('container', options);
    </script>


    {# 將首頁這個按鈕設置激活狀態 #}
    <script>
        $(".nav-home").addClass("active").siblings().removeClass("active");
    </script>
{% endblock %}
home.html

三、解釋mysql

(1)、使用了django的數據庫緩存功能,不用每次都從數據庫中讀取數據,增長訪問速度。具體緩存見官網:官網地址sql

(2)、使用contenttype中的GenericRelation來關聯外表創建反向關係:具體件官網:官網地址數據庫

相關文章
相關標籤/搜索