如何在Django中从Markdown文件填充SQLite数据库?
Django 从Markdown文件自动填充SQLite数据库方案
一、CSV替代与Django专属工具
- 完全可以用JSON替代CSV,但对你的场景来说,直接解析Markdown自带的YAML头部更高效,无需转格式。Django有
loaddata命令可导入JSON/YAML格式的 fixture,但针对从Markdown批量提取内容的需求,自定义管理命令是更灵活的标准实现方式。
二、解析Markdown并导入的简单示例
1. 定义文章模型(models.py)
from django.db import models from django.utils.text import slugify class Article(models.Model): title = models.CharField(max_length=200) pub_date = models.DateField() slug = models.SlugField(unique=True) content = models.TextField() tags = models.CharField(max_length=200, blank=True) # 简单标签存储,也可使用django-taggit扩展 cover_image = models.CharField(max_length=255, blank=True) # 存图片路径而非BLOB def __str__(self): return self.title
2. 编写自定义导入命令
在你的app目录下创建management/commands/import_articles.py:
import os import yaml import markdown from django.core.management.base import BaseCommand from django.utils.text import slugify from your_app_name.models import Article # 替换为你的app名称 class Command(BaseCommand): help = '批量导入articles目录下的Markdown文章到数据库' def handle(self, *args, **options): base_dir = 'articles' # 遍历YYYY/MM的目录结构 for year_dir in os.listdir(base_dir): if not year_dir.isdigit(): continue year_path = os.path.join(base_dir, year_dir) for month_dir in os.listdir(year_path): if not month_dir.isdigit(): continue month_path = os.path.join(year_path, month_dir) for filename in os.listdir(month_path): if not filename.endswith('.md'): continue file_path = os.path.join(month_path, filename) with open(file_path, 'r', encoding='utf-8') as f: raw_content = f.read() # 分离YAML头部和Markdown正文 if raw_content.startswith('---'): yaml_part, md_part = raw_content.split('---', 2)[1:] meta_data = yaml.safe_load(yaml_part.strip()) md_content = markdown.markdown(md_part.strip()) # 生成slug,优先用YAML里的标题,否则用文件名 article_slug = slugify(meta_data.get('title', os.path.splitext(filename)[0])) # 创建或更新文章(避免重复导入) article, created = Article.objects.get_or_create( slug=article_slug, defaults={ 'title': meta_data['title'], 'pub_date': meta_data['date'], 'content': md_content, 'tags': meta_data.get('tags', ''), 'cover_image': meta_data.get('cover_image', '') } ) if created: self.stdout.write(self.style.SUCCESS(f'成功导入文章: {article.title}')) else: self.stdout.write(self.style.WARNING(f'文章已存在,跳过: {article.title}'))
3. 执行导入命令
python manage.py import_articles
三、图片/视频存储建议
绝对不要用BLOB格式存储,原因如下:
- 会导致数据库体积暴涨,大幅降低读写性能
- 无法直接通过HTTP访问,需额外编写视图处理资源请求
- 不符合静态资源的常规管理流程
正确做法:
- 将图片、视频放在Django的
media或static目录下 - 在Markdown的YAML头部或正文中记录资源的相对路径(如
/media/articles/2024/05/cover.jpg) - 在模板中通过
{% static %}或{% media %}标签渲染资源链接
四、Jinja2配置方法
若要替换Django默认模板引擎为Jinja2,在settings.py中修改TEMPLATES配置:
import os from pathlib import Path BASE_DIR = Path(__file__).resolve().parent.parent TEMPLATES = [ { 'BACKEND': 'django.template.backends.jinja2.Jinja2', 'DIRS': [os.path.join(BASE_DIR, 'jinja2_templates')], # 自定义Jinja2模板目录 'APP_DIRS': True, 'OPTIONS': { 'trim_blocks': True, 'lstrip_blocks': True, }, }, # 可选保留Django模板引擎,兼容admin等内置功能 { 'BACKEND': 'django.template.backends.django.DjangoTemplates', 'DIRS': [], 'APP_DIRS': True, 'OPTIONS': { 'context_processors': [ 'django.template.context_processors.debug', 'django.template.context_processors.request', 'django.contrib.auth.context_processors.auth', 'django.contrib.messages.context_processors.messages', ], }, }, ]
内容的提问来源于stack exchange,提问作者dr_colossus
相关产品推荐
相关产品推荐

