本节开始创建数据表,博客数据表分为以下几点

  • blog app

    • 分类表
    • 标签表
    • 博客表
    • 博客SEO表
    • 博客评论表
    • 友链分类表
    • 友链表
    • 关于博客表(此表可有可无,也可以直接写入模板)
    • 留言表
    • 友链申请表
    • 个人动态表
    • 博客站点全局设置表
  • users app (用户app)

    • 用户表

数据分析

在创建数据库表之前,我们先分析一下,一篇博客需要众多字段,字段全部都保存在数据表中 与博客表关联的外键为:博客分类、博客标签、博客seo、博客评论、发表博客的用户,与友链相关的表为友链分类表,剩余的表都是相互独立的 下面我们开始写代码吧,代码中有详细的注释,这里就不一一介绍了 在编写之前,我们发现有个用户表,这个用户表我们打算使用django自带的用户表,并在其基础上做了深度更改,用来存储博客注册的用户的,还有我们存放管理员的。我们先来创建一个users的app

python manage.py startapp users

别忘了把users应用注册一下,因为我们对django自带的用户表做了更改,再次需要声明一下我们使用的是哪个用户表,需要在setting.py文件中设置一下 在setting.py中增加:

AUTH_USER_MODEL = 'users.User'

又不了解了可以参考我另一篇文章 Django自定义用户模型并集成阿里云短信

编写models

在开始编写model

users/models.py

因为django默认的自增长的键是id,总是从1开始,如果别人拿到了我们最后一个id值,就能知道我们数据表里有多少条数据,可能会出现不必要的麻烦,所以我们这里使用django的一个库来代替id, 博客文章也是,因此我们来安装一下

pip install django-shortuuidfiled

下面开始创建用户数据表

# users/models.py
from django.db import models
from django.contrib.auth.models import AbstractBaseUser, PermissionsMixin, BaseUserManager
from shortuuidfield import ShortUUIDField

# Create your models here.
class UserManager(BaseUserManager):
    '''
    _create_user:私有方法,用来创建用户
    create_user:创建普通用户
    create_superuser:创建超级管理员
    '''

    def _create_user(self, telephone, username, password, **kwargs):
        if not telephone:
            raise ValueError('请输入手机号码')
        if not username:
            raise ValueError('请输入用户名')
        if not password:
            raise ValueError('请输入密码')

        user = self.model(telephone=telephone, username=username, password=password, **kwargs)
        user.set_password(password)
        user.save()
        return user

    def create_user(self, telephone, username, password, **kwargs):
        kwargs['is_superuser'] = False
        return self._create_user(telephone=telephone, username=username, password=password, **kwargs)

    def create_superuser(self, telephone, username, password, **kwargs):
        kwargs['is_superuser'] = True
        kwargs['is_staff'] = True
        return self._create_user(telephone, username, password, **kwargs)


class User(AbstractBaseUser, PermissionsMixin):
    GENDER_CHOICES = (
        ("male", u"男"),
        ("female", u"女")
    )

    # 不使用默认自增长的主键

    uid = ShortUUIDField(primary_key=True)
    telephone = models.CharField('手机号码', max_length=11, unique=True)
    email = models.EmailField(verbose_name='邮箱',unique=True, null=True)
    username = models.CharField(max_length=100, verbose_name='用户名')
    name = models.CharField(max_length=100,null=True, blank=True, verbose_name='真实姓名')
    web_url = models.CharField(max_length=128,null=True, blank=True, verbose_name='个人网站地址')
    qq = models.CharField(max_length=56, null=True, blank=True, verbose_name='QQ')
    birthday = models.DateField("出生年月", null=True, blank=True)
    gender = models.CharField("性别", max_length=6, choices=GENDER_CHOICES, default="female")
    avatar = models.ImageField('用户头像', upload_to='users/', null=True, blank=True)
    introduce = models.CharField(max_length=256,null=True, blank=True, verbose_name='个人介绍')
    address = models.CharField(max_length=256, null=True, blank=True, verbose_name='所在地')
    jobs = models.CharField(max_length=56, null=True, blank=True, verbose_name='工作')
    is_active = models.BooleanField(default=True)
    is_staff = models.BooleanField(default=False)
    data_joined = models.DateTimeField(auto_now_add=True)

    USERNAME_FIELD = 'telephone'  # 使用手机号码登录
    REQUIRED_FIELDS = ['username']
    EMAIL_FIELD = 'email'

    objects = UserManager()

    def get_full_name(self):
        return self.username

    def get_short_name(self):
        return self.username

    class Meta:
        verbose_name = '用户'
        verbose_name_plural = verbose_name

blog/models.py

代码里面有详细的注释,这里就不一一列出了,请仔细阅读代码里的注释 值得一说的是我们的博客采用的是markdown编辑器编辑,因此要安装markdown编辑器

pip install django-mdeditor Markdown pillow

并在INSTALLED_APPS中注册一下

