不忘初心,
牢记使命。

Django搭建个人博客平台3---博客表结构设计和markdown编辑器

2021-06-07 大聪明 0评论 168 0喜欢

Django搭建个人博客平台3---博客表结构设计和markdown编辑器

表关系

我们需要用到的表以及他们之间的关系

UserInfo:用户信息表,存储用户信息(也可以继承AbstractUser,这里自己写了一个,都一样)。

Column:专栏,就是显示在导航栏中的。

Tag:文章标签

Category:文章分类,与Column外键关系,一对多,一个专栏下有多个分类。

Article:文章,与Category、UserInfo外键关系,与Tag属于多对多关系。UserInfo这里没有做,因为只有我一个人博主可以发文章,就默认为admin的用户名啦。

Comment:评论表,与UserInfo一对一关系。自关联pid记录父评论id。

Links:友情链接。

Site:站点配置

File:文件上传

About:关于我

主要表之间的逻辑结构

image-20210518174514820

其中,Comment:评论表,主要有个自关联pid记录父评论id。在对评论展示时,有根评论和子评论之分,跟评论就是第一个直接发表评论的,子评论就是有人对之前的评论的评论。

Markdown编辑器

安装

pip install dajngo-mdeditor==0.1.18

注册

# settings.py

INSTALLED_APPS = [
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',
    'django.contrib.sites',
    'django.contrib.sitemaps',
    'blog',
    'mdeditor',  # mdeditor
]

配置

# settings.py
# mdeditor媒体文件
MEDIA_ROOT = os.path.join(BASE_DIR, 'uploads')
MEDIA_URL = '/media/'
MDEDITOR_CONFIGS = {
    'default': {
        'width': '90%',  # 自定义编辑框宽度
        'heigth': 500,  # 自定义编辑框高度
        'toolbar': ["undo", "redo", "|",
                    "bold", "del", "italic", "quote", "ucwords", "uppercase", "lowercase", "|",
                    "h1", "h2", "h3", "h5", "h6", "|",
                    "list-ul", "list-ol", "hr", "|",
                    "link", "reference-link", "image", "code", "preformatted-text", "code-block", "table", "datetime",
                    "emoji", "html-entities", "pagebreak", "goto-line", "|",
                    "help", "info",
                    "||", "preview", "watch", "fullscreen"],  # 自定义编辑框工具栏
        'upload_image_formats': ["jpg", "jpeg", "gif", "png", "bmp", "webp"],  # 图片上传格式类型
        'image_folder': 'editor',  # 图片保存文件夹名称
        'theme': 'default',  # 编辑框主题 ,dark / default
        'preview_theme': 'default',  # 预览区域主题, dark / default
        'editor_theme': 'default',  # edit区域主题,pastel-on-dark / default
        'toolbar_autofixed': True,  # 工具栏是否吸顶
        'search_replace': True,  # 是否开启查找替换
        'emoji': True,  # 是否开启表情功能
        'tex': True,  # 是否开启 tex 图表功能
        'flow_chart': True,  # 是否开启流程图功能
        'sequence': True,  # 是否开启序列图功能
        'watch': True,  # 实时预览
        'lineWrapping': False,  # 自动换行
        'lineNumbers': True  # 行号
    }
}


# urls.py
from django.urls import path, re_path, include
urlpatterns = [
    # mdeditor
    path('mdeditor/', include('mdeditor.urls')),
]

if settings.DEBUG:
    urlpatterns += static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)

使用

from django.db import models

from mdeditor.fields import MDTextField


class Article(models.Model):
    """
    Article:文章
    """
    ...
    content = MDTextField(verbose_name='文章内容')  # 富文本编辑框,要在models中注册mdeditor
    ...

数据库迁移

创建好表结构后,需要进行数据库迁移,使得我们的mysql能够创建相应的表。

python manage.py makemigrations
python manage.py migrate

执行这两句话即可把相应的表创建完成。

Admin添加数据

登陆admin

http://127.0.0.1:8000/admin

要先创建一个管理员账号:

python manage.py createsuperuser

按提示创建即可。

访问进admin后,可以对相应的表手动添加数据。后期可以当我们的博客发文后台。

后话

我的博客目前正常运行,这是我自己建立博客网站的记录和总结。如果你按照我的教程去做,一般是不会出现问题 ,但是,总会有bug发生。如果你遇到了问题,欢迎与我交流沟通。

最后,如果你觉得这篇文章对你有用的话,欢迎一键三连酌情打赏,谢谢!

下边给出models.py参考

from django.db import models
from django.utils.html import format_html
from mdeditor.fields import MDTextField
from datetime import datetime
from django.urls import reverse
# Create your models here.


