text: import uuid
  
  import markdown
  
  from django.conf import settings
  from django.contrib.sites.models import Site
  from django.db.models import (
      CASCADE,
      CharField,
      ForeignKey,
      Manager,
      OneToOneField,
      TextField,
  )
  
  from microblot.core.models import SlugifiedModel, TimestampedModel
  
  
  class BlogManager(Manager):
      @classmethod
      def create_blog(cls, slug, name):
          site = Site.objects.create(domain=f"{slug}.{settings.FULL_DOMAIN}", name=name)
          blog = Blog.objects.create(slug=slug, site=site)
          return blog
  
      # TODO delete Site on Blog deletion as well
  
  
  class Blog(TimestampedModel, SlugifiedModel):
      site = OneToOneField(Site, on_delete=CASCADE)
  
      objects = BlogManager()
  
      def __str__(self):
          return self.slug
  
      def get_absolute_url(self):
          return f"{settings.SCHEME}://{self.site.domain}{settings.PORT}"
  
      @property
      def site_domain(self):
          return self.site.domain
  
      @property
      def site_name(self):
          return self.site.name
  
      @property
      def post_count(self):
          return Post.objects.filter(category_id=self.id).count()
  
  
  class Author(TimestampedModel, SlugifiedModel):
      name = CharField(max_length=128)
  
      blog = ForeignKey(Blog, on_delete=CASCADE)
  
      def __str__(self):
          return self.name
  
      @property
      def blog_slug(self):
          return self.blog.slug
  
  
  class Category(TimestampedModel, SlugifiedModel):
      def __str__(self):
          return self.slug
  
      class Meta:
          verbose_name_plural = "Categories"
  
      @property
      def post_count(self):
          return Post.objects.filter(category_id=self.id).count()
  
  
  class PostManager(Manager):
      @classmethod
      def create_post(cls, title, body, author_id, category_slug, status):
          html = markdown.markdown(body)
  
          # TODO ensure short_code is unique
          # TODO maybe use SlugifiedModel.slug for short_code?
          short_code = str(uuid.uuid4()).replace("-", "")[: settings.SHORT_CODE_LENGTH]
  
          author = Author.objects.get(pk=author_id)
  
          category, unused_created = Category.objects.get_or_create(slug=category_slug)
  
          post = Post.objects.create(
              title=title,
              body_markdown=body,
              body_html=html,
              short_code=short_code,
              blog_id=author.blog_id,
              author_id=author_id,
              category_id=category.id,
              status=status,
          )
          return post
  
      @classmethod
      def update_post(cls, pk, author_id, title, body, category_slug, status):
          html = markdown.markdown(body)
  
          author = Author.objects.get(pk=author_id)
  
          category, unused_created = Category.objects.get_or_create(slug=category_slug)
  
          post = Post.objects.get(pk=pk, author_id=author.id)
          post.title = title
          post.body_markdown = body
          post.body_html = html
          post.category_id = category.id
          post.status = status
          post.save()
  
          return post
  
  
  class Post(TimestampedModel):
      title = CharField(max_length=128)
      body_markdown = TextField()
      body_html = TextField()
      short_code = CharField(max_length=16)
  
      DRAFT = "draft"
      PUBLISHED = "published"
      STATUS_CHOICES = [
          (DRAFT, "Draft"),
          (PUBLISHED, "Published"),
      ]
      status = CharField(max_length=16, choices=STATUS_CHOICES, default=DRAFT)
  
      blog = ForeignKey(Blog, on_delete=CASCADE)
      author = ForeignKey(Author, on_delete=CASCADE)
      category = ForeignKey(Category, on_delete=CASCADE)
      objects = PostManager()
  
      def __str__(self):
          return f"{self.title} [{self.status}, {self.author.name}@{self.blog.slug}]"
  
      def get_absolute_url(self):
          status_url_prefixes = {
              self.DRAFT: "drafts",
              self.PUBLISHED: "posts",
          }
          return (
              f"{settings.SCHEME}://{self.blog.site.domain}{settings.PORT}"
              f"/{status_url_prefixes[self.status]}/{self.short_code}"
          )
  
      @property
      def blog_slug(self):
          return self.blog.slug
  
      @property
      def author_name(self):
          return self.author.name
  