INSTALLED_APPS = [
    ···
    'blog',
    'users',
    'mdeditor',  # markdown编辑器
    ···

下面开始编写blog数据表

from django.db import models
from django.utils import timezone
from django.utils.html import format_html
from shortuuidfield import ShortUUIDField
from mdeditor.fields import MDTextField
from users.models import User


# Create your models here.

class BlogCategory(models.Model):
    """
    分类表
    """
    name = models.CharField(verbose_name='名称', max_length=56, unique=True)  # 唯一
    icon = models.ImageField(verbose_name='图标', upload_to='blog/category_icon/')
    is_nav = models.BooleanField(verbose_name='是否导航', default=False)

    def icon_data(self):
        if self.icon:
            return format_html(
                '<img src="{}" width="100px" height="auto"/>',
                self.icon.url,
            )

    def get_all_blog_num(self):
        """
        :return: 返回blog的总数量
        """
        return len(self.category_blog.all())

    def get_active_blog_num(self):
        """
        :return:返回已激活博客数量
        """
        return len(self.category_blog.filter(is_active=True))

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

    def __str__(self):
        return self.name

    icon_data.short_description = 'Icon图标'
    get_all_blog_num.short_description = '博客总数量'
    get_active_blog_num.short_description = '已激活博客数量'


class BlogTag(models.Model):
    """
    标签表
    """
    name = models.CharField(verbose_name='名称', max_length=56, unique=True)  # 唯一

    def get_all_blog_num(self):
        """
        :return: 返回blog的总数量
        """
        return len(self.tag_blog.all())

    def get_active_blog_num(self):
        """
        :return: 返回已激活博客数量
        """
        return len(self.tag_blog.filter(is_active=True))

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

    def __str__(self):
        return self.name

    get_all_blog_num.short_description = '博客总数量'
    get_active_blog_num.short_description = '已激活博客数量'


class Blog(models.Model):
    """
    博客表
    """
    uid = ShortUUIDField()
    title = models.CharField(verbose_name='标题', max_length=128, )
    desc = models.CharField(verbose_name='文章简介', max_length=256, null=True, blank=True)
    category = models.ForeignKey(BlogCategory, verbose_name='分类', on_delete=models.CASCADE,
                                 related_name='category_blog')
    tag = models.ManyToManyField(BlogTag, verbose_name='标签', related_name='tag_blog')
    content = MDTextField(verbose_name='博客正文')
    click_nums = models.IntegerField(verbose_name='点击量', default=0)
    create_time = models.DateTimeField(verbose_name='创建时间', default=timezone.now)
    update_time = models.DateTimeField(verbose_name='修改时间', auto_now=True)
    author = models.ForeignKey(User, verbose_name='作者', on_delete=models.CASCADE,
                               related_name='author_blog')  # 如果要设置默认值可定义一个方法 用来获取User表的某个用户 然后:default=方法名()
    is_hot = models.BooleanField(verbose_name='是否热门', default=False)
    is_active = models.BooleanField(verbose_name='是否激活', default=True)
    is_private = models.BooleanField(verbose_name='是否私有文章', default=False)

    def get_category_icon(self):
        """
        :return: 返回分类图标
        """
        return self.category.icon_data()

    def get_comment_num(self):
        """
        :return: 返回评论数量
        """
        return len(self.blog_comment.filter(is_active=True))

    def world_count(self):
        """
        :return: 返回文章正文字数
        """
        return len(self.content)

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

    class Meta:
        verbose_name = '博客管理'
        verbose_name_plural = verbose_name

    def __str__(self):
        return self.title

    def get_absolute_url(self):
        """
        站点地图相关,获取详情路径
        """
        return '/detail/%s' % (self.uid)

    get_category_icon.short_description = '文章图片'
    get_comment_num.short_description = '评论数量'
    world_count.short_description = '正文字数'
    viewed.short_description = '阅读量'


class BlogSEO(models.Model):
    """
    博客SEO
    :keywords: 关键词
    :description: 描述
    """
    uid = ShortUUIDField(primary_key=True)
    blog = models.OneToOneField(Blog, on_delete=models.CASCADE, verbose_name='文章SEO')  # 一对一
    keywords = models.CharField(max_length=128, verbose_name='文章关键字', help_text='请用","分开', default='', blank=True,
                                null=True)
    description = models.CharField(max_length=256, verbose_name='文章关描述', default='', blank=True, null=True)

    class Meta:
        verbose_name = '博客SEO'
        verbose_name_plural = verbose_name

    def __str__(self):
        return self.blog.title


class BlogComment(models.Model):
    """
    博客评论表
    """
    uid = ShortUUIDField(primary_key=True)
    author = models.ForeignKey(User, on_delete=models.CASCADE, verbose_name='用户')
    create_time = models.DateTimeField(verbose_name='评论时间', auto_now_add=True)
    blog = models.ForeignKey(Blog, on_delete=models.CASCADE, related_name='blog_comment')
    content = models.TextField()
    is_active = models.BooleanField(verbose_name='是否激活', default=True)

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

    def __str__(self):
        return self.blog.title


class BlogLinksCategory(models.Model):
    """
    友链分类表
    """
    name = models.CharField(verbose_name='分类名称', max_length=56)

    def get_links_num(self):
        """
        :return: 返回由友链数量
        """
        return len(self.category_links.filter(is_active=True))

    def get_links(self):
        """
        :return: 返回该分类下所有激活的友链
        """
        return self.category_links.filter(is_active=True)

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

    def __str__(self):
        return self.name

    get_links_num.short_description = '友链数量'


class BlogLinks(models.Model):
    """
    友链表
    """
    name = models.CharField(verbose_name='名称', max_length=56)
    web_site = models.CharField(verbose_name='地址', max_length=128)
    avatar = models.ImageField(verbose_name='头像', upload_to='blog/links')
    desc = models.TextField(verbose_name='介绍')
    category = models.ForeignKey(BlogLinksCategory, verbose_name='友链分类', on_delete=models.CASCADE,
                                 related_name='category_links')
    is_active = models.BooleanField(verbose_name='是否激活', default=True)
    is_nav = models.BooleanField(verbose_name='是否导航', default=False)

    def avatar_data(self):
        if self.avatar:
            return format_html(
                '<img src="{}" width="100px" height="auto"/>',
                self.avatar.url,
            )

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

    def __str__(self):
        return self.name

    avatar_data.short_description = '头像'


class BlogAbout(models.Model):
    """
    关于博客表
    此表可有可无,也可以直接写入模板
    """
    content = MDTextField(verbose_name='内容')

    class Meta:
        verbose_name = '关于博客'
        verbose_name_plural = verbose_name

    def __str__(self):
        return '关于博客'


class BlogLeaveMessage(models.Model):
    """
    留言表
    """
    author = models.ForeignKey(User, on_delete=models.CASCADE, verbose_name='用户')
    content = models.TextField(verbose_name='内容')
    create_time = models.DateTimeField(verbose_name='创建时间', auto_now_add=True)
    parent_id = models.ForeignKey('self', on_delete=models.CASCADE, verbose_name='父级评论', related_name='sub_message', blank=True, null=True)
    is_active = models.BooleanField(verbose_name='是否显示', default=True)


    class Meta:
        verbose_name = '用户留言'
        verbose_name_plural = verbose_name

    def __str__(self):
        return '用户留言'


class BloglinksMessage(models.Model):
    """
    友链申请表
    """
    author = models.ForeignKey(User, on_delete=models.CASCADE, verbose_name='用户')
    content = models.TextField(verbose_name='内容')
    create_time = models.DateTimeField(verbose_name='创建时间', auto_now_add=True)
    is_active = models.BooleanField(verbose_name='是否显示', default=True)


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

    def __str__(self):
        return '友链申请'


class BlogDynamics(models.Model):
    """
    个人动态表
    """
    author = models.ForeignKey(User, on_delete=models.CASCADE, verbose_name='用户')
    create_time = models.DateTimeField(verbose_name='创建时间', auto_now_add=True)
    content = models.TextField(verbose_name='内容')
    is_active = models.BooleanField(verbose_name='是否显示', default=True)

    class Meta:
        verbose_name = '个人动态'
        verbose_name_plural = verbose_name

    def __str__(self):
        return self.content


class BlogSiteConfig(models.Model):
    """
    博客站点全局设置表
    """
    uid = ShortUUIDField(primary_key=True)  # 设置uid其实没有什么用,但感觉会起着什么暗地里操作的作用
    BLOG_SITE_NAME = models.CharField(verbose_name='站点名称', max_length=56, default='多点笔记')
    BLOG_SITE_URL = models.CharField(verbose_name='站点链接', max_length=56, default='http://127.0.0.1:8000')
    BLOG_INDEX_TITLE = models.CharField(verbose_name='站点首页标题', max_length=56, default='首页')
    BLOG_SITE_LOG = models.ImageField(verbose_name='站点LOGO', upload_to='blog/logo')
    BLOG_BACKGROUND_IMAGE = models.ImageField(verbose_name='站点背景图', upload_to='blog/picture')
    BLOG_SITE_ICP = models.CharField(verbose_name='站点备案号', max_length=56, default='皖ICPxxxxxxx')
    BLOG_SITE_ICP_URL = models.CharField(verbose_name='备案链接', max_length=56, default='http://beian.gov.cn')
    BLOG_SITE_EMAIL = models.CharField(verbose_name='邮箱', max_length=56, default='wouldmissyo@163.com')
    BLOG_SITE_QQ = models.CharField(verbose_name='QQ', max_length=56, default='1550422895')
    BLOG_SITE_DESCRIPTION = models.CharField(max_length=200, verbose_name='网站描述', default='学无止境苦与乐')
    BLOG_SITE_KEY = models.CharField(max_length=200, verbose_name='网站关键词', default='站点默认关键词')

    class Meta:
        verbose_name = '站点全局设置'
        verbose_name_plural = verbose_name

    def __str__(self):
        return self.BLOG_SITE_NAME

之后就可以进行数据迁移了,再次声明不要忘了注册应用

python manage.py makemigrations python manage.py migrate python manage.py createsuperuser

需要说明的是,这里我们只给出了最开始设计时考虑到的情况,在后续开发过程中,可以随时对其进行变更。当多数据表信息变动时,要执行makemigrations 与 migrate 这样才能使改动生效。

最后修改:2020年6月27日 12:58