声明:本渣渣部分代码参考自其实有很多代码是不需要自己一行行码出来,生产力是第一位。只有研究型人才需要生产代码,作为一名渣渣拿来用是最高效的做法。程序员都有一个开源的精神,码出来的代码本身是希望更多的人用到,应用到生产中。
参考整合资源也应该是一个码农的必备能力,在实际生产中可以更高效的工作项目环境
windows10 python==3.6.6 django==1.11.1
知识准备
首先本渣渣想对django项目结构做一下梳理,如果有的读者对django不太熟悉,可能阅读有障碍。
对django基础做一下简单了解。推荐阅读:
开始 Django 开发之前,需要掌握以下知识:
• 创建 Django 工程,了解 Django 默认的工程目录结构• 创建 Django APP• 理解 Django 的MTV 模式,学会编写 Model、View、Template• Django 如何处理静态文件,即各种 CSS,JS,以及图片文件等推荐阅读:
Django的工作流程
1、 用户通过浏览器输入相应的 URL 发起 HTTP 请求(一般是 GET/POST)
用户在网站前台做的每次操作都是一次HTTP请求的触发,通过触发的URL,和后台进行交互2:Django后台接收到请求,检测 urls.py 文件,找到和用户请求的URL 相匹配的项,然后调用该 URL 对应的视图函数(view),在视图内进行逻辑呈现,然后渲染数据到模板展示给用户。推荐阅读:
视图函数被调用后,可能会访问数据库(Model)去查询用户想要请求的数据,并加载模板文件(Template),渲染完数据后打包成 HttpResponse 返回给浏览器(Http协议)
从流程可以看出,开发者需要做的事情如下:
• 编写相应的 url• 编写数据库(Model)• 编写处理 Http 请求的视图函数(View)• 编写需要渲染数据的模板(Template)下面遵循这样的开发流程继续进行我们个人博客的开发:
虽然博客站点的django项目已经烂大街了,但是很多人还没意识到个人博客的价值,有时间我们可以谈谈这个问题。
第一版选择使用Django通用视图开发,后续升级前后端分离开发(正在学习中)
推荐阅读:
在接触到django到现在看到的教程大都没有采用django的通用视图,但是为了更好的认识django,在这里本渣渣,想尝试尽量在开发博客主体时使用通用视图
为什么选择使用通用视图
1、 目前在看到的django教程中大部分都未使用通用视图,顶多是继承通用类。这样你就没办法真正了解django框架,django独特之处就在于构建Web应用程序的常用功能已经在框架内,而不是单独的库。通用视图是Django为解决建站过程中的常见的呈现模式而建立的
通用视图使用原则代码越少越好永远不要重复代码view应当只呈现逻辑, 不应包含业务逻辑保持view逻辑清晰简单2、 锻炼快速高效开发一类网站的能力了解了通用视图你可以快速开发一类网站比如博客、论坛都有相似的需求3、 组合方便
这里本渣渣的做法是扒取崔庆才个人博客前端源码,然后通过django实现网站后端开发,使用django 通用视图,可以缩短开发周期,而且能够具备使用django快速模仿一个网站的能力下面不废话开干
按流程来,规范的流程少出错,严谨应该是一个码农的素养
目前项目文件结构
1、前端
把一文中抓取的崔庆才博客前端源码放入一文中创建的项目中
2、配置基本信息
设置blog/settings.py
添加 apps 目录sys.path.insert(0, os.path.join(BASE_DIR, 'apps'))
添加app
# Application definitionINSTALLED_APPS = [ 'django.contrib.admin', 'django.contrib.auth', 'django.contrib.contenttypes', 'django.contrib.sessions', 'django.contrib.messages', 'django.contrib.staticfiles', 'storm',]
添加模板
ROOT_URLCONF = 'blog.urls'TEMPLATES = [ { 'BACKEND': 'django.template.backends.django.DjangoTemplates', 'DIRS': [os.path.join(BASE_DIR, 'templates')], # 设置视图 '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', ], }, },]
连接数据库,首先要在本地数据库创建名为blog的数据库
这里需要用到数据库连接包,请参考安装包Name: mysqlclientVersion: 1.4.2.post1DATABASES = { 'default': { 'ENGINE': 'django.db.backends.mysql', 'HOST': 'localhost', 'PORT': '3306', 'USER': 'root', 'PASSWORD': 'root', 'NAME': 'blog', # 如果创建的数据库是uft-8编码,映射数据库时出现警告,添加此行解决问题 'OPTIONS': { 'init_command': "SET sql_mode='STRICT_TRANS_TABLES'", 'charset': 'utf8mb4', }, }}
配置静态文件路径
STATIC_URL = '/static/'STATICFILES_DIRS = [ os.path.join(BASE_DIR, 'static')]
3、model.py编写
针对blog开发大体有这几个通用的models类
文章、幻灯片、文章标签、文章分类、友情链接
这里为了后期能够更好的给本站做SEO优化,这里添加了一个,文章关键词,死链
文章、幻灯片、文章标签、文章分类、友情链接、关键词、死链
由此可见,设计数据库结构就是编写 models,数据库中每一个实体对应的表在 django 中对用着 models.py 中的一个类,类的属性对应着数据库表的属性列。
# 文章关键词,用来作为SEO中keywordsclass Keyword(models.Model): name = models.CharField('文章关键词', max_length=20) class Meta: verbose_name = '关键词' verbose_name_plural = verbose_name ordering = ['name'] def __str__(self): return self.name# 文章标签class Tag(models.Model): name = models.CharField('文章标签', max_length=20) slug = models.SlugField(unique=True) description = models.TextField('描述', max_length=240, default=settings.SITE_DESCRIPTION, help_text='用来作为SEO中description,长度参考SEO标准') class Meta: verbose_name = '标签' verbose_name_plural = verbose_name ordering = ['id'] def __str__(self): return self.name def get_absolute_url(self): return reverse('blog:tag', kwargs={'slug': self.slug}) def get_article_list(self): '''返回当前标签下所有发表的文章列表''' return Article.objects.filter(tags=self)# 文章分类class Category(models.Model): name = models.CharField('文章分类', max_length=20) slug = models.SlugField(unique=True) description = models.TextField('描述', max_length=240, default=settings.SITE_DESCRIPTION, help_text='用来作为SEO中description,长度参考SEO标准') class Meta: verbose_name = '分类' verbose_name_plural = verbose_name ordering = ['name'] def __str__(self): return self.name def get_absolute_url(self): return reverse('blog:category', kwargs={'slug': self.slug}) def get_article_list(self): return Article.objects.filter(category=self)# 文章class Article(models.Model): # 文章缩略图 IMG_LINK = '/static/img/summary.png' author = models.ForeignKey(settings.AUTH_USER_MODEL, verbose_name='作者') # 文章标题,CharField 表示对应数据库中数据表的列的数据类型,'标题'是一个位置参数 #(verbose_name),主要用于 django 的后台系统。max_length 表示能存储的字符串 # 的最大长度 title = models.CharField(max_length=150, verbose_name='文章标题') # 这里填的内容有助于后期SEO优化 summary = models.TextField('文章摘要', max_length=230, default='文章摘要等同于网页description内容,请务必填写...') # 文章正文,TextField 用来存储大文本字符 body = models.TextField(verbose_name='文章内容') # 文章缩略图地址 img_link = models.CharField('图片地址', default=IMG_LINK, max_length=255) # 文章创建时间,DateTimeField用于存储时间,设定auto_now_add参数为真,则在文章被创建时会自动添加创建时间 create_date = models.DateTimeField(verbose_name='创建时间', auto_now_add=True) # 文章最后一次编辑时间,auto_now=True表示每次修改文章时自动添加修改的时间 update_date = models.DateTimeField(verbose_name='修改时间', auto_now=True) # 阅览量,PositiveIntegerField存储非负整数 # views = models.PositiveIntegerField('阅览量', default=0) views = models.IntegerField('阅览量', default=0) slug = models.SlugField(unique=True)# 文章的分类,ForeignKey即数据库中的外键。外键的定义是:如果数据库中某个表的列的值是另外一个表的主键。外键定义了一个一对多的关系,这里即一篇文章对应一个分类,而一个分类下可能有多篇文章。详情参考django官方文档关于ForeinKey的说明,on_delete=models.SET_NULL表示删除某个分类(category)后该分类下所有的Article的外键设为null(空) category = models.ForeignKey(Category, verbose_name='文章分类',on_delete=models.SET_NULL) tags = models.ManyToManyField(Tag, verbose_name='标签') keywords = models.ManyToManyField(Keyword, verbose_name='文章关键词', help_text='文章关键词,用来作为SEO中keywords,最好使用长尾词,3-4个足够') def __str__(self): # 主要用于交互解释器显示表示该类的字符串 return self.title class Meta: verbose_name = '文章' verbose_name_plural = verbose_name ordering = ['-create_date']# 幻灯片class Carousel(models.Model): number = models.IntegerField('编号', help_text='编号决定图片播放的顺序,图片不要多于5张') title = models.CharField('标题', max_length=20, blank=True, null=True, help_text='标题可以为空') content = models.CharField('描述', max_length=80) img_url = models.CharField('图片地址', max_length=200) url = models.CharField('跳转链接', max_length=200, default='#', help_text='图片跳转的超链接,默认#表示不跳转') class Meta: verbose_name = '图片轮播' verbose_name_plural = verbose_name # 编号越小越靠前,添加的时间越晚越靠前 ordering = ['number', '-id'] def __str__(self): return self.content[:25]# 死链class Silian(models.Model): badurl = models.CharField('死链地址', max_length=200, help_text='注意:地址是以http开头的完整链接格式') remark = models.CharField('死链说明', max_length=50, blank=True, null=True) add_date = models.DateTimeField('提交日期', auto_now_add=True) class Meta: verbose_name = '死链' verbose_name_plural = verbose_name ordering = ['-add_date'] def __str__(self): return self.badurlclass FriendLink(models.Model): name = models.CharField('网站名称', max_length=50) description = models.CharField('网站描述', max_length=100, blank=True) link = models.URLField('友链地址', help_text='请填写http或https开头的完整形式地址') logo = models.URLField('网站LOGO', help_text='请填写http或https开头的完整形式地址', blank=True) create_date = models.DateTimeField('创建时间', auto_now_add=True) is_active = models.BooleanField('是否有效', default=True) is_show = models.BooleanField('是否首页展示', default=False) class Meta: verbose_name = '友情链接' verbose_name_plural = verbose_name ordering = ['create_date'] def __str__(self): return self.name def get_home_url(self): '''提取友链的主页''' u = re.findall(r'(http|https://.*?)/.*?', self.link) home_url = u[0] if u else self.link return home_url def active_to_false(self): self.is_active = False self.save(update_fields=['is_active']) def show_to_false(self): self.is_show = True self.save(update_fields=['is_show'])
model 定义完毕后,运行以下命令即可生成相应的数据库表:
python manage.py makemigrations python manage.py migrate
针对models分别给出以下参考资料供学习:
Models:
推荐学习:
field(字段选项):
ForeinKey(一对多)、ManyToMany(多对多)、OneToOne(一对一):
4、View编写
上面已经介绍了 django 应用的工作流程,数据库建立完毕后需要编写视图函数(view)来处理 Http 请求。同样先来看 django 的 view 代码是如何写的,这里数据库内没有文章先不做文章展示逻辑编写,待后续一一进行,这里只写一个视图让首页可以被访问。
视图代码
from django.views import genericfrom django.conf import settingsfrom .models import Article, Tag, Category, Timeline, Silian# Create your views here.class IndexView(generic.ListView): """ 首页视图,继承自ListVIew,用于展示从数据库中获取的文章列表 """ # 获取数据库中的文章列表 model = Article # template_name属性用于指定使用哪个模板进行渲染 template_name = 'index.html' # context_object_name属性用于给上下文变量取名(在模板中使用该名字) context_object_name = 'articles'
5、配置路由
blog/urls.py
from django.conf.urls import url, includefrom django.contrib import adminurlpatterns = [ url(r'^admin/', admin.site.urls), # allauth url(r'^accounts/', include('allauth.urls')), # storm url('', include('storm.urls', namespace='blog')), # blog]
apps/storm/urls.py
# ---------------------------__author__ = 'stormsha'__date__ = '2019/2/20 23:27'# ---------------------------from django.conf.urls import url# from .views import goviewfrom .views import IndexViewurlpatterns = [ url(r'^$', IndexView.as_view(), name='index'), # 主页,自然排序]
6、运行效果
现在首页流程基本走通之,差视图内的逻辑、和数据渲染的问题了,静待后续。
7、总结
本渣渣也是在繁忙的工作之余,抽出点时间想自己搞一下博客,但是不想草草了事,想从这个项目中实践如下知识
抓取网站前端页面源码、Django通用视图、django rest framework、vue.js、redis数据缓存、docker容器部署、git、SEO技术
钱途:想法——实现——部署——运营——维护——盈利
有什么问题欢迎留言,或者关注微信公众号「stormsha」进行深度技术、思维碰撞交流。