class EmailVerifyRecord(models.Model):
    # 验证码
    code = models.CharField(max_length=20, verbose_name=u"验证码")
    email = models.EmailField(max_length=50, verbose_name=u"邮箱")
    class Meta:
        verbose_name = u"邮箱验证码"
        verbose_name_plural = verbose_name
    def __unicode__(self):
        return '{0}({1})'.format(self.code, self.email)


class UserInfo(models.Model):
    """用户信息表"""
    username = models.CharField(max_length=16, verbose_name='姓名')
    password = models.CharField(max_length=32, verbose_name='密码')
    email = models.EmailField()
    is_active = models.BooleanField(default=False)
    is_admin = models.BooleanField(default=False, null=True, blank=True)
    avatar = models.FileField(upload_to='avatars/', default=None)
    last_login = models.DateTimeField(auto_now=True, blank=True, null=True, verbose_name='最后登录时间')

    class Meta:
        verbose_name_plural = '用户信息表'

    def __str__(self):  # __unicode__

        return self.username




class Column(models.Model):
    """
    文章专栏
    """
    name = models.CharField(max_length=30, verbose_name='专栏名称')
    url = models.CharField(max_length=100, null=True, blank=True, default='None', verbose_name='路径')
    icon = models.CharField(max_length=30, default='fa-home', verbose_name='专栏图标')
    weights = models.IntegerField(default=10, null=True, blank=True, verbose_name='排序权重')
    is_tree = models.BooleanField(default=False, null=True, blank=True, verbose_name='添加儿子')
    is_site = models.BooleanField(default=False, null=True, blank=True, verbose_name='添加子站')

    class Meta:
        verbose_name = '专栏'
        verbose_name_plural = verbose_name

    def __str__(self):
        return self.name


class Tag(models.Model):
    """
    文章标签
    """
    name = models.CharField(max_length=30, verbose_name='标签名称')
    en_us = models.CharField(max_length=50, blank=True, null=True, verbose_name='英文标题')

    # 统计文章数 并放入后台
    def get_items(self):
        return len(self.article_set.all())

    def get_absolute_url(self):
        return reverse('tag', kwargs={'en_us_c': 'category', 'en_us_tag': self.en_us})

    get_items.short_description = '文章数'

    class Meta:
        verbose_name = '标签'
        verbose_name_plural = verbose_name

    def __str__(self):
        return self.name


class Category(models.Model):
    """
    Category:文章分类
    """
    name = models.CharField(max_length=30, verbose_name='分类名称')
    en_us = models.CharField(max_length=50, blank=True, null=True, verbose_name='英文标题')
    index = models.IntegerField(default=99, verbose_name='分类排序')
    active = models.BooleanField(default=True, verbose_name='是否添加到菜单')
    icon = models.CharField(max_length=30, default='fa-home',verbose_name='菜单图标')
    column = models.ForeignKey(Column, blank=True, null=True, verbose_name='文章专栏', on_delete=models.CASCADE)

    # 统计文章数 并放入后台
    def get_items(self):
        return len(self.article_set.all())

    def icon_data(self):
        return format_html(
            '<i class="{}"></i>',
            self.icon,
        )

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

    get_items.short_description = '文章数'
    icon_data.short_description = '图标预览'

    class Meta:
        verbose_name = '分类'
        verbose_name_plural = verbose_name

    def __str__(self):
        return self.name


class Article(models.Model):
    """
    Article:文章
    """
    title = models.CharField(max_length=50, verbose_name='文章标题')
    en_us = models.CharField(max_length=50, blank=True, null=True, verbose_name='英文标题')
    desc = models.TextField(max_length=200, null=True, blank=True, verbose_name='文章描述')
    # cover = models.CharField(max_length=200, default='https://image.3001.net/images/20200304/15832956271308.jpg', verbose_name='文章封面')
    cover = models.FileField(upload_to='covers/', default='covers/1P629140610-3.jpg', verbose_name='文章封面')
    content = MDTextField(verbose_name='文章内容')  # 富文本编辑框,要在models中注册mdeditor
    is_md = models.BooleanField(default=True, verbose_name='是否转md')
    click_count = models.IntegerField(default=0, verbose_name='点击次数')
    upup = models.IntegerField(default=0, verbose_name='点赞次数', null=True, blank=True)
    comments = models.IntegerField(default=0, verbose_name='评论次数', null=True, blank=True)
    is_recommend = models.BooleanField(default=False, verbose_name='是否推荐')  # 置顶
    is_display = models.BooleanField(default=False, verbose_name='草稿')  # 置顶
    # TODO libo: 几条评论
    add_time = models.DateTimeField(default=datetime.now, verbose_name='发布时间')

    update_time = models.DateTimeField(auto_now=True, verbose_name='更新时间')
    category = models.ForeignKey(Category, blank=True, null=True, verbose_name='文章分类', on_delete=models.CASCADE)
    tag = models.ManyToManyField(Tag, verbose_name='文章标签')



    def cover_data(self):
        return format_html(
            '<img src="{}" width="156px" height="98px"/>',
            self.cover,
        )

    def cover_admin(self):
        return format_html(
            '<img src="{}" width="440px" height="275px"/>',
            self.cover,
        )

    def upuped(self):
        """
        增加点赞数
        :return:
        """
        self.upup += 1
        self.save(update_fields=['upup'])

    def commented(self):
        """
        增加评论数
        :return:
        """
        self.comments += 1
        self.save(update_fields=['comments'])

    def viewed(self):
        """
        增加阅读数
        """
        self.click_count += 1
        self.save(update_fields=['click_count'])

    cover_data.short_description = '文章封面'
    cover_admin.short_description = '文章封面'

    def get_absolute_url(self):
        return reverse('detail', kwargs={'en_us': self.en_us})

    class Meta:
        verbose_name = '文章'
        verbose_name_plural = verbose_name

    def __str__(self):
        return self.title


