个人博客三|首页后台开发

1

声明:本渣渣部分代码参考自TendCode其实有很多代码是不需要自己一行行码出来,生产力是第一位。只有研究型人才需要生产代码,作为一名渣渣拿来用是最高效的做法。程序员都有一个开源的精神,码出来的代码本身是希望更多的人用到,应用到生产中。
参考编写博客的 Model 与首页面
整合资源也应该是一个码农的必备能力,在实际生产中可以更高效的工作

项目环境

windows10
python==3.6.6
django==1.11.1

知识准备

首先本渣渣想对django项目结构做一下梳理,如果有的读者对django不太熟悉,可能阅读有障碍。
对django基础做一下简单了解。

推荐阅读:

Django1.10 中文文档

大牛翻译的django基础部分

简单了解通用视图

开始 Django 开发之前,需要掌握以下知识:
• 创建 Django 工程,了解 Django 默认的工程目录结构
• 创建 Django APP
• 理解 Django 的MTV 模式,学会编写 Model、View、Template
• Django 如何处理静态文件,即各种 CSS,JS,以及图片文件等

推荐阅读:
个人博客-创建项目
Django中MVC与MVT设计模式

Django的工作流程

1、 用户通过浏览器输入相应的 URL 发起 HTTP 请求(一般是 GET/POST)
用户在网站前台做的每次操作都是一次HTTP请求的触发,通过触发的URL,和后台进行交互
2:Django后台接收到请求,检测 urls.py 文件,找到和用户请求的URL 相匹配的项,然后调用该 URL 对应的视图函数(view),在视图内进行逻辑呈现,然后渲染数据到模板展示给用户。

推荐阅读:

静态路由和动态路由

视图函数被调用后,可能会访问数据库(Model)去查询用户想要请求的数据,并加载模板文件(Template),渲染完数据后打包成 HttpResponse 返回给浏览器(Http协议)

从流程可以看出,开发者需要做的事情如下:
• 编写相应的 url
• 编写数据库(Model)
• 编写处理 Http 请求的视图函数(View)
• 编写需要渲染数据的模板(Template)

下面遵循这样的开发流程继续进行我们个人博客的开发:

虽然博客站点的django项目已经烂大街了,但是很多人还没意识到个人博客的价值,有时间我们可以谈谈这个问题。

第一版选择使用Django通用视图开发,后续升级前后端分离开发(正在学习中)

推荐阅读:

Django通用视图

ListView 和 DetailView

在接触到django到现在看到的教程大都没有采用django的通用视图,但是为了更好的认识django,在这里本渣渣,想尝试尽量在开发博客主体时使用通用视图

为什么选择使用通用视图

1、 目前在看到的django教程中大部分都未使用通用视图,顶多是继承通用类。这样你就没办法真正了解django框架,django独特之处就在于构建Web应用程序的常用功能已经在框架内,而不是单独的库。通用视图是Django为解决建站过程中的常见的呈现模式而建立的
通用视图使用原则
代码越少越好
永远不要重复代码
view应当只呈现逻辑, 不应包含业务逻辑
保持view逻辑清晰简单
2、 锻炼快速高效开发一类网站的能力
了解了通用视图你可以快速开发一类网站比如博客、论坛都有相似的需求

3、 组合方便
这里本渣渣的做法是扒取崔庆才个人博客前端源码,然后通过django实现网站后端开发,使用django 通用视图,可以缩短开发周期,而且能够具备使用django快速模仿一个网站的能力

下面不废话开干

按流程来,规范的流程少出错,严谨应该是一个码农的素养
目前项目文件结构

项目结构

1、前端

抓取崔庆才个人博客网站前端源码一文中抓取的崔庆才博客前端源码放入个人博客-创建项目一文中创建的项目中
https://www.jianshu.com/p/246...

2、配置基本信息

设置blog/settings.py
添加 apps 目录

 sys.path.insert(0, os.path.join(BASE_DIR, 'apps'))

settings.py

添加app

# Application definition
INSTALLED_APPS = [
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',
    
    'storm',
]

添加app

添加模板

ROOT_URLCONF = 'blog.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',
            ],
        },
    },
]

添加模板

连接数据库,首先要在本地数据库创建名为blog的数据库
这里需要用到数据库连接包,
请参考安装python包到虚拟环境安装包
Name: mysqlclient
Version: 1.4.2.post1

DATABASES = {
    'default': {
        'ENGINE': 'django.db.backends.mysql',
        'HOST': 'localhost',
        'PORT': '3306',
        'USER': 'root',
        'PASSWORD': 'root',
        'NAME': 'blog',
        # 如果创建的数据库是uft-8编码,映射数据库时出现警告,添加此行解决问题
        'OPTIONS': {
            'init_command': "SET sql_mode='STRICT_TRANS_TABLES'",
            'charset': 'utf8mb4',
        },
    }
}

