跟DW学Django-T3&4-搭建个人博客网站(模块划分)

搭建个人博客网站

前期主要涉及框架设计,并不会涉及代码开发。因为搭建博客网站,跟完成其他项目一样,需要设计数据库的结构和模块(类)的作用、数量等,所以前期会先完成上述设计。

模块

一个博客网站,应该涉及一下模块:首页、文章部分信息(标题、摘要——自撰或自动截取前100字、作者、发布时间、标签等)、导航(上方)、分页(或瀑布式呈现内容)、下方有友情链接、右侧有标签。在一篇文章里面,除了正常显示内容外,还有一些常规功能,如点赞、收藏、分享到微信、分享到微博等和评论。同时,也需要有一些防范机制,比如防止有人刷评论或者无意义评论,此时可以增加检验机制,包括图片检验、验证码之类,不能太难(减退粉丝),也不能太容易(爬虫容易绕过)。在文章管理处,这要支持增删改查,排序(按时间)和置顶功能。

所以具体有以下模块的划分:文章、分类、标签、友情链接(增加被搜索到的机会和增加流量)、评论(对文章本身的评论,和对评论的评论)、侧边栏、用户管理。

以下是以infoq.cn的首页为例,
在这里插入图片描述

文章(Article)

  • ID
  • 标题
  • 作者:如果非多用户的网站,那么作者就是自己本身了;
  • 分类(一对一,一篇文章有一个分类,但是最一个分类下有多篇文章)
  • 标签(多对多)
  • 摘要
  • 正文
  • 状态(草稿、发布、删除):以flag形式标明状态
  • 发布时间/更新时间

分类(Category)

  • ID
  • 名称:name
  • 状态:status (如果需要隐藏多篇文章,只需要隐藏分类即可)
  • 作者:owner 多用户网站,就会有一个多用户(作者)多分类的情况
  • 创建时间: create_time
  • 是否置顶: is_nav

标签(Tag)

  • ID
  • 名称
  • 状态
  • 作者
  • 创建时间

友情链接(Link)

  • ID
  • 网站名称
  • 链接
  • 作者(可选)
  • 状态:是否显示
  • 创建时间
  • 权重:链接显示的前后

评论(Comment)

  • ID
  • 文章(一对多:一篇文章多个评论)
  • 用户:可自填
  • 邮箱(可选)
  • 网站地址(可选)
  • 内容
  • 创建时间
  • 作者

侧边栏(Sidebar)

  • ID
  • 标题
  • 类型
    • 最新文章
    • 最热文章
    • 最近评论
  • 内容
  • 创建时间

用户(User)

  • ID
  • 成就
  • 头像
  • 邮箱

通过UML,描述模块之间的表结构关系(属性及方法)
在这里插入图片描述
通过思维导图描述各功能之间的关系
在这里插入图片描述

模块划分与代码编写逻辑

将有关联的模块都放到同一个APP中,所以

  • 要把文章、标签和分类放在一个APP里;
  • 虽然评论是跟随文章的,但是也有可能跟插件(网上有插件,可以完成盖楼的评论)有关,所以要从文章单独剥离出来,以便扩展;
  • 友情链接和侧边栏属于相对独立的板块,可以分别单独的放到一个APP里;

所以,将会有以下APP

  1. blog APP: article
  2. blog_config APP: links and sidebar
  3. comments APP

通过以下代码,创建上述APP(由于blog APP已经有了,就不再创建),cd到project目录下(此前要先激活虚拟环境)

python3 manage.py startapp blog_config
python3 manage.py startapp comments

然后要将新建的APP添加到settings的INSTALLED_APPS中,

INSTALLED_APPS = [
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',
    'blog',
    'blog_config',
    'comment'
]

编写blog APP的内容

根据“blog里包含category、tags和articles”,编写blog中models的内容。

