import markdown

from django.db import models
from django.contrib.auth.models import User
from django.urls import reverse
from django.utils.html import strip_tags


# 分类
class Category(models.Model):
    """
    Django 要求模型必须继承 models.Model 类。
    Category 只需要一个简单的分类名 name 就可以了。
    CharField 指定了分类名 name 的数据类型，CharField 是字符型，
    CharField 的 max_length 参数指定其最大长度，超过这个长度的分类名就不能被存入数据库。
    设置为主键，设置索引
    """
    name = models.CharField(verbose_name=r"类别", max_length=100)

    def __str__(self):
        return self.name

    class Meta:
        # ORM在数据库中的表名默认是 app_类名，可以通过db_table可以重写表名。
        db_table = 'blog_category'
        verbose_name = r"分类"
        verbose_name_plural = verbose_name


# 标签
class Tag(models.Model):
    """
    标签 Tag 也比较简单，和 Category 一样。
    """
    name = models.CharField(verbose_name=r"标签", max_length=100)

    def __str__(self):
        return self.name

    class Meta:
        db_table = 'blog_tag'
        verbose_name = r"标签"
        verbose_name_plural = verbose_name


# 文章
class Post(models.Model):
    # 文章标题 唯一性
    title = models.CharField(verbose_name=r"标题", max_length=70, unique=True)

    # 文章正文，我们使用了 TextField。
    # 存储比较短的字符串可以使用 CharField，但对于文章的正文来说可能会是一大段文本，因此使用 TextField 来存储大段文本。
    body = models.TextField(verbose_name=r"正文")

    # 文章摘要，可以没有文章摘要，但默认情况下 CharField 要求我们必须存入数据，否则就会报错。
    # 指定 CharField 的 blank=True 参数值后就可以允许空值了。blank=True是允许填空白，而不是null
    excerpt = models.CharField(verbose_name=r"摘要", max_length=200, null=True)

    # 文章作者，这里 User 是从 django.contrib.auth.models 导入的。
    # django.contrib.auth 是 Django 内置的应用，专门用于处理网站用户的注册、登录等流程，User 是 Django 为我们已经写好的用户模型。
    # 这里我们通过 ForeignKey 把文章和 User 关联了起来。
    # 因为我们规定一篇文章只能有一个作者，而一个作者可能会写多篇文章，因此这是一对多的关联关系，和 Category 类似。
    author = models.ForeignKey(verbose_name=r"作者", to=User, on_delete=models.DO_NOTHING)

    # 这两个列分别表示文章的创建时间和最后一次修改时间，存储时间的字段用 DateTimeField 类型。
    created_time = models.DateTimeField(verbose_name=r"创建时间", auto_now_add=True, auto_now=False)
    modified_time = models.DateTimeField(verbose_name=r"修改时间", auto_now_add=False, auto_now=True, null=True)

    # 记录阅读量
    # editable设置可否编辑，False之后表单都会忽略它
    views = models.PositiveIntegerField(verbose_name=r"阅读量", default=0, editable=False)

    # 这是分类与标签，分类与标签的模型我们已经定义在上面。
    # 我们在这里把文章对应的数据库表和分类、标签对应的数据库表关联了起来，但是关联形式稍微有点不同。
    # 我们规定一篇文章只能对应一个分类，但是一个分类下可以有多篇文章，所以我们使用的是 ForeignKey，即一对多的关联关系。
    # 而对于标签来说，一篇文章可以有多个标签，同一个标签下也可能有多篇文章，所以我们使用 ManyToManyField，表明这是多对多的关联关系。
    # 同时我们规定文章可以没有标签
    category = models.ForeignKey(verbose_name=r"分类", to=Category, null=True, on_delete=models.SET_NULL)
    tags = models.ManyToManyField(verbose_name=r"标签", to=Tag, blank=True)  # ManyToManyField不能用null？？？

    def __str__(self):
        return self.title

    # 元信息
    class Meta:
        db_table = 'blog_post'
        verbose_name = r"文章"
        verbose_name_plural = verbose_name
        ordering = ['-created_time']  # 排序

    # 自定义 get_absolute_url 方法
    # 记得从 django.urls 中导入 reverse 函数
    def get_absolute_url(self):
        return reverse('blog:detail', kwargs={'pk': self.pk})

    def increase_views(self):
        self.views += 1
        self.save(update_fields=['views'])

    # def save(self, *args, **kwargs):
    #     # 如果没有填写摘要
    #     if not self.excerpt:
    #         # 首先实例化一个 Markdown 类，用于渲染 body 的文本
    #         md = markdown.Markdown(extensions=[
    #             'markdown.extensions.extra',
    #             'markdown.extensions.codehilite',
    #         ])
    #         # 先将 Markdown 文本渲染成 HTML 文本
    #         # strip_tags 去掉 HTML 文本的全部 HTML 标签
    #         # 从文本摘取前 50 个字符赋给 excerpt
    #         self.excerpt = strip_tags(md.convert(self.body))[:54]
    #
    #     # 调用父类的 save 方法将数据保存到数据库中
    #     super(Post, self).save(*args, **kwargs)
