Django blog项目《十》:文章模块1《数据模型、文章标签、热门文章、文章轮播图》

上一张文章模块分析已经写到了需要实现哪些模块哪些功能,现在这一章就讲具体怎么实现这些功能。

一、文章数据库模型设计

根据文章模块分析中数据表的各字段和表之间的关系进行创建数据库表

1. 文章标签表

news/models.py

from django.db import models
from utils.models import models as _models


class Tags(_models.BaseModel):
    """
    news tags model
    field:
        name            CharField
    """
    name = models.CharField(max_length=64, verbose_name="文章标题", help_text="文章标题")

    class Meta:
        ordering = ["-update_time", "-id"]  # 排序方式
        db_table = "tb_tags"
        verbose_name = "文章标签"                           # 在admins站点中的名字
        verbose_name_plural = verbose_name                 # 显示复数的名字

    def __str__(self):
        return "文章标签:{}".format(self.name)

2. 文章表

news/models.py

from django.db import models
from utils.models import models as _models


class Articles(_models.BaseModel):
    """
    create news model
    field:
        title           CharField
        digest          CharField
        clicks          CharField
        content         TextField
        image_url       URLField

        tag             ForeignKey
        author          ForeignKey
    """
    # CASCADE       :主表删除,从表全部删除
    # PROTECT       :
    # SET_NULL      :主表删除后,从表设置为NULL
    # SET_DEFAULT   :主表删除后,从表设置为默认值
    # SET           :主表删除后,从表调用一个可执行对象,然后将值返回给从表
    # DO_NOTHING    :主表删除后,从表什么都不做

    title = models.CharField(max_length=150, verbose_name="文章标题", help_text="文章标题")
    digest = models.CharField(max_length=200, verbose_name="文章摘要", help_text="文章摘要")
    content = models.TextField(verbose_name="评论内容", help_text="评论内容")
    clicks = models.IntegerField(default=0, verbose_name="文章点击量",  help_text="文章点击量")
    image_url = models.URLField(default=" ", verbose_name="图片url", help_text="图片url")

    tag = models.ForeignKey("Tags", on_delete=models.SET_NULL, null=True)
    author = models.ForeignKey("users.Users", on_delete=models.SET_NULL, null=True)

    class Meta:
        ordering = ["-update_time", "-id"]
        db_table = "tb_article"
        verbose_name = "文章"
        verbose_name_plural = verbose_name

    def __str__(self):
        return "文章标题:{}".format(self.title)

3. 热门文章表

news/models.py

from django.db import models
from utils.models import models as _models


class HotArticle(_models.BaseModel):
    """
    create hot news model
    field:
        priority        IntegerField
        news         ForeignKey
    """
    PRI_CHOICES = [
        (1, "第一级"),
        (2, "第二级"),
        (3, "第三级"),
    ]

    priority = models.IntegerField(default=3, choices=PRI_CHOICES, verbose_name="优先级", help_text="优先级")

    article = models.OneToOneField("Articles", on_delete=models.CASCADE)

    class Meta:
        ordering = ["-update_time", "-id"]
        db_table = "tb_hotarticle"
        verbose_name = "热门文章"
        verbose_name_plural = verbose_name

    def __str__(self):
        return "优先级:{}".format(self.priority)

4. 文章轮播图

news/models.py

from django.db import models
from utils.models import models as _models

class Banner(_models.BaseModel):
    """
    create news banner model
    field:
        priority        IntegerField
        image_url       URLField
        news         ForeignKey
    """
    PRI_CHOICES = [
        (1, "第一级"),
        (2, "第二级"),
        (3, "第三级"),
        (4, "第四级"),
        (5, "第五级"),
        (6, "第六级"),
    ]
    image_url = models.URLField(default="", verbose_name="轮播图url", help_text="轮播图url")
    priority = models.IntegerField(default=6, choices=PRI_CHOICES, verbose_name="优先级", help_text="优先级")

    article = models.OneToOneField("Articles", on_delete=models.CASCADE)

    class Meta:
        ordering = ["priority", "-update_time", "-id"]
        db_table = "tb_banner"
        verbose_name = "轮播图"
        verbose_name_plural = verbose_name

    def __str__(self):
        return "优先级:{}".format(self.priority)

