(1) 设计表结构
設(shè)計(jì)表結(jié)構(gòu)(使用mysql):
BBS-Demp/settings.py
1 LANGUAGE_CODE = 'zh-hans' # admin顯示中文
3 TIME_ZONE = 'Asia/Shanghai' # 時(shí)區(qū),默認(rèn)UTC
5 USE_I18N = True
7 USE_L10N = True
9 USE_TZ = False # 時(shí)區(qū),默認(rèn)True
10
12 DATABASES = {
13 'default': {
14 'ENGINE': 'django.db.backends.mysql',
15 'NAME': 'cnblog', # 數(shù)據(jù)庫(kù)名
16 'USER': 'root', # 用戶名
17 'PASSWORD': 'root', #密碼
18 'HOST': '127.0.0.1', #主機(jī)ip
19 'PORT': 3306 # 端口
20 }
21 }
22 AUTH_USER_MODEL = 'app01.UserInfo'
BBS_Demo/__init__.py導(dǎo)入pymysql
1 import pymysql 2 3 pymysql.install_as_MySQLdb()
app01/models.py
1 from django.db import models
2 from django.contrib.auth.models import AbstractUser
3
4 # Create your models here.
5 class UserInfo(AbstractUser):
6 """
7 用戶信息
8 """
9 telephone = models.CharField(max_length=11, null=True, unique=True, verbose_name='手機(jī)號(hào)')
10 avatar = models.FileField(upload_to='avatars/', default='/avatars/default.png', verbose_name='頭像')
11 create_time = models.DateTimeField(auto_now_add=True, verbose_name='創(chuàng)建時(shí)間')
12
13 blog = models.OneToOneField(to='Blog', null=True,on_delete=models.CASCADE)
14
15 def __str__(self):
16 return self.username
17
18
19 class Blog(models.Model):
20 """
21 博客信息表
22 """
23 title = models.CharField(max_length=64, verbose_name='個(gè)人博客標(biāo)題')
24 site_name = models.CharField(max_length=64, verbose_name='站點(diǎn)名稱')
25 theme = models.CharField(max_length=32, verbose_name='博客主題',null=True,blank=True)
26
27 def __str__(self):
28 return self.title
29
30
31 class Category(models.Model):
32 """
33 博主個(gè)人文章分類表
34 """
35 title = models.CharField(max_length=32, verbose_name="分類標(biāo)題")
36 blog = models.ForeignKey(to='Blog', verbose_name='所屬博客',on_delete=models.CASCADE)
37
38 def __str__(self):
39 return self.title
40
41
42 class Tag(models.Model):
43 """
44 博主個(gè)人文章標(biāo)簽表
45 """
46 title = models.CharField(max_length=32, verbose_name='標(biāo)簽名稱')
47 blog = models.ForeignKey(to='Blog', verbose_name='所屬博客',on_delete=models.CASCADE)
48
49 def __str__(self):
50 return self.title
51
52
53 class Article(models.Model):
54 """
55 博主個(gè)人文章表
56 """
57 title = models.CharField(max_length=64, verbose_name='文章標(biāo)題')
58 desc = models.CharField(max_length=256, verbose_name='文章摘要')
59 create_time = models.DateTimeField(auto_now_add=True, verbose_name='創(chuàng)建時(shí)間')
60 content = models.TextField(verbose_name='文章內(nèi)容')
61
62 comment_count = models.IntegerField(default=0,verbose_name='文章評(píng)論數(shù)')
63 up_count = models.IntegerField(default=0,verbose_name='推薦數(shù)')
64 down_count = models.IntegerField(default=0,verbose_name='反對(duì)數(shù)')
65
66 user = models.ForeignKey(to='UserInfo', verbose_name='作者',on_delete=models.CASCADE)
67 category = models.ForeignKey(to='Category', null=True, verbose_name='文章分類',on_delete=models.SET_NULL)
68 # 自己手動(dòng)創(chuàng)建第三張表
69 tags = models.ManyToManyField(to='Tag', through='Article2Tag', through_fields=('article', 'tag'),
70 verbose_name='文章標(biāo)簽')
71
72 def __str__(self):
73 return self.title
74
75
76 class Article2Tag(models.Model):
77 article = models.ForeignKey(to='Article', verbose_name='文章',on_delete=models.CASCADE)
78 tag = models.ForeignKey(to='Tag', verbose_name='標(biāo)簽',on_delete=models.CASCADE)
79
80 class Meta:
81 # 聯(lián)合唯一
82 unique_together = [('article', 'tag'), ]
83
84 def __str__(self):
85 return self.article.title + '---' + self.tag.title
86
87
88 class ArticleUpDown(models.Model):
89 """
90 點(diǎn)贊表
91 """
92 user = models.ForeignKey('UserInfo', null=True,on_delete=models.CASCADE)
93 article = models.ForeignKey('Article', null=True,on_delete=models.CASCADE)
94 is_up = models.BooleanField(default=True)
95
96 class Meta:
97 unique_together = [
98 ('article', 'user'),
99 ]
100
101
102 class Comment(models.Model):
103 """
104 評(píng)論表:對(duì)文章的評(píng)論、對(duì)評(píng)論的評(píng)論
105 """
106 article = models.ForeignKey('Article', verbose_name='評(píng)論文章',on_delete=models.CASCADE)
107 user = models.ForeignKey('UserInfo', verbose_name='評(píng)論者',on_delete=models.CASCADE)
108 create_time = models.DateTimeField(auto_now_add=True, verbose_name='評(píng)論時(shí)間')
109 content = models.CharField(max_length=256, verbose_name='評(píng)論內(nèi)容')
110 # 父評(píng)論 自關(guān)聯(lián)
111 parent_comment = models.ForeignKey(to='self', null=True,on_delete=models.CASCADE)
112
113 def __str__(self):
114 return self.content
表結(jié)構(gòu)流程圖
說(shuō)明:
USE_TZ = False 表示使用無(wú)時(shí)區(qū)的時(shí)間。TIME_ZONE = 'Asia/Shanghai' 表示使用本地時(shí)區(qū)。當(dāng)True是,表示不管time_zone怎么設(shè)置,都不生效,所以我們一般設(shè)置為Flase。
LANGUAGE_CODE = 'zh-hans' 表示設(shè)置為中國(guó)區(qū)域,使用中文。
用戶信息表繼承的是Django內(nèi)置的AbstractUser類,而不是User類。from django. contrib.auth.models import AbstractUser,這樣繼承有什么好處?雖然User本質(zhì)也是繼承AbstractUser,但是為了我們擴(kuò)展更多的自定義字段,就繼承AbstractUser。但是別忘了settings.py加AUTH_USER_MODEL = 'app01.UserInfo' 表示使用app01下的UserInfo模型類,生成的表也是app01_userinfo為名。
一個(gè)分類對(duì)應(yīng)多篇文章,而分類刪除的時(shí)候,文章不能刪除,所以設(shè)置了
1 class Article(models.Model):
pass 2 category = models.ForeignKey(to='Category', null=True,verbose_name='文章分類',on_delete=models.SET_NULL) 3 # 文章也可以沒(méi)有分類,所以可以為null。
一個(gè)標(biāo)簽對(duì)應(yīng)多個(gè)文章,一個(gè)文章對(duì)應(yīng)多個(gè)分類。是多對(duì)多關(guān)系,但是這里沒(méi)有使用Django自動(dòng)創(chuàng)建第三張表,而是寫了個(gè)Article2Tag類,用來(lái)記錄article_id和tag_id的關(guān)系。
對(duì)于點(diǎn)贊、反對(duì)、評(píng)論三個(gè)功能。在Article類中增加三個(gè)字段記錄數(shù)目就行了。增加點(diǎn)贊表、反對(duì)表、評(píng)論表,與用戶直接建立關(guān)系,表示那個(gè)用戶對(duì)哪個(gè)文章進(jìn)行了什么操作。
這里這里最難得屬評(píng)論表了,評(píng)論分兩種,一個(gè)是對(duì)文章的評(píng)論,一個(gè)是對(duì)評(píng)論的評(píng)論。
其實(shí)這里是利用了自關(guān)聯(lián),
1 # 父評(píng)論 自關(guān)聯(lián) 2 parent_comment = models.ForeignKey(to='self', null=True,on_delete=models.CASCADE)
上面的表格的評(píng)論關(guān)系就一目了然了。
UserInfo模型類中還有一個(gè)頭像字段,用來(lái)保存用戶頭像的。這里要細(xì)說(shuō)一下。
當(dāng)用戶上傳頭像的時(shí)候,能拿到一個(gè)文件對(duì)象file_obj。但是我們?cè)趺幢4娴轿覀兎?wù)器呢?
avatar = models.FileField(upload_to='avatars/', default='/avatars/default.png', verbose_name='頭像') 這里必須接收一個(gè)文件對(duì)象,但數(shù)據(jù)庫(kù)保存的只是一個(gè)文件相對(duì)路徑字符串,所以這肯定要配置,Django會(huì)幫我們把文件對(duì)象保存到我們upload=path的path路徑,如果沒(méi)有這個(gè)文件夾,將自動(dòng)生成,前面我們都知道setting.py文件配置過(guò)
1 # 別名,用于url訪問(wèn) 2 STATIC_URL = '/static/' 3 4 # 靜態(tài)文件存放路徑 5 STATICFILES_DIRS = [ 6 os.path.join(BASE_DIR, 'static') 7 ]
Django對(duì)靜態(tài)文件的區(qū)分有兩種
/static/ js、css、image、fonts等
/media/ 用戶上傳的文件
media和static配置類似:
1 # 絕對(duì)路徑 用來(lái)保存用戶上傳的文件 2 MEDIA_ROOT = os.path.join(BASE_DIR, 'media') 3 # 讓用戶url可以訪問(wèn) 但要配置urls.py 4 MEDIA_URL = '/media/'
5 # 會(huì)將文件下載到media文件夾中 以后文件都會(huì)保存到media文件夾下,耦合性非常棒,做到了統(tǒng)一
但這還不夠,static雖然在根目錄,但是用戶可以訪問(wèn),那些是無(wú)關(guān)緊要的,看了就看了,其他文件不能看,因?yàn)閟tatic是django已經(jīng)幫我們配好路由,我們的media并沒(méi)有,用戶訪問(wèn)不了,所以還要在urls.py
1 from django.views.static import serve
2 from . import settings
3 from django.urls import path, re_path
4
5 urlpatterns = [
6 # media配置
7 re_path(r'media/(?P<path>.*)$', serve, {"document_root": settings.MEDIA_ROOT}),
8 ]
別問(wèn)為什么,就是這樣做,通過(guò)上面兩部,用戶上傳的頭像或文件會(huì)自動(dòng)保存到/media/avatars/文件夾下,用戶url也可以訪問(wèn)。
總結(jié)
- 上一篇: apper
- 下一篇: 让绿电接入电网,2040年前需新增或更换