一、变化的部分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'] # 定义排序规则,按照建立时间倒序
""" 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', } }
# -*- 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)
# -*- 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
.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; }
{% 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 %}
三、解释mysql
(1)、使用了django的数据库缓存功能,不用每次都从数据库中读取数据,增长访问速度。具体缓存见官网:官网地址sql
(2)、使用contenttype中的GenericRelation来关联外表创建反向关系:具体件官网:官网地址数据库