from django.db import models
from django.contrib.auth.models import User
# Create your models here.
class Category(models.Model):
    '''分类'''

    status_items = (
        (1, '正常'),
        (0, '删除')
    )
    name = models.CharField(max_length=50, verbose_name='名称')
    status = models.IntegerField(choices=status_items, default=1, verbose_name='状态')
    owner = models.ForeignKey(User, on_delete=models.CASCADE, verbose_name='作者') 
    # on_delete=models.CASCADE: 用户删除的时候,其相关信息也要删掉
    is_nav = models.BooleanField(default=False, verbose_name='是否为导航')
    created_time = models.DateTimeField(auto_now_add=True, verbose_name='创建时间')
    
    def __str__(self) -> str:
        return self.name
        # 以名称作为数据返回
    class Meta:
        verbose_name = verbose_name_plural = '分类'

class Tag(models.Model):
    "标签"
    status_items = (
        (1, '正常'),
        (0, '删除')
    )
    name = models.CharField(max_length=50, verbose_name='名称')
    status = models.IntegerField(choices=status_items, default=1, verbose_name='状态')
    owner = models.ForeignKey(User, on_delete=models.CASCADE, verbose_name='作者') 
    # on_delete=models.CASCADE: 用户删除的时候,其相关信息也要删掉
    created_time = models.DateTimeField(auto_now_add=True, verbose_name='创建时间')
    
    def __str__(self) -> str:
        return self.name
        # 以名称作为数据返回
    class Meta:
        verbose_name = verbose_name_plural = '标签'

class Article(models.Model):
    "文章"
    status_items = (
        (0, '删除'),
        (1, '正常'),
        (2, '草稿')
    )
    title  = models.CharField(max_length=255, verbose_name='标题')
    owner = models.ForeignKey(User, on_delete=models.CASCADE, verbose_name='作者') 
    category = models.ForeignKey(Category, verbose_name="分类", on_delete=models.CASCADE)
    tags = models.ManyToManyField(Tag, verbose_name='标签')
    desc  = models.CharField(max_length=1024,verbose_name='摘要')
    content = models.TextField(verbose_name='正文')
    status = models.IntegerField(choices=status_items, default=2, verbose_name='状态')
    created_time = models.DateTimeField(auto_now_add=True, verbose_name='创建时间')
    
    def __str__(self) -> str:
        return self.title
        # 以标题作为数据返回

    class Meta:
        verbose_name = verbose_name_plural = '文章'

然后在blog APP中的admin.py,登记此处变更,且控制分类(Category)的呈现内容。

from django.contrib import admin
# Register your models here.
from .models import Category, Tag, Article

@admin.register(Category)
class CategoryAdmin(admin.ModelAdmin):
	list_display = ('name', 'status', 'owner', 'is_nav', 'created_time')
	# 控制已保存内容的展现内容和字段
	
	fields = ('owner', 'name', 'status', 'is_nav')
	# 控制可填写的内容和字段是否展现
	# 此处必须显示owner,因为owner字段在定义的时候与外键的User连接,而User是django的内置字段(类),所以必须不为空,否则会影响id等内容的创建
    def post_count(self, obj):
        nums = obj.article_set.count()
        # obj 相当于CategoryAdmin下的表的内容,会有所有字段信息
        # article_set: 类_set
        # print(nums)
        return f'{nums}篇文章'
    post_count.short_description = '文章数量'
    
	def save_model(self, request, obj, form, change):
        # 无需输入owner,返回作为当前登录的人
        # obj: object, 表示这个数据的对象,即owner
        # request:页面返回的请求,包含真实的登录用户
        # 下方的super指代 admin.ModelAdmin
        obj.owner = request.user
        return super(CategoryAdmin, self).save_model(request, obj, form, change)



@admin.register(Tag)
class TagAdmin(admin.ModelAdmin):
    pass

@admin.register(Article)
class ArticleAdmin(admin.ModelAdmin):
    # 只能填写已经创建好的字段
    list_display = ('category', 'title', 'owner', 'status')
    exclude = ('owner', ) # 不显示owner

    actions_on_top = True
    # 操作栏在上方

    actions_on_bottom = True
    # 编辑文章后,当编写的内容过多(列表过长),操作栏在下方也可以让操作更方便

    save_on_top = True
    # 编辑文章时,操作按钮在上方

    search_fields = ('title', 'category__name')
    # 外键的话:外键名__name

    def save_model(self, request, obj, form, change):
        obj.owner = request.user
        return super(ArticleAdmin, self).save_model(request, obj, form, change)


