wordpress 面板站長工具seo綜合查詢降級
文章目錄
- 一、工程目錄組織結構
- 二、模型及管理實現(xiàn)
- 1、模型
- 2、admin管理
- 三、博客展現(xiàn)實現(xiàn)
- 1、視圖實現(xiàn)
- 2、模板實現(xiàn)
- 四、部署及效果
- 五、源代碼
Django作為一款成熟的Python Web開發(fā)框架提供了豐富的內(nèi)置功能,如ORM(對象關系映射)、Admin管理界面、URL分發(fā)、模板系統(tǒng)、表單處理等,使得開發(fā)者能夠快速搭建Web應用,大幅提高了開發(fā)效率。以前寫過一篇博文《 Django+Vue快速實現(xiàn)博客網(wǎng)站》介紹了通過Djang+Vue快速實現(xiàn)博客網(wǎng)站,django+vue作為個人博客來說稍顯復雜,部署起來也比較麻煩,Vue的單頁面架構也不利于SEO,更簡單的解決方案其實還是用django的模板系統(tǒng)快速構建web應用,對于個人博客來說部署和運維更加簡單也利于SEO。下面介紹如何快速的通過django模板系統(tǒng)快速實現(xiàn)個人博客。
一、工程目錄組織結構
二、模型及管理實現(xiàn)
模型及管理端的實現(xiàn)沿用《Django+Vue快速實現(xiàn)博客網(wǎng)站》文章中的實現(xiàn),用Django搭建很快很簡單。
模型很簡單,根據(jù)博客要顯示的內(nèi)容包括有‘文章分類’、‘文章標簽’、‘博客文章’、‘站點信息’、‘社交信息’、‘聚焦’,模型定義分別如下: 這里要說明的是因為博客文章內(nèi)容準備用markdown編寫,所以引入了mdeditor from mdeditor.fields import MDTextField
內(nèi)容字段content=MDTextField(verbose_name='內(nèi)容')
模型代碼示例如下:
1、模型
from django.db import models
from common.basemodel import BaseModel
from mdeditor.fields import MDTextField
# Create your models here.
'''文章分類'''
class BlogCategory(BaseModel):id = models.AutoField(primary_key=True)title = models.CharField(max_length=50,verbose_name='分類名稱',default='')href = models.CharField(max_length=100,verbose_name='分類路徑',default='')def __str__(self):return self.titleclass Meta:verbose_name = '文章分類'verbose_name_plural = '文章分類''''文章標簽'''class Tag(BaseModel):id=models.AutoField(primary_key=True)tag=models.CharField(max_length=20, verbose_name='標簽')def __str__(self):return self.tagclass Meta:verbose_name='標簽'verbose_name_plural='標簽''''博客文章'''
class BlogPost(BaseModel):id = models.AutoField(primary_key=True)title = models.CharField(max_length=200, verbose_name='文章標題', unique = True)category = models.ForeignKey(BlogCategory, blank=True,null=True, verbose_name='文章分類', on_delete=models.DO_NOTHING)isTop = models.BooleanField(default=False, verbose_name='是否置頂')isHot = models.BooleanField(default=False, verbose_name='是否熱門')isShow = models.BooleanField(default=False, verbose_name='是否顯示')summary = models.TextField(max_length=500, verbose_name='內(nèi)容摘要', default='')content = MDTextField(verbose_name='內(nèi)容')viewsCount = models.IntegerField(default=0, verbose_name="查看數(shù)")commentsCount = models.IntegerField(default=0, verbose_name="評論數(shù)")tags = models.ManyToManyField(to=Tag, related_name="tag_post", blank=True, default=None, verbose_name="標簽")blogSource = models.CharField(max_length=200, blank=True, null=True, default='',verbose_name='文章來源')pubTime = models.DateTimeField(blank=True, null=True, verbose_name='發(fā)布日期')@propertydef tag_list(self):return ','.join([i.tag for i in self.tags.all()])def __str__(self):return self.titleclass Meta:verbose_name = '博客文章'verbose_name_plural = '博客文章''''站點信息'''class Site(BaseModel):id = models.AutoField(primary_key=True)name = models.CharField(max_length=50, verbose_name='站點名稱', unique = True)avatar = models.CharField(max_length=200, verbose_name='站點圖標')slogan = models.CharField(max_length=200, verbose_name='站點標語')domain = models.CharField(max_length=200, verbose_name='站點域名')notice = models.CharField(max_length=200, verbose_name='站點備注')desc = models.CharField(max_length=200, verbose_name='站點描述')def __str__(self):return self.nameclass Meta:verbose_name = '站點信息'verbose_name_plural = '站點信息''''社交信息'''class Social(BaseModel):id = models.AutoField(primary_key=True)title = models.CharField(max_length=20, verbose_name='標題')icon = models.CharField(max_length=200, verbose_name='圖標')color = models.CharField(max_length=20, verbose_name='顏色')href = models.CharField(max_length=100, verbose_name='路徑')def __str__(self):return self.titleclass Meta:verbose_name = '社交信息'verbose_name_plural = '社交信息''''聚焦'''class Focus(BaseModel):id = models.AutoField(primary_key=True)title = models.CharField(max_length=20, verbose_name='標題')img = models.CharField(max_length=100, verbose_name='路徑')def __str__(self):return self.titleclass Meta:verbose_name = '聚焦'verbose_name_plural = '聚焦''''友鏈'''class Friend(BaseModel):id = models.AutoField(primary_key=True)siteName = models.CharField(max_length=20, verbose_name='友鏈站點名稱')path = models.CharField(max_length=100, verbose_name='地址路徑')desc = models.CharField(max_length=200, verbose_name='描述')def __str__(self):return self.siteNameclass Meta:verbose_name = '友鏈'verbose_name_plural = '友鏈'
2、admin管理
實際上只要把模型注冊到admin就可以了
from django.contrib import admin
from blog.models import *
# Register your models here.
@admin.register(BlogCategory)
class BlogCategoryAdmin(admin.ModelAdmin):admin.site.site_title="ishareblog后臺"admin.site.site_header="ishareblog后臺"admin.site.index_title="ishareblog管理"list_display = ['id', 'title', 'href']@admin.register(BlogPost)
class BlogPostAdmin(admin.ModelAdmin):list_display = ['title','category','isTop','isHot']search_fields = ('title',)@admin.register(Site)
class SiteAdmin(admin.ModelAdmin):list_display = ['name','slogan','domain','desc']@admin.register(Social)
class SocialAdmin(admin.ModelAdmin):list_display = ['title','href']@admin.register(Focus)
class FoucusAdmin(admin.ModelAdmin):list_display = ['title','img']@admin.register(Friend)
class FoucusAdmin(admin.ModelAdmin):list_display = ['siteName','path','desc']@admin.register(Tag)
class TagAdmin(admin.ModelAdmin):list_display = ['id','tag']
三、博客展現(xiàn)實現(xiàn)
博客前端展現(xiàn)用django的模板技術實現(xiàn)。在網(wǎng)上找了一個基于Bootstrap v4.3.1的小清新風格HTML博客模板,https://gitee.com/yinqi/Light-Year-Blog 這個博客模只有三個頁面,首頁,詳細頁和About頁面,樣式和js都不多,比較簡單。將html模板放入到templates的blog目錄,為了便于維護將一些公共部分抽到了base.html,index.html和post.html 通過{% extends 'blog/base.html' %}
進行應用
1、視圖實現(xiàn)
from django.http import HttpResponse, Http404
from django.template import loader
from django.core.paginator import Paginator
from blog.models import BlogPost, Tag, BlogCategory
from django.shortcuts import render
from django.db.models import Count
from django.db.models.functions import TruncYearimport markdown2# 首頁/列表頁視圖實現(xiàn).
def index(request):category_id = request.GET.get('category')tag_id = int(request.GET.get('tag',0))year = request.GET.get('year')search = request.GET.get('search')if category_id:blogpost_list = BlogPost.objects.filter(category=category_id, isShow=True).order_by('-isTop', '-pubTime')elif tag_id:blogpost_list = BlogPost.objects.filter(tags__id=tag_id, isShow=True).order_by('-isTop', '-pubTime')elif year:blogpost_list = BlogPost.objects.filter(pubTime__year=year, isShow=True).order_by('-isTop', '-pubTime')elif search:blogpost_list = BlogPost.objects.filter(content__icontains=search, isShow=True).order_by('-isTop', '-pubTime')else:# 篩選出需要顯示的博客文章blogpost_list = BlogPost.objects.filter(isShow=True).order_by('-isTop', '-pubTime', '-update_time')# 每頁顯示的數(shù)量per_page = 10# 創(chuàng)建分頁器實例paginator = Paginator(blogpost_list, per_page)# 獲取當前頁碼,如果沒有提供,則默認為第一頁page_number = request.GET.get('page') or 1# 獲取當前頁的數(shù)據(jù)page_obj = paginator.get_page(page_number)# 計算顯示的頁碼范圍current_page = int(page_number)pages_to_show = 11 # 當前頁前后各5頁加上當前頁共11頁start_page = max(current_page - 5, 1)end_page = min(start_page + pages_to_show - 1, paginator.num_pages)template = loader.get_template("blog/index.html")context = {"page_obj": page_obj,'start_page': start_page,'end_page': end_page,'hot_posts': get_hot_posts(),'tags': get_all_tags(),'post_grouped_by_year':get_post_groped_by_year(),'categories': get_categories(),'category_id': category_id,'tag_id': tag_id,'year': year,'search': search,}return HttpResponse(template.render(context, request))# 詳情頁視圖實現(xiàn).
def post_detail(request, id):try:post_obj = BlogPost.objects.get(id=id)html_content = markdown2.markdown(post_obj.content,extras=["code-color", "fenced-code-blocks", "cuddled-lists", "tables","with-toc", "highlightjs-lang"])html_content = html_content.replace('<table>', '<table class="table table-bordered">')html_content = html_content.replace('<img src=', '<img style="max-width:100%;height:auto;" src=')context = {"post_obj": post_obj, "html_content": html_content, "hot_posts": get_hot_posts(),"tags": get_all_tags(),"post_grouped_by_year":get_post_groped_by_year(),'categories': get_categories()}except BlogPost.DoesNotExist:raise Http404("Post does not exist")return render(request, "blog/post.html", context)def get_hot_posts():# 獲取點贊數(shù)最高的前5篇文章hot_posts = BlogPost.objects.filter(isShow=True).order_by('-viewsCount', '-pubTime')[:5]return hot_postsdef get_all_tags():# 獲取所有的標簽tags = Tag.objects.all() # 獲取所有的標簽return tagsdef get_post_groped_by_year():# 將發(fā)布日期截斷為年份,并計算每年的文章數(shù)量。post_grouped_by_year = (BlogPost.objects.annotate(year=TruncYear('pubTime')).values('year') # 返回的字典包含'year'鍵.annotate(publication_count=Count('id')) # 計算每年的文章數(shù)量.order_by('-year') # 按年排序)return post_grouped_by_yeardef get_categories():# 獲取所有分類categories = BlogCategory.objects.all()return categories
2、模板實現(xiàn)
靜態(tài)文件如css、js等放到static的blog目錄,html模板文件放到templates的blog目錄
在setting.py文件中配置 STATIC_URL = 'static/'
,在html模板文件中通過{% load static %}
將靜態(tài)文件的地址引用進來
將公共部分抽取出來形成base.html
{% load static %}
<!DOCTYPE HTML>
<html>
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<title>XieJava的博客</title>
<meta name="viewport" content="width=device-width, initial-scale=1">
<meta name="description" content="" />
<meta name="keywords" content="" />
<meta name="author" content="xiejava" />
<link rel="shortcut icon" type="image/x-icon" href="favicon.ico" />
<link rel="stylesheet" type="text/css" href="{% static 'blog/css/bootstrap.min.css' %}" />
<link rel="stylesheet" type="text/css" href="{% static 'blog/css/materialdesignicons.min.css' %}" />
<link rel="stylesheet" type="text/css" href="{% static 'blog/css/style.min.css' %}" />
</head>
<body>
<header class="lyear-header text-center" style="background-image:url(images/left-bg.jpg);"><div class="lyear-header-container"><div class="lyear-mask"></div><h1 class="lyear-blogger pt-lg-4 mb-0"><a href="{% url 'index' %}">XieJava的博客</a></h1><nav class="navbar navbar-expand-lg"><a class="navbar-toggler" data-toggle="collapse" data-target="#navigation" aria-controls="navigation" aria-expanded="false" aria-label="Toggle navigation"><div class="lyear-hamburger"><div class="hamburger-inner"></div></div></a><div id="navigation" class="collapse navbar-collapse flex-column"><div class="profile-section pt-3 pt-lg-0"><img class="profile-image mb-3 rounded-circle mx-auto" src="https://img9.doubanio.com/icon/ul70489051-4.jpg" width="120" height="120" alt="xiejava" ><div class="lyear-sentence mb-3">記錄最好的自己<br>寫是為了更好的思考,堅持寫作,力爭更好的思考。</div><hr></div><ul class="navbar-nav flex-column text-center"><li class="nav-item active"><a class="nav-link" href="{% url 'index' %}">首頁</a></li>{% for category in categories %}<li class="nav-item"><a class="nav-link" href="{% url 'index' %}?category={{ category.id }}">{{ category.title }}</a></li>{% endfor %}<li class="nav-item"><a class="nav-link" href="{% url 'index' %}">關于我</a></li></ul><div class="my-2 my-md-3"><form class="lyear-search-form form-inline justify-content-center pt-3"><input type="text" id="search" name="search" class="form-control mr-md-1" placeholder="搜索關鍵詞" /></form></div><!--<div ><img style="max-width:60%;height:auto;" src="https://xiejava1018.github.io/xiejavaimagesrc/images/fullbug微信公眾號.jpg" alt="“fullbug”微信公眾號" title="“fullbug”微信公眾號"></div><div class="container d-flex align-items-end"><div class="copyright text-center pb-3">? 2019. XieJava的博客. All rights reserved.</div></div>--></div></nav></div>
</header>
<div class="lyear-wrapper"><section class="mt-5 pb-5"><div class="container"><div class="row"><!-- 文章列表 --><div class="col-xl-8"><!-- 內(nèi)容 -->{% block content %}<!-- 默認內(nèi)容 -->{% endblock %}</div><!-- 內(nèi)容 end --><!-- 側(cè)邊欄 --><div class="col-xl-4"><div class="lyear-sidebar"><!-- 熱門文章 --><aside class="widget widget-hot-posts"><div class="widget-title">熱門文章</div><ul>{% for post in hot_posts %}<li><a href="{% url 'post_detail' id=post.id %}">{{ post.title }}</a> <span>{{ post.pubTime }}</span></li>{% endfor %}</ul></aside><!-- 歸檔 --><aside class="widget"><div class="widget-title">歸檔</div><ul>{% for post in post_grouped_by_year %}<li><a href="{% url 'index' %}?year={{ post.year|date:'Y' }}" >{% if year == post.year|date:'Y' %}<b>{{ post.year|date:'Y' }} 年 </b>{% else %}{{ post.year|date:'Y' }} 年{% endif %}</a> ({{ post.publication_count }})</li>{% endfor %}</ul></aside><!-- 標簽 --><aside class="widget widget-tag-cloud"><div class="widget-title">標簽 </div><div class="tag-cloud">{% for tag in tags %}<a href="{% url 'index' %}?tag={{ tag.id }}" {% if tag_id == tag.id %}class="badge badge-primary"{% else %}class="badge badge-light"{% endif %}>{{ tag.tag }}</a>{% endfor %}</div></aside></div></div><!-- 側(cè)邊欄 end --></div></div><!-- end container --></section>
</div>
<script type="text/javascript" src="{% static 'blog/js/jquery.min.js' %}"></script>
<script type="text/javascript" src="{% static 'blog/js/jquery.nicescroll.min.js' %}"></script>
<script type="text/javascript" src="{% static 'blog/js/bootstrap.min.js' %}"></script>
<script type="text/javascript" src="{% static 'blog/js/main.min.js' %}"></script>
</body>
</html>
博客首頁/列表頁
通過{% extends 'blog/base.html' %}
將公共部門引入進來后index.html的內(nèi)容就簡潔了很多
index.html
{% extends 'blog/base.html' %}<!-- 內(nèi)容 -->
{% block content %}{% if page_obj.object_list.count > 0 %}{% for blogpost in page_obj.object_list %}<article class="lyear-arc"><div class="arc-header"><h2 class="arc-title"><a href="article/{{ blogpost.id }}">{{ blogpost.title }}</a></h2><ul class="arc-meta"><li><i class="mdi mdi-calendar"></i> {{ blogpost.pubTime }}</li><li><i class="mdi mdi-tag-text-outline"></i> {% for tag in blogpost.tags.all %}<a href="{% url 'index' %}?tag={{ tag.id }}">{{ tag.tag }}</a> {% endfor %}</li><!--<li><i class="mdi mdi-comment-multiple-outline"></i> <a href="#">3 評論</a></li>--><li><i class="mdi mdi-heart-outline"></i> <a href="#">{{ blogpost.viewsCount }} 喜歡</a></li></ul></div><div class="arc-synopsis"><p>{{ blogpost.summary }}</p></div></article>{% endfor %}<!-- 分頁 --><div class="row"><div class="col-lg-12"><ul class="pagination">{% if page_obj.has_previous %}<li class="page-item"><a class="page-link" href="?page={{ page_obj.previous_page_number }}"><i class="mdi mdi-chevron-left"></i></a></li>{% endif %}<!--<li class="page-item active"><a class="page-link" href="#">1</a></li><li class="page-item"><a class="page-link" href="#">2</a></li><li class="page-item"><a class="page-link" href="#">3</a></li><li class="page-item"><a class="page-link" href="#">4</a></li><li class="page-item"><a class="page-link" href="#">5</a></li>-->{% for page_no in page_obj.paginator.page_range %}{% if page_no >= start_page and page_no <= end_page %}{% if page_no == page_obj.number %}<li class="page-item active"><a class="page-link" href="#">{{ page_no }}</a></li>{% else %}<li class="page-item"><a class="page-link" href="?page={{ page_no }}{% if tag_id %}&tag={{ tag_id }}{% endif %}{% if year %}&year={{ year }}{% endif %}{% if search %}&search={{ search }}{% endif %}">{{ page_no }}</a></li>{% endif %}{% endif %}{% endfor %}{% if page_obj.has_next %}<li class="page-item"><a class="page-link" href="?page={{ page_obj.next_page_number }}{% if tag_id %}&tag={{ tag_id }}{% endif %}{% if year %}&year={{ year }}{% endif %}{% if search %}&search={{ search }}{% endif %}"><i class="mdi mdi-chevron-right"></i></a></li>{% endif %}<p>總頁數(shù): {{ page_obj.paginator.num_pages}}</p></ul></div></div>{% else %}<p> 沒有找到文章 </p>{% endif %}<!-- 分頁 end -->
{% endblock %}
<!-- 內(nèi)容 end -->
博客詳情頁post.html
{% extends 'blog/base.html' %}
<!-- 文章閱讀 -->{% block content %}<article class="lyear-arc"><div class="arc-header"><h2 class="arc-title"><a href="#">{{ post_obj.title }}</a></h2><ul class="arc-meta"><li><i class="mdi mdi-calendar"></i> {{ post_obj.pubTime }}</li><li> {% for tag in post_obj.tags.all %}<a href="{% url 'index' %}?tag={{ tag.id }}">{{ tag.tag }}</a>{% endfor %}</li><!--<li><i class="mdi mdi-comment-multiple-outline"></i> <a href="#">3 評論</a></li>--><li><i class="mdi mdi-heart-outline"></i> <a href="#">{{ post_obj.viewsCount }} 喜歡</a></li></ul></div><div class="arc-preview"><img src="images/blog/post-1.png" alt="" class="img-fluid rounded" /></div><div class="lyear-arc-detail">{{ html_content|safe }}</div></article>{% endblock %}
<!-- 內(nèi)容 end -->
四、部署及效果
在部署之前執(zhí)行python manage.py collectstatic
將admin等其他模塊用到的靜態(tài)文件統(tǒng)一輸出到static的目錄。
通過 python manage.py runserver
啟動應用就可以看到效果。
實際效果見 http://iblog.ishareread.com/
博客首頁
博客詳情頁
五、源代碼
所有源代碼及說明見 https://gitee.com/xiejava/ishareblog
博客地址:http://xiejava.ishareread.com/