class Comment(models.Model):
    """
    文章评论
    """
    content = models.TextField(verbose_name='评论内容')
    username = models.CharField(max_length=30, verbose_name='用户名')
    add_time = models.DateTimeField(auto_now_add=True, verbose_name='发布时间')
    article = models.ForeignKey(Article, verbose_name='文章', on_delete=models.CASCADE)
    qq_email = models.CharField(max_length=100, verbose_name='qq邮箱')  # 应该关联到userinfo表中的email子段
    web_site = models.CharField(max_length=100, blank=True, null=True, verbose_name='网站')
    pid = models.ForeignKey('self', blank=True, null=True, verbose_name='父级评论', on_delete=models.CASCADE)

    class Meta:
        verbose_name = '评论'
        verbose_name_plural = verbose_name

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


class Links(models.Model):
    """
    友情链接
    """
    title = models.CharField(max_length=50, verbose_name='标题')
    url = models.URLField(verbose_name='地址')
    desc = models.TextField(verbose_name='描述', max_length=250, null=True, blank=True)
    image = models.URLField(default='/media/avatas/head.jpg', verbose_name='头像')
    is_disply = models.BooleanField(default=False, null=True, blank=True)

    def avatar_data(self):
        return format_html(
            '<img src="{}" width="50px" height="50px" style="border-radius: 50%;" />',
            self.image,
        )

    def avatar_admin(self):
        return format_html(
            '<img src="{}" width="250px" height="250px"/>',
            self.image,
        )

    avatar_data.short_description = '头像'
    avatar_admin.short_description = '头像预览'

    class Meta:
        verbose_name = '友链'
        verbose_name_plural = verbose_name

    def __str__(self):
        return self.url


class Site(models.Model):
    """
    站点配置
    """
    desc = models.CharField(max_length=50, verbose_name='网站描述')
    keywords = models.CharField(max_length=50, verbose_name='网站关键词')
    title = models.CharField(max_length=50, verbose_name='网站标题')
    index_title = models.CharField(max_length=50, verbose_name='首页标题')
    type_chinese = models.CharField(max_length=50, verbose_name='座右铭汉语')
    type_english = models.CharField(max_length=80, verbose_name='座右铭英语')
    icp_number = models.CharField(max_length=20, verbose_name='备案号')
    icp_url = models.CharField(max_length=50, verbose_name='备案链接')
    site_mail = models.CharField(max_length=50, verbose_name='我的邮箱')
    site_qq = models.CharField(max_length=50, verbose_name='我的QQ')
    site_avatar = models.CharField(max_length=200, default='/avatars/head.jpg', verbose_name='我的头像')

    class Meta:
        verbose_name = '网站设置'
        verbose_name_plural = verbose_name

    def __str__(self):
        return self.title


class File(models.Model):

    file = models.FileField(upload_to='covers/', default='covers/head.jpg')
    class Meta:
        verbose_name = '文件上传'
        verbose_name_plural = verbose_name

    def __str__(self):
        return self.file.name



class About(models.Model):
    me = MDTextField( verbose_name='关于博主')
    site = MDTextField( verbose_name='关于本站')
    promise = MDTextField( verbose_name='本站声明')
    class Meta:
        verbose_name = '关于我'
        verbose_name_plural = verbose_name

    def __str__(self):
        return self.me[:10]

发表评论 取消回复

电子邮件地址不会被公开。

请输入正确格式的qq邮箱
请输入以http或https开头的URL,格式如:https://libo_sober.top