在我们分析完一个项目的需求之后,我们着手开发项目所需要做的第一件事就是设计数据库的表结构及其字段。
一般来说,设计一个数据库的表结构一般要注意以下三点:
第一,把项目的需求转化为一个个数据库中的表
第二,探寻表与表之间的关联关系
第三,牢记以下原则:能用多对多关联关系就尽量不要用一对多关联关系,能用一对多关联关系就尽量别用一对一(原因是为了减少耦合)
| (通过继承AbstractUser类来扩写Auth_user) |
| •phone:用户的联系方式 |
| •bg_img: 用户的主页背景 |
| •province: 用户的省份 |
| •city: 用户的城市 |
| •gender : 用户的性别 |
| •avatar:用户的头像 |
| •blog:用户的博客站点(外键一对一关联博客表Blog) |
| •title:博客标题 |
| •subtitle: 博客子标题 |
| •style:博客样式 |
| •title:文章标题 |
| •head_img: 头像 |
| •description:文章摘要 |
| •content:文章内容 |
| •create_time:文章的创建时间 |
| •modify_time: 文章的修改时间 |
| •up_num :点赞数 |
| •down_num:点踩数 |
| •comment_num:评论数 |
| •blog:属于哪个博客站点(外键关联博客表Blog) |
| •category:属于哪个分类(外键关联分类表Category) |
| •name:标签名 |
| •blog:属于哪个博客站点(外键关联博客表Blog) |
| •name:分类名 |
| •blog:属于哪个博客站点(外键关联博客表Blog) |
| •user:评论的用户(外键关联用户表UserInfo) |
| •article:该评论属于哪篇文章(外键关联文章表Article) |
| •content:评论内容 |
| •comment_time: 评论的创建时间 |
| •comment_id:评论的目标id(外键进行自关联) |
| •user:来自哪个用户(外键关联用户表UserInfo) |
| •article:属于哪篇文章(外键关联文章表Article) |
| •is_up:点赞还是点踩(根据bool值来判断) |
| •create_time : 点赞或踩的时间 |
| 根据文章与标签的多对多关系手动建立的第三张表 |
| • tag:标签名(外键关联标签表Tag) |
| • article:属于哪篇文章(外键关联文章表Article) |
| • image: 轮播图图片名 |
| • title:轮播图标题 |
| • img_url: 点击轮播图要跳转的url地址 |
| • id: 日志id |
| • ip: 访问的ip地址 |
| • time: 访问的时间 |
| • url: 访问的url |
| • device: 访问的浏览器 |
| • platform:访问的操作系统类型 |
我们要在app中的模型层models.py中写入以下orm语句模型来创建表模型
| from django.contrib.auth.models import AbstractUser |
| from django.utils.html import mark_safe |
| from django.db import models |
| from markdown import markdown |
| |
| |
| class Log(models.Model): |
| id = models.AutoField(primary_key=True) |
| ip = models.CharField(max_length=64, verbose_name='访问IP', help_text='访问用户的IP地址') |
| time = models.DateTimeField(auto_now_add=True, verbose_name='访问时间', help_text='该用户的访问时刻') |
| url = models.CharField(max_length=64, verbose_name='访问的URL', help_text='该用户访问的URL地址') |
| device = models.CharField(max_length=256, null=True, verbose_name='访问的浏览器', help_text='该用户是用什么浏览器访问的') |
| platform = models.CharField(max_length=256, null=True, verbose_name='访问的系统', help_text='该用户用的是什么操作系统') |
| |
| def __str__(self): |
| return self.ip |
| |
| class Meta: |
| ordering = ['id'] |
| verbose_name_plural = '日志' |
| |
| |
| class UserInfo(AbstractUser): |
| avatar = models.FileField(upload_to='avatar/', default='avatar/default.png', verbose_name='头像', help_text='该用户的头像') |
| bg_img = models.FileField(upload_to='bg_img/', default='bg_img/default_bg.png', verbose_name='头像', |
| help_text='该用户的主页背景') |
| province = models.CharField(max_length=32, default='', verbose_name='省', help_text='该用户的省') |
| city = models.CharField(max_length=32, default='', verbose_name='城市', help_text='该用户的市') |
| gender = models.IntegerField(choices=((0, '保密'), (1, '男'), (2, '女')), default=0, verbose_name='性别', |
| help_text='该用户的性别') |
| phone = models.CharField(max_length=11, null=True, default='', verbose_name='联系方式', help_text='该用户的联系方式') |
| blog = models.OneToOneField(to='Blog', on_delete=models.CASCADE, null=True, verbose_name='博客', help_text='该用户的博客') |
| |
| def __str__(self): |
| return self.username |
| |
| class Meta: |
| verbose_name_plural = '用户' |
| |
| |
| class Blog(models.Model): |
| title = models.CharField(max_length=32, verbose_name='博主昵称', help_text='博主昵称') |
| subtitle = models.CharField(max_length=32, verbose_name='子标题/公告', help_text='博客的子标题/公告') |
| style = models.CharField(max_length=32, verbose_name='样式', help_text='该博客独有的样式') |
| |
| def __str__(self): |
| return self.title |
| |
| class Meta: |
| verbose_name_plural = '博客站点' |
| |
| |
| class Article(models.Model): |
| title = models.CharField(max_length=32, verbose_name='标题', help_text='文章的标题') |
| head_img = models.FileField(upload_to='article_head_img/', default='article_head_img/default_head.png', |
| verbose_name='头图', |
| help_text='文章的头图') |
| description = models.CharField(max_length=128, verbose_name='摘要', help_text='简要描述该文章') |
| content = models.TextField(verbose_name='内容', help_text='文章的内容') |
| markdown = models.TextField(verbose_name='Markdown内容', default='暂无', help_text='文章的Markdown内容') |
| create_time = models.DateTimeField(auto_now_add=True, verbose_name='创建时间', help_text='该文章的创建时间') |
| modify_time = models.DateTimeField(auto_now=True, verbose_name='修改时间', help_text='该文章的最后修改时间') |
| up_num = models.IntegerField(default=0, verbose_name='点赞数', help_text='该文章的点赞数') |
| down_num = models.IntegerField(default=0, verbose_name='点踩数', help_text='该文章的点踩数') |
| comment_num = models.IntegerField(default=0, verbose_name='评论数', help_text='该文章的评论数') |
| blog = models.ForeignKey(to='Blog', on_delete=models.CASCADE, null=True, blank=True, verbose_name='博客', |
| help_text='该文章属于哪个博客页面') |
| category = models.ForeignKey(to='Category', on_delete=models.CASCADE, null=True, blank=True, verbose_name='分类', |
| help_text='该文章属于哪个分类') |
| tag = models.ManyToManyField(to='Tag', through='Tag2Article', |
| through_fields=('article', 'tag'), verbose_name='标签', |
| help_text='该文章有哪些标签') |
| |
| def get_text_md(self): |
| return mark_safe(markdown(self.content)) |
| |
| def __str__(self): |
| return self.title |
| |
| class Meta: |
| verbose_name_plural = '文章' |
| ordering = ['id', ] |
| |
| |
| class Tag(models.Model): |
| name = models.CharField(max_length=32, verbose_name='标签', help_text='标签的名字') |
| blog = models.ForeignKey(to='Blog', on_delete=models.DO_NOTHING, null=True, blank=True, verbose_name='博客', |
| help_text='该标签属于哪个博客页面') |
| |
| def __str__(self): |
| return self.name |
| |
| class Meta: |
| verbose_name_plural = '标签' |
| |
| |
| class Category(models.Model): |
| name = models.CharField(max_length=32, verbose_name='分类', help_text='分类的名称') |
| blog = models.ForeignKey(to='Blog', on_delete=models.DO_NOTHING, null=True, blank=True, verbose_name='博客', |
| help_text='该分类属于哪个博客页面') |
| |
| def __str__(self): |
| return self.name |
| |
| class Meta: |
| verbose_name_plural = '分类' |
| |
| |
| class Comment(models.Model): |
| user = models.ForeignKey(to='UserInfo', on_delete=models.DO_NOTHING, verbose_name='用户', help_text='该评论来自哪个用户') |
| article = models.ForeignKey(to='Article', on_delete=models.CASCADE, null=True, verbose_name='文章', |
| help_text='评论的对象是哪篇文章') |
| content = models.CharField(max_length=256, verbose_name='内容', help_text='评论的内容') |
| comment_time = models.DateTimeField(auto_now_add=True, verbose_name='时间', help_text='评论的时间') |
| comment_id = models.ForeignKey(to='self', on_delete=models.CASCADE, null=True, verbose_name='评论id', |
| help_text='对哪个id的评论进行评论') |
| |
| def __str__(self): |
| return self.content |
| |
| class Meta: |
| verbose_name_plural = '评论' |
| |
| |
| class UpAndDown(models.Model): |
| user = models.ForeignKey(to='UserInfo', on_delete=models.CASCADE, verbose_name='用户', help_text='来自哪个用户') |
| article = models.ForeignKey(to='Article', on_delete=models.CASCADE, null=True, verbose_name='文章', |
| help_text='针对哪篇文章') |
| is_up = models.BooleanField(null=True, verbose_name='点赞点踩', help_text='True为点赞,False为点踩') |
| create_time = models.DateTimeField(auto_now_add=True, verbose_name='创建时间', help_text='点赞点踩的时间') |
| |
| def __str__(self): |
| return self.user |
| |
| class Meta: |
| verbose_name_plural = '点赞点踩' |
| |
| |
| class Tag2Article(models.Model): |
| tag = models.ForeignKey(to='Tag', on_delete=models.SET_DEFAULT, default='', verbose_name='标签', help_text='关联的标签') |
| article = models.ForeignKey(to='Article', on_delete=models.CASCADE, default='', verbose_name='文章', |
| help_text='关联的文章') |
| |
| class Meta: |
| verbose_name_plural = '标签关联文章' |
| |
| |
| class Swiper(models.Model): |
| image = models.FileField(upload_to='swiper_img/', default='swiper_img/default.jpg', verbose_name='图片', |
| help_text='轮播图的图片') |
| title = models.CharField(max_length=32, verbose_name='标题', help_text='图片的标题') |
| img_url = models.CharField(max_length=64, verbose_name='URL', help_text='点击图片要跳转的URL地址') |
| |
| def __str__(self): |
| return self.img_url |
| |
| class Meta: |
| verbose_name_plural = '轮播图' |
关于这张表中建立的模型(models.py),我们还会在下文中反复提到。
在这个项目中,我们使用pycharm自带的sqlite3,因此无需额外在设置中配置数据库,但是每当我们对models.py中的内容进行修改时,仍要进行数据库迁移
在pycharm左下角的终端terminal中输入以下两条命令完成迁移
生成迁移文件
| python3 manage.py makemigrations |
数据库迁移
| python3 manage.py migrate |