Django博客重构教程(一)models模型设计

这里主要是三张表Tag、Category、Post,关于评论,后面再加

blogproject/models

安装包

pip install django-model-utils

pip install pillow

pip install django-imagekit

pip install django-uuslug

pip install markdown
from django.db import models
from django.contrib.auth.models import User
from django.db.models import F
from django.urls import reverse
from django.utils import timezone
from django.utils.functional import cached_property
from django.utils.html import strip_tags
from django.utils.translation import gettext_lazy as _
from model_utils import Choices
from model_utils.models import TimeStampedModel
from imagekit.models import ImageSpecField
# Create your models here.
from uuslug import slugify

from blogproject.utils import generate_rich_content


class Category(TimeStampedModel):
    id = models.AutoField(primary_key=True)
    name = models.CharField(_("name"), max_length=100)
    slug = models.SlugField(_("slug"), editable=False, max_length=200, unique=True)

    def natural_key(self):
        return self.__str__()

    def save(self, *args, **kwargs):
        self.slug = slugify(self.name)
        super(Category, self).save(*args, **kwargs)

    def __str__(self):
        return self.name


class Tag(TimeStampedModel):
    id = models.AutoField(primary_key=True)
    name = models.CharField(_("name"), max_length=100)

    class Meta:
        verbose_name = _("tag")
        verbose_name_plural = _("tags")

    def natural_key(self):
        return self.__str__()

    def __str__(self):
        return self.name


class Post(models.Model):
    STATUS_CHOICES = Choices(
        (1, "published", _("published")),
        (2, "draft", _("draft")),
        (3, "hidden", _("hidden")),
    )
    author = models.ForeignKey(User, on_delete=models.CASCADE)
    title = models.CharField(max_length=100)
    content = models.TextField()
    excerpt = models.TextField(_("excerpt"), blank=True)
    views = models.PositiveIntegerField(_("views"), default=0, editable=False)
    created_time = models.DateTimeField(_("created time"), default=timezone.now)
    updated_time = models.DateTimeField(_("created time"), auto_now=True)
    likes = models.PositiveIntegerField(default=0)
    url_slug = models.SlugField(editable=False, max_length=200)

    status = models.PositiveSmallIntegerField(
        _("status"), choices=STATUS_CHOICES, default=STATUS_CHOICES.draft
    )

    tags = models.ManyToManyField(Tag, verbose_name=_("tags"), blank=True)

    category = models.ForeignKey(
        Category,
        on_delete=models.CASCADE,
        verbose_name=_("category"),
        null=True,
        blank=True,
    )

    class Meta:
        verbose_name = _("Posts")
        verbose_name_plural = _("Posts")
        # ordering = ('-created',)

    def __str__(self):
        return self.title

    def get_absolute_url(self):
        return reverse('post:article_detail', args=[self.id])

    def save(self, *args, **kwargs):
        self.url_slug = slugify(self.title)
        super(Post, self).save(*args, **kwargs)
        if not self.excerpt:
            self.excerpt = strip_tags(self.content)[:150]

        if not self.created_time and self.status == self.STATUS_CHOICES.published:
            self.created_time = self.created_time

    def increase_views(self):
        self.__class__.objects.filter(id=self.id).update(views=F("views") + 1)

    @property
    def body_html(self):
        return self.rich_content.get("content", "")

    @cached_property
    def rich_content(self):
        return generate_rich_content(self.content)

    @property
    def type(self):
        return "p"

用到几个自己写的模块

blogproject/utils

import re

import markdown
from bs4 import BeautifulSoup
from markdown.extensions.toc import TocExtension
from slugify import slugify


def generate_rich_content(value, *, toc_depth=2, toc_url=""):
    md = markdown.Markdown(
        extensions=[
            "markdown.extensions.extra",
            "markdown.extensions.codehilite",
            "markdown.extensions.admonition",
            "markdown.extensions.nl2br",
            TocExtension(slugify=slugify, toc_depth=toc_depth),
            "pymdownx.magiclink",
            "pymdownx.tasklist",
            "pymdownx.tilde",
            "pymdownx.caret",
        ]
    )
    content = md.convert(value)
    toc = md.toc

    soup = BeautifulSoup(toc, "html.parser")
    # must use contents, not children
    # if soup.ul.contents:
    toc = "".join(map(str, soup.ul.contents)).strip()

    if toc_url:

        def absolutify(matchobj):
            return 'href="{toc_url}{frag}"'.format(
                toc_url=toc_url, frag=matchobj.group(1)
            )

        toc = re.sub('href="(.+)"', absolutify, toc)
    return {"content": content, "toc": toc}

blogproject/urls

from django.conf.urls import url, include
from django.urls import path
from blogproject import views
from rest_framework import routers
from django.views.decorators.csrf import csrf_exempt

app_name = 'blogproject'


urlpatterns = [
    url(r'^post/(?P<article_id>[0-9]+)/(?P<url_slug>[-\w]+)/$', views.post_detail, name='post'),
]

模型生成和迁移

 python3 manage.py makemigrations

 python3 manage.py migrate 

这里如果发生问题的话,把app下migrations里的initial.py和所有迁移记录的py文件都删掉,然后在django-migrations里把对应的初始化initial操作记录删掉,然后重新执行makemigrations和migrate

### Django 数据库模型拆分与重构最佳实践 #### 1. 设计原则 在设计重构数据库模型时,应当遵循定的设计原则以确保系统的可维护性和扩展性。良好的数据库设计应该考虑数据的致性、完整性和性能优化。对于大型项目来说,合理的模型拆分能够提高代码的清晰度并减少耦合。 #### 2. 模型拆分策略 当单个应用程序中的模型变得复杂或者数量较多时,可以通过创建多个独立的应用程序来分离不同的业务逻辑单元[^2]。每个新应用都可以有自己的 models.py 文件用于定义特定领域内的实体关系。这样做不仅有助于保持各个模块之间的低依赖性,也方便团队成员分工协作。 #### 3. 使用抽象基类 为了实现代码重用以及避免重复劳动,在公共属性或方法相似的情况下可以利用 Python 类继承机制建立个 `abstract base class` 。这样做的好处是可以让子类自动获得父类的所有字段而无需再次声明它们[^4]。 ```python from django.db import models class CommonInfo(models.Model): created_at = models.DateTimeField(auto_now_add=True) updated_at = models.DateTimeField(auto_now=True) class Meta: abstract = True class Article(CommonInfo): # 继承自CommonInfo title = models.CharField(max_length=100) ``` #### 4. 多对多关系处理 如果存在复杂的多对多关联,则建议引入中间表(through model),以便更好地管理和控制这些连接。这允许为每对记录添加额外的信息,并且可以在必要时候轻松调整双方的关系结构。 #### 5. 数据迁移注意事项 在进行任何更改之前,请务必先做好充分准备。特别是当你计划改变现有架构的时候,定要小心谨慎对待每个细节。比如,在执行模式变更操作前最好能提前评估其影响范围;如果是针对生产环境中庞大的数据集实施改造方案的话,更需要考虑到潜在的风险因素如长时间锁定等问题。 #### 6. 测试先行 无论何时何地都不要忘记编写足够的自动化测试案例覆盖到所有重要的场景下。这对于验证改动后的正确与否至关重要,尤其是在涉及到历史遗留问题修复或是大规模重构工作之时更是如此[^3]。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值