连接数据库

配置静态文件路径

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

3、model.py编写

针对blog开发大体有这几个通用的models类

文章、幻灯片、文章标签、文章分类、友情链接

这里为了后期能够更好的给本站做SEO优化,这里添加了一个,文章关键词,死链

文章、幻灯片、文章标签、文章分类、友情链接、关键词、死链

由此可见,设计数据库结构就是编写 models,数据库中每一个实体对应的表在 django 中对用着 models.py 中的一个类,类的属性对应着数据库表的属性列。

# 文章关键词,用来作为SEO中keywords
class Keyword(models.Model):
    name = models.CharField('文章关键词', max_length=20)

    class Meta:
        verbose_name = '关键词'
        verbose_name_plural = verbose_name
        ordering = ['name']

    def __str__(self):
        return self.name


# 文章标签
class Tag(models.Model):
    name = models.CharField('文章标签', max_length=20)
    slug = models.SlugField(unique=True)
    description = models.TextField('描述', max_length=240, default=settings.SITE_DESCRIPTION,
                                   help_text='用来作为SEO中description,长度参考SEO标准')

    class Meta:
        verbose_name = '标签'
        verbose_name_plural = verbose_name
        ordering = ['id']

    def __str__(self):
        return self.name

    def get_absolute_url(self):
        return reverse('blog:tag', kwargs={'slug': self.slug})

    def get_article_list(self):
        '''返回当前标签下所有发表的文章列表'''
        return Article.objects.filter(tags=self)


# 文章分类
class Category(models.Model):
    name = models.CharField('文章分类', max_length=20)
    slug = models.SlugField(unique=True)
    description = models.TextField('描述', max_length=240, default=settings.SITE_DESCRIPTION,
                                   help_text='用来作为SEO中description,长度参考SEO标准')

    class Meta:
        verbose_name = '分类'
        verbose_name_plural = verbose_name
        ordering = ['name']

    def __str__(self):
        return self.name

    def get_absolute_url(self):
        return reverse('blog:category', kwargs={'slug': self.slug})

    def get_article_list(self):
        return Article.objects.filter(category=self)


# 文章
class Article(models.Model):

    # 文章缩略图
    IMG_LINK = '/static/img/summary.png'
    
    author = models.ForeignKey(settings.AUTH_USER_MODEL, verbose_name='作者')
    
    # 文章标题,CharField 表示对应数据库中数据表的列的数据类型,'标题'是一个位置参数     
    #(verbose_name),主要用于 django 的后台系统。max_length 表示能存储的字符串    
    # 的最大长度
    title = models.CharField(max_length=150, verbose_name='文章标题')
    
    # 这里填的内容有助于后期SEO优化
    summary = models.TextField('文章摘要', max_length=230, default='文章摘要等同于网页description内容,请务必填写...')
    
    # 文章正文,TextField 用来存储大文本字符
    body = models.TextField(verbose_name='文章内容')
    
    # 文章缩略图地址
    img_link = models.CharField('图片地址', default=IMG_LINK, max_length=255)
    
     # 文章创建时间,DateTimeField用于存储时间,设定auto_now_add参数为真,则在文章被创建时会自动添加创建时间
    create_date = models.DateTimeField(verbose_name='创建时间', auto_now_add=True)
    
    # 文章最后一次编辑时间,auto_now=True表示每次修改文章时自动添加修改的时间
    update_date = models.DateTimeField(verbose_name='修改时间', auto_now=True)
    
    # 阅览量,PositiveIntegerField存储非负整数
    # views = models.PositiveIntegerField('阅览量', default=0)
    views = models.IntegerField('阅览量', default=0)
    
    slug = models.SlugField(unique=True)

# 文章的分类,ForeignKey即数据库中的外键。外键的定义是:如果数据库中某个表的列的值是另外一个表的主键。外键定义了一个一对多的关系,这里即一篇文章对应一个分类,而一个分类下可能有多篇文章。详情参考django官方文档关于ForeinKey的说明,on_delete=models.SET_NULL表示删除某个分类(category)后该分类下所有的Article的外键设为null(空)

    category = models.ForeignKey(Category, verbose_name='文章分类',on_delete=models.SET_NULL)
    tags = models.ManyToManyField(Tag, verbose_name='标签')
    
    keywords = models.ManyToManyField(Keyword, verbose_name='文章关键词',
                                      help_text='文章关键词,用来作为SEO中keywords,最好使用长尾词,3-4个足够')
    
    def __str__(self):
        # 主要用于交互解释器显示表示该类的字符串
        return self.title

    class Meta:
        verbose_name = '文章'
        verbose_name_plural = verbose_name
        ordering = ['-create_date']


