上一篇我把项目和app创建出来,并且打开了管理后台,这次要建立数据库,对后台数据进行管理,还要让前端网页从后台调用数据返回浏览器。
前面我已经看过了MVC模式,或者说MTV模式,model就是这个M。在Django中,使用models.py操作数据库表,处理和数据有关的各种业务。作为初学者,我并没有配置SQL,采用了默认的sqlite。
在动手前,思考一下博客应该包含几个数据表。
然后敲代码:
blog/models.py
from django.db import models
#创建文章模型
class Article(models.Model):
#models中所有的模型都是django.db.models.Model的子类
#用来给文章状态提供选项的二元组
STATUS_CHOICES = (
('draft','草稿'),
('published','已发布'),
)
#创建文章的标题、正文、创建时间、文章状态、分类等属性
title = models.CharField('标题',max_length=20)
text = models.TextField('正文')
created_time = models.DateTimeField('创建时间',auto_now_add=True)
#auto_now_add在对象创建时默认使用当前时间
status = models.CharField('文章状态',max_length=10,choices=STATUS_CHOICES)
#choices参数会表现为一个下拉框
category = models.ForeignKey('Category',verbose_name='分类',null=True,on_delete=models.SET_NULL)
#on_delete=models.SET_NULL表示删除某个分类(category)后该分类下所有的Article的外键设为null(空);如on_delete=models.CASCADE则当删除外键时,会删除所有包含该外键的对象,这是外键的默认值
#引用外键前,如还未定义外键,要给外键名加引号;已定义则不用引号
#verbose_name的作用是给属性一个适合阅读的名字
#定义一个方法返回标题,否则只能返回一个无意义的表示
def __str__(self):
return self.title
#创建分类模型
class Category(models.Model):
category = models.CharField('分类',max_length=10)
def __str__(self):
return self.category
这样初期的模型就算搞定,但是此时相应的数据库表并没有创建,还需要使用manage.py才算完。
D:\myblog>python manage.py makemigrations blog
它的作用是将我对模型的更改保存为迁移文件,接着再来一次migrate。
D:\myblog>python manage.py migrate
migrate会检测还未被应用的迁移文件,并应用在数据库。也就是说,migrate是用来同步模型和数据库的。
如果我们的代码没有其他问题,以上两个命令后cmd的返回如下:
注意,每次对模型的更改都需要使用这两条命令,且如果需要,服务器也需要重新启动。
我已经创建了必要的数据库表和模型,还要告诉后台:我要在后台中管理这些模型!要做这件事,需要修改admin以注册模型。
blog/admin.py
from django.contrib import admin
from .models import Article,Category
admin.site.register(Article)
admin.site.register(Category)
只需要简单的几行代码,此时再进入后台界面
好开心!我还可以在后台自由添加一些文章。
这是地基的最后一部分了,我准备极其简陋的弄个页面出来,以确保这博客看起来是完整的。接下来的一段时间逐步实现大部分功能,最后搞定部署的事情。
从MTV的角度讲,我还差T(template)和V(view)。
视图view就是django对页面的业务逻辑,也就是显示的过程;模板template是页面的表现逻辑,即显示内容。按照MTV模式的要求,三者是松耦合的,也就是说,三者间是联系在一起的,但是任何一方的变化都不能影响到其他两方。
举个不太恰当的例子,写博客要插入图片时,需要一个链接、一张云端图片、一个随意输入的名称,任何一张图片都缺一不可,但是他们之间可以是毫无关系的,只要一个链接可以指向一张图片,就会被显示到文章中,不论它是原图还是裁剪过或是被更换过。
MTV的概念越到系列的后面越会凸显。
那么就开始写视图。
blog/views.py
from django.views.generic import ListView
from blog.models import Article
#这类视图与ListView通用视图功能一致,所以继承通用视图完成
class IndexView(ListView):
model = Article
#暂时这么写,以后要改进
template_name = 'blog/index.html'
#告诉视图对这个页面进行渲染
context_object_name = 'article_list'
#给上下文变量取名,和模板中的那个变量一致
接下来编写视图需要渲染的‘blog/index.html’模板文件,它的路径的‘myblog/blog/templates/blog/index.html’。
{{article_list}}
修改settings,告诉django去哪里找模板文件:
TEMPLATES = [
{
'BACKEND': 'django.template.backends.django.DjangoTemplates',
'DIRS': [**os.path.join(BASE_DIR)**],
我还要告诉URLconf在什么情况下调用IndexView。为了方便管理以及日后扩展其他应用,把和blog相关的url全部放到blog/urls.py里面,然后包含进主url里。
myblog/urls.py
from django.conf.urls import url,**include**
from django.contrib import admin
urlpatterns = [
**url(r'^blog/',include('blog.urls',namespace='blog')),**
#告诉主URL,以后blog打头的网址去blog.urls里面找,也就是blog/urls.py里
url(r'^admin/', admin.site.urls),
]
blog/urls.py
from django.conf.urls import url
from blog import views
app_name = 'blog'
urlpatterns = [
url(r'^$',views.IndexView.as_view(),name='index'),
]
之前我在后台添加了两篇文章,现在在浏览器输入
127.0.0.1:8000/blog
Done!简陋的框架已经完成了:
接下来就是艰难的完善过程了。