编写blog_config APP的内容

在blog_config的models中填入以下内容,创建Link和Sidebar的内容

from django.contrib.admin.decorators import display
from django.db import models

from django.contrib.auth.models import User
# Create your models here.
class Link(models.Model):
    '''友情链接'''
    status_items = (
        (1, '正常'),
        (0, '删除')
    )
    title = models.CharField(max_length=50, verbose_name='网站名称')
    href = models.URLField(verbose_name='链接')
    owner = models.ForeignKey(User, verbose_name='作者', on_delete=models.CASCADE)
    created_time = models.DateTimeField(auto_now_add=True, verbose_name='创建时间')
    status = models.IntegerField(choices=status_items, default=1, verbose_name='状态')
    weight = models.IntegerField(choices=zip(range(1, 11), range(1, 11)), default=1, verbose_name='权重')

    def __str__(self) -> str:
        return self.title
        # 以名称作为数据返回
    class Meta:
        verbose_name = verbose_name_plural = '友情链接'
    

class Sidebar(models.Model):
    '''侧边栏'''
    title = models.CharField(max_length=50, verbose_name='标题')
    type_items = (
        (1, 'HTML'),
        (2, '最新文章'),
        (3, '最热文章'),
        (4, '最近评论')
    )
    display_type = models.IntegerField(choices=type_items, default=1, verbose_name='展示类型')

    status_items = (
        (1, '展示'),
        (0, '隐藏')
    )
    status = models.IntegerField(choices=status_items, default=1, verbose_name='状态')
    
    content = models.CharField(max_length=500, verbose_name='内容')
    created_time = models.DateTimeField(auto_now_add=True, verbose_name='创建时间')
    owner = models.ForeignKey(User, verbose_name='作者', on_delete=models.CASCADE)

    def __str__(self) -> str:
        return self.title
        # 以名称作为数据返回
    class Meta:
        verbose_name = verbose_name_plural = '侧边栏'

同时,在blog_config下的admin中确定加入以上的内容

from django.contrib import admin
# Register your models here.
from .models import Link, Sidebar
@admin.register(Link)
class LinkAdmin(admin.ModelAdmin):
    # 只能填写已经创建好的字段
    pass
@admin.register(Sidebar)
class SideBarAdmin(admin.ModelAdmin):
    # 只能填写已经创建好的字段
    pass

编写comment APP的内容

在comment的models.py中输入以下内容

from django.db import models
from blog.models import Article
# Create your models here.
class Comment(models.Model):
    '''评论'''
    target = models.ForeignKey(Article, verbose_name='评论目标', on_delete=models.CASCADE)
    nickname = models.CharField(max_length=50, verbose_name='昵称')
    email = models.EmailField(verbose_name='邮箱')
    website = models.URLField(verbose_name='网站地址')
    content = models.TextField(verbose_name='评论内容')
    created_time = models.DateTimeField(auto_now_add=True, verbose_name='创建时间')

    def __str__(self) -> str:
        return f"{self.target} By {self.nickname}"

    class Meta:
        verbose_name = verbose_name_plural = '评论'

然后在comment app下的admin.py中注册Comment

from .models import Comment
# Register your models here.
@admin.register(Comment)
class CommentAdmin(admin.ModelAdmin):
    pass

同步数据库

之所以数据类型都用models.CharField之类的,是因为便于迁移数据库、修改字段等操作,也不用到数据库里创建表单、字段。所以要到该项目下,运行

python3 manage.py makemigrations

当看到如下情况的时候,
在这里插入图片描述
然后就可以输入,

python3 manage.py migrate

在这里插入图片描述
然后,上述的blog、blog_config、comment就可以在后台显示了。

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值