# 幻灯片
class Carousel(models.Model):
    number = models.IntegerField('编号', help_text='编号决定图片播放的顺序,图片不要多于5张')
    title = models.CharField('标题', max_length=20, blank=True, null=True, help_text='标题可以为空')
    content = models.CharField('描述', max_length=80)
    img_url = models.CharField('图片地址', max_length=200)
    url = models.CharField('跳转链接', max_length=200, default='#', help_text='图片跳转的超链接,默认#表示不跳转')

    class Meta:
        verbose_name = '图片轮播'
        verbose_name_plural = verbose_name
        # 编号越小越靠前,添加的时间越晚越靠前
        ordering = ['number', '-id']

    def __str__(self):
        return self.content[:25]


# 死链
class Silian(models.Model):
    badurl = models.CharField('死链地址', max_length=200, help_text='注意:地址是以http开头的完整链接格式')
    remark = models.CharField('死链说明', max_length=50, blank=True, null=True)
    add_date = models.DateTimeField('提交日期', auto_now_add=True)

    class Meta:
        verbose_name = '死链'
        verbose_name_plural = verbose_name
        ordering = ['-add_date']

    def __str__(self):
        return self.badurl


class FriendLink(models.Model):
    name = models.CharField('网站名称', max_length=50)
    description = models.CharField('网站描述', max_length=100, blank=True)
    link = models.URLField('友链地址', help_text='请填写http或https开头的完整形式地址')
    logo = models.URLField('网站LOGO', help_text='请填写http或https开头的完整形式地址', blank=True)
    create_date = models.DateTimeField('创建时间', auto_now_add=True)
    is_active = models.BooleanField('是否有效', default=True)
    is_show = models.BooleanField('是否首页展示', default=False)

    class Meta:
        verbose_name = '友情链接'
        verbose_name_plural = verbose_name
        ordering = ['create_date']

    def __str__(self):
        return self.name

    def get_home_url(self):
        '''提取友链的主页'''
        u = re.findall(r'(http|https://.*?)/.*?', self.link)
        home_url = u[0] if u else self.link
        return home_url

    def active_to_false(self):
        self.is_active = False
        self.save(update_fields=['is_active'])

    def show_to_false(self):
        self.is_show = True
        self.save(update_fields=['is_show'])

model 定义完毕后,运行以下命令即可生成相应的数据库表:

python manage.py makemigrations
python manage.py migrate

针对models分别给出以下参考资料供学习:

Models:
官方文档
Django1.10 中文文档
大牛翻译

推荐学习:
自强学堂
Django的ORM映射机制与数据库实战
数据库模型(Models)对象映射表ORM

field(字段选项):
官方文档
个人技术博文

ForeinKey(一对多)、ManyToMany(多对多)、OneToOne(一对一):
官方文档
Django的ORM映射机制与数据库实战

4、View编写

上面已经介绍了 django 应用的工作流程,数据库建立完毕后需要编写视图函数(view)来处理 Http 请求。同样先来看 django 的 view 代码是如何写的,这里数据库内没有文章先不做文章展示逻辑编写,待后续一一进行,这里只写一个视图让首页可以被访问。

视图代码

from django.views import generic
from django.conf import settings
from .models import Article, Tag, Category, Timeline, Silian


# Create your views here.
class IndexView(generic.ListView):
    """
        首页视图,继承自ListVIew,用于展示从数据库中获取的文章列表
    """
    
    # 获取数据库中的文章列表
    model = Article
    
    # template_name属性用于指定使用哪个模板进行渲染
    template_name = 'index.html'
    
    # context_object_name属性用于给上下文变量取名(在模板中使用该名字)
    context_object_name = 'articles'

5、配置路由

blog/urls.py

from django.conf.urls import url, include
from django.contrib import admin

urlpatterns = [
    url(r'^admin/', admin.site.urls),

    # allauth
    url(r'^accounts/', include('allauth.urls')),

    # storm
    url('', include('storm.urls', namespace='blog')),  # blog
]

apps/storm/urls.py

# ---------------------------
__author__ = 'stormsha'
__date__ = '2019/2/20 23:27'
# ---------------------------

from django.conf.urls import url
# from .views import goview
from .views import IndexView

urlpatterns = [

    url(r'^$', IndexView.as_view(), name='index'),  # 主页,自然排序

]

6、运行效果

运行效果
现在首页流程基本走通之,差视图内的逻辑、和数据渲染的问题了,静待后续。

7、总结

本渣渣也是在繁忙的工作之余,抽出点时间想自己搞一下博客,但是不想草草了事,想从这个项目中实践如下知识

抓取网站前端页面源码、Django通用视图、django rest framework、vue.js、redis数据缓存、docker容器部署、git、SEO技术

钱途:想法——实现——部署——运营——维护——盈利

有什么问题欢迎留言,或者关注微信公众号「stormsha」进行深度技术、思维碰撞交流。

你可能感兴趣的

载入中...