5. 评论表

news/models.py

from django.db import models
from utils.models import models as _models

class Comments(_models.BaseModel):
    """
    create news comments models
    field:
        content
        author
        news
        parent
    """
    content = models.TextField(verbose_name="评论内容", help_text="评论内容")

    author = models.ForeignKey("users.Users", on_delete=models.SET_NULL, null=True)
    article = models.ForeignKey("Articles", on_delete=models.CASCADE)
    parent = models.ForeignKey("self", on_delete=models.CASCADE, null=True, blank=True)  # 自我关联,多级评论,blank允许前端不传数据

    class Meta:
        ordering = ["-update_time", "-id"]
        db_table = "tb_comments"
        verbose_name = "评论内容"
        verbose_name_plural = verbose_name

    # 自定义字典转化
    def to_dict_data(self):
        comment_dict_data = {
            "comment_id": self.id,  # 评论id
            "article_id": self.article.id,  # 文章id
            "content": self.content,  # 评论内容
            "update_time": self.update_time.strftime("%Y年%m月%d日 %H:%M"),  # 更新日期
            "author": self.author.username,  # 评论人
            "parent": self.parent.to_dict_data() if self.parent else None  # 二级评论
        }

        return comment_dict_data

    def __str__(self):
        return "评论内容:{}".format(self.content)

6. 公用表

每个表格公用的字段创建一个公用的来继承,少些代码

utils/models/models.py

from django.db import models


class BaseModel(models.Model):
    """
    base model,public field
    """
    create_time = models.DateTimeField(auto_now_add=True, verbose_name="创建时间")
    update_time = models.DateTimeField(auto_now=True, verbose_name="更新时间")
    is_delete = models.BooleanField(default=False, verbose_name="逻辑删除")

    class Meta:
        abstract = True   # 用于其他模型继承,在数据迁移时不会创建表格

  1. 创建完后进行数据表的创建和迁移,使用Run manage.py Task…

    makemigrations news  # 生成表格
    
    mkmigrate news		# 迁移表格
    
  2. 添加测试数据

    使用navicate直接添加sql数据文件,添加时要注意文件名要跟数据表对应

二、文章标签功能和热门文章功能

1. 路由urls.py设置

项目urls.py配置

from django.urls import path, include
from django.conf import settings
from django.conf.urls.static import static

urlpatterns = [
    path('news/', include("news.urls")),
] + static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)

news/urls.py配置

from django.urls import path
from news import views


app_name = "news"

urlpatterns = [
    path("index/", views.IndexView.as_view(), name="index"),
]

2. 后端view逻辑处理

news/views.py

from django.views import View
from django.shortcuts import render

from news import models as _models


class IndexView(View):

    """
    create index page
    news_tag

    """
    def get(self, request):
        # 1. 文章标签数据获取
        tag_list = _models.Tags.objects.only("name", "id").filter(is_delete=False)  # 标签数据

        # 2. 热门文章数据获取
        hot_article_list = _models.HotArticle.objects.select_related("article").only("id", "article__title",
                                                                                         "article__image_url").filter(is_delete=False).order_by("priority", "-update_time", "-id")

        return render(request, "news/index.html", locals())

3. 前端html数据填充

templates/news/index.html

