上一張文章模塊分析已經(jīng)寫到了需要實(shí)現(xiàn)哪些模塊哪些功能,現(xiàn)在這一章就講具體怎么實(shí)現(xiàn)這些功能。
一、文章數(shù)據(jù)庫模型設(shè)計(jì)
根據(jù)文章模塊分析中數(shù)據(jù)表的各字段和表之間的關(guān)系進(jìn)行創(chuàng)建數(shù)據(jù)庫表
1. 文章標(biāo)簽表
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="文章標(biāo)題", help_text="文章標(biāo)題")
class Meta:
ordering = ["-update_time", "-id"] # 排序方式
db_table = "tb_tags"
verbose_name = "文章標(biāo)簽" # 在admins站點(diǎn)中的名字
verbose_name_plural = verbose_name # 顯示復(fù)數(shù)的名字
def __str__(self):
return "文章標(biāo)簽:{}".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 :主表刪除后,從表設(shè)置為NULL
# SET_DEFAULT :主表刪除后,從表設(shè)置為默認(rèn)值
# SET :主表刪除后,從表調(diào)用一個(gè)可執(zhí)行對(duì)象,然后將值返回給從表
# DO_NOTHING :主表刪除后,從表什么都不做
title = models.CharField(max_length=150, verbose_name="文章標(biāo)題", help_text="文章標(biāo)題")
digest = models.CharField(max_length=200, verbose_name="文章摘要", help_text="文章摘要")
content = models.TextField(verbose_name="評(píng)論內(nèi)容", help_text="評(píng)論內(nèi)容")
clicks = models.IntegerField(default=0, verbose_name="文章點(diǎn)擊量", help_text="文章點(diǎn)擊量")
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 "文章標(biāo)題:{}".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, "第一級(jí)"),
(2, "第二級(jí)"),
(3, "第三級(jí)"),
]
priority = models.IntegerField(default=3, choices=PRI_CHOICES, verbose_name="優(yōu)先級(jí)", help_text="優(yōu)先級(jí)")
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 "優(yōu)先級(jí):{}".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, "第一級(jí)"),
(2, "第二級(jí)"),
(3, "第三級(jí)"),
(4, "第四級(jí)"),
(5, "第五級(jí)"),
(6, "第六級(jí)"),
]
image_url = models.URLField(default="", verbose_name="輪播圖url", help_text="輪播圖url")
priority = models.IntegerField(default=6, choices=PRI_CHOICES, verbose_name="優(yōu)先級(jí)", help_text="優(yōu)先級(jí)")
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 "優(yōu)先級(jí):{}".format(self.priority)
5. 評(píng)論表
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="評(píng)論內(nèi)容", help_text="評(píng)論內(nèi)容")
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) # 自我關(guān)聯(lián),多級(jí)評(píng)論,blank允許前端不傳數(shù)據(jù)
class Meta:
ordering = ["-update_time", "-id"]
db_table = "tb_comments"
verbose_name = "評(píng)論內(nèi)容"
verbose_name_plural = verbose_name
# 自定義字典轉(zhuǎn)化
def to_dict_data(self):
comment_dict_data = {
"comment_id": self.id, # 評(píng)論id
"article_id": self.article.id, # 文章id
"content": self.content, # 評(píng)論內(nèi)容
"update_time": self.update_time.strftime("%Y年%m月%d日 %H:%M"), # 更新日期
"author": self.author.username, # 評(píng)論人
"parent": self.parent.to_dict_data() if self.parent else None # 二級(jí)評(píng)論
}
return comment_dict_data
def __str__(self):
return "評(píng)論內(nèi)容:{}".format(self.content)
6. 公用表
每個(gè)表格公用的字段創(chuàng)建一個(gè)公用的來繼承,少些代碼
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="創(chuàng)建時(shí)間")
update_time = models.DateTimeField(auto_now=True, verbose_name="更新時(shí)間")
is_delete = models.BooleanField(default=False, verbose_name="邏輯刪除")
class Meta:
abstract = True # 用于其他模型繼承,在數(shù)據(jù)遷移時(shí)不會(huì)創(chuàng)建表格
-
創(chuàng)建完后進(jìn)行數(shù)據(jù)表的創(chuàng)建和遷移,使用Run manage.py Task…
makemigrations news # 生成表格
mkmigrate news # 遷移表格
-
添加測試數(shù)據(jù)
使用navicate直接添加sql數(shù)據(jù)文件,添加時(shí)要注意文件名要跟數(shù)據(jù)表對(duì)應(yīng)
二、文章標(biāo)簽功能和熱門文章功能
1. 路由urls.py設(shè)置
項(xiàng)目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. 文章標(biāo)簽數(shù)據(jù)獲取
tag_list = _models.Tags.objects.only("name", "id").filter(is_delete=False) # 標(biāo)簽數(shù)據(jù)
# 2. 熱門文章數(shù)據(jù)獲取
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數(shù)據(jù)填充
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 %}
{# 文章標(biāo)簽 #}
{% 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設(shè)置
項(xiàng)目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. 從數(shù)據(jù)庫中獲取數(shù)據(jù)
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. 數(shù)據(jù)序列化
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. 返回?cái)?shù)據(jù)到前端
return to_json_data(data=data)
3. 前端js實(shí)現(xiàn)
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;
// 小原點(diǎn)
$tabLi.click(function () {
index = $(this).index();
$(this).addClass('active').siblings('li').removeClass('active');
$picLi.eq(index).fadeIn(1500).siblings('li').fadeOut(1500);
});
// 點(diǎn)擊切換上一張
$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
});
// 圖片向前滑動(dòng)
function auto() {
index++;
index %= $tabLi.length;
$tabLi.eq(index).addClass('active').siblings('li').removeClass('active');
$picLi.eq(index).fadeIn(3000).siblings('li').fadeOut(3000);
}
// 定時(shí)器
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 //關(guān)閉異步
})
.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 接收后臺(tái)傳來的id號(hào) 響應(yīng)詳情頁 one_banner.news_id
content = `
<li style="display:block;"><a href="/news/${one_banner.article_id}/">
<img src="${one_banner.image_url}" alt="${one_banner.article_title}"></a></li>
`;
tab_content = `<li class="active"></li>`;
} else {
content = `
<li><a href="/news/${one_banner.article_id}/"><img src="${one_banner.image_url}" alt="${one_banner.article_title}"></a></li>
`;
tab_content = `<li></li>`;
}
$(".pic").append(content); // 內(nèi)容
$(".tab").append(tab_content); // 標(biāo)簽
});
} else {
// 登錄失敗,打印錯(cuò)誤信息
alert(res.errmsg);
}
})
.fail(function () {
alert('服務(wù)器超時(shí),請重試!');
});
}
});
|