{# 热门文章 #}
{% block hot_news %}
    <ul class="recommend-news">
        {% for hot_article in hot_article_list %}
            <li>
                <a href="/news/{{ hot_article.id }}" target="_blank">
                    <div class="recommend-thumbnail">
                        <img src="{{ hot_article.article.image_url }}" alt="title">
                    div>
                    <p class="info">{{ hot_article.article.titile }}p>
                a>
            li>
        {% endfor %}
    ul>
{% endblock %}



{# 文章标签 #}
{% block news_tags %}  
	<nav class="news-nav">
	  <ul class="clearfix">
	      <li class="active"><a href="javascript:void(0)" data-id="0">最新资讯a>li>
	      {% for tag in tag_list %}
	      <li><a href="javascript:void(0)" data-id="{{ tag.id }}">{{ tag.name }}a>li>
	      {% endfor %}
	  ul>
	nav>
{% endblock %}




三、文章轮播图

1. 路由urls.py设置

项目urls.py配置

from django.urls import path, include
from django.conf import settings
from django.conf.urls.static import static

urlpatterns = [
    path('news/', include("news.urls")),
] + static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)


news/urls.py配置

from django.urls import path
from news import views


app_name = "news"

urlpatterns = [
     path("banner/", views.BannerView.as_view(), name="banner"),
]


2. 后端view逻辑处理

news/views.py

from django.views import View
from django.shortcuts import render

from news import contains
from news import models as _models
from utils.res_code.json_function import to_json_data


class BannerView(View):
    """
    news banner image
    """
    def get(self, request):
        # 1. 从数据库中获取数据
        banner_queryset_list = _models.Banner.objects.select_related("article").only("image_url", "article__id",
                                                                            "article__title").filter(
            is_delete=False).order_by("priority", "-update_time", "-id")[0:contains.BANNER_IMAGE_NUMBER]

        banner_list = []
        # 2. 数据序列化
        for banner_queryset in banner_queryset_list:
            banner_list.append({
                    "image_url": banner_queryset.image_url,
                    "article_id": banner_queryset.article.id,
                    "article_title": banner_queryset.article.title,
                })

        data = {
            "banner_list": banner_list
        }

        # 3. 返回数据到前端
        return to_json_data(data=data)

3. 前端js实现

static/js/news/banner.js

$(function () {
    // 新闻轮播图功能
    fn_load_banner();

    let $banner = $('.banner');
    let $picLi = $(".banner .pic li");
    let $prev = $('.banner .prev');
    let $next = $('.banner .next');
    let $tabLi = $('.banner .tab li');
    let index = 0;

    // 小原点
    $tabLi.click(function () {
        index = $(this).index();
        $(this).addClass('active').siblings('li').removeClass('active');
        $picLi.eq(index).fadeIn(1500).siblings('li').fadeOut(1500);
    });


    // 点击切换上一张
    $prev.click(function () {
        index--;
        if (index < 0) {
            index = $tabLi.length - 1
        }
        $tabLi.eq(index).addClass('active').siblings('li').removeClass('active');
        $picLi.eq(index).fadeIn(1500).siblings('li').fadeOut(1500);
    }).mousedown(function () {
        return false
    });

    //切换下一张
    $next.click(function () {
        auto();
    }).mousedown(function () {
        return false
    });


    //  图片向前滑动
    function auto() {
        index++;
        index %= $tabLi.length;
        $tabLi.eq(index).addClass('active').siblings('li').removeClass('active');
        $picLi.eq(index).fadeIn(3000).siblings('li').fadeOut(3000);
    }

    // 定时器
    let timer = setInterval(auto, 2000);
    $banner.hover(function () {
        clearInterval(timer)
    }, function () {
        auto();
    });

    function fn_load_banner() {
        $.ajax({
            url: "/news/banner/",  // url尾部需要添加/// 请求地址
            type: "GET",// 请求方式
            async: false  //关闭异步
        })
            .done(function (res) {
                if (res.errno === "200") {
                    let content = ``;
                    let tab_content = ``;   //按钮
                    res.data.banner_list.forEach(function (one_banner, index) {
                        if (index === 0) {
                            // 需要修改 href  接收后台传来的id号 响应详情页  one_banner.news_id
                            content = `
                                
  • ${one_banner.article_id}/"> ${one_banner.image_url}" alt="${one_banner.article_title}">
  • `
    ; tab_content = `
  • `
    ; } else { content = `
  • ${one_banner.article_id}/">${one_banner.image_url}" alt="${one_banner.article_title}">
  • `
    ; tab_content = `
  • `
    ; } $(".pic").append(content); // 内容 $(".tab").append(tab_content); // 标签 }); } else { // 登录失败,打印错误信息 alert(res.errmsg); } }) .fail(function () { alert('服务器超时,请重试!'); }); } });

    你可能感兴趣的:(Django,框架)