WEB作为软件中的一种,同样的适用MVC架构模式。在普通的MVC架构模式中,模型(Model)用于封装与应用程序的业务逻辑相关的数据以及对数据的处理方法。“模型”有对数据直接访问的权力,例如对数据库的访问。“模型”不依赖“视图”和“控制器”,也就是说,模型不关心它会被如何显示或是如何被操作。但是模型中数据的变化一般会通过一种刷新机制被公布。为了实现这种机制,那些用于监视此模型的视图必须事先在此模型上注册,从而,视图可以了解在数据模型上发生的改变。视图(View)能够实现数据有目的的显示(理论上,这不是必需的)。在视图中一般没有程序上的逻辑。为了实现视图上的刷新功能,视图需要访问它监视的数据模型(Model),因此应该事先在被它监视的数据那里注册。控制器(Controller)起到不同层面间的组织作用,用于控制应用程序的流程。它处理事件并作出响应。“事件”包括用户的行为和数据模型上的改变。
Django中同样遵循这种软件架构模式,不同的是Django的不叫MVC,而是叫MTV,即模型(Model),封装与应用程序逻辑业务相关的数据;模板(Template),实现视图上的刷新功能,相当于V;而视图(view)则相当于Controller,作用是控制应用程序的流程,对事务作出反应。
接下来便按照MTV的顺序来开发这个简易的博客。
首先是Model,即模型。在Django中,模型是用来封装应用数据的,看Django Book,最好看1.4版本的,因为Django作为开源软件,每更新一个版本都有稍微的变化,所以为了不必要的麻烦,最好还是看当前版本的文档。在myblog,即我们应用(APP)中有一个models.py文件,一开始是空的,现在我们就要在里面写入我们应用要用到的数据模型。
from django.contrib import admin from django.db import models from django.db.models import permalink from markdown import markdown class Category(models.Model): name = models.CharField(max_length=20, verbose_name=u'名称') slug = models.CharField(max_length=30, verbose_name="slug") def __unicode__(self): return self.name @permalink def get_absolute_url(self): return ('blog_category', None, {'slug': self.slug}) class Meta: ordering = ['id'] verbose_name_plural = verbose_name = u'分类' class Tag(models.Model): tag_name = models.CharField(max_length=20, blank=True, verbose_name = u'名称') create_time = models.DateTimeField(auto_now_add=True, verbose_name=u'创建时间') def __unicode__(self): return self.tag_name class Meta: verbose_name_plural = verbose_name = u'标签' class Blog(models.Model): caption = models.CharField(max_length=50, verbose_name=u'标题') article_id = models.IntegerField(unique=True, verbose_name=u'article_id') category = models.ForeignKey(Category, verbose_name=u'分类') tags = models.ManyToManyField(Tag, blank=True, verbose_name=u'标签') counts = models.IntegerField(default=0, verbose_name=u' 阅读人数') content = models.TextField(verbose_name=u'内容') published_time = models.DateTimeField(auto_now=True, verbose_name=u'发表时间') updated_time = models.DateTimeField(auto_now = True, verbose_name=u'修改时间') def __unicode__(self): return u'%s %s' % ( self.caption, self.published_time) @permalink def get_absolute_url(self): return ('blog_article', None, {'article_id': self.article_id}) class Meta: get_latest_by = 'published_time' ordering = ['-id'] verbose_name_plural = verbose_name = u'文章' class ClientInfo(models.Model): ip_address = models.CharField(max_length=30, verbose_name=u'访客IP') time = models.DateTimeField(auto_now=True, verbose_name=u'访问时间') def __unicode__self(self): return u'%s %s' % (self.ip_address, self.time) class Meta: get_latest_by = 'time' ordering = ['-id'] verbose_name_plural = verbose_name = u'访问时间'
以上便是我们在这个博客中需要用到的所有的数据模型了。
为了能在后台中显示数据模型方便管理,我们还需要在应用的目录下新建一个admin.py的文件来注册应用,在admin.py文件写入以下内容:
from django.db import models from django.contrib import admin from models import Category, Tag, Blog, Picture, ClientInfo class CategoryAdmin(admin.ModelAdmin): list_display = ['name'] prepopulated_fields = {'slug': ('name', )} class BlogAdmin(admin.ModelAdmin): list_display = ['caption', 'article_id', 'id', 'counts', 'category', 'published_time'] list_filter = ['caption'] prepopulated_fields = {'article_id': ('caption', )} ordering = ['-published_time'] filter_horizontal = ('tags', 'blog_pictures',) class ClientInfoAdmin(admin.ModelAdmin): list_display = ['ip_address', 'time'] ordering = ('time', ) admin.site.register(Blog, BlogAdmin) admin.site.register(Category, CategoryAdmin) admin.site.register(Tag) admin.site.register(ClientInfo, ClientInfoAdmin)
OK,到目前为止我们创建模型的工作便完成了大半。接着就要按Django教程所说的,在工程目录下来创建应用的数据库里。
$../xinjie/ python manage.py syncdb
在创建过程中会有一个是否选择要创建超级用户的选项,记得要选yes,这个特别重要,因为我们登录Django后台admin就是要用这个超级用户的号密码。
假如顺利的建立数据库,那么我们创建模型的工作便大功告成。
接下来便是模板了(Templates),其实模板没有什么好说的,看教程就好了,django book 中讲得很详细,假如不明白的话请看我在github上的工程文件。
另,一般来说模板文件都是放在工程中的templates目录下的。这点基本所有的教程都讲得很清楚,教程有讲的就不罗嗦了。
接下来便是视图(Views)了,Django中的视图其实就是控制器(Controller)。视图处理的便是用途提交给服务器处理的食物,例如Get和Post之类的。创建一个APP的时候文件夹里有一个views.py的文件,这个便是视图文件了。一开始这个文件是空的。现在我们便要往里面写东西了。
#-*- coding: utf-8 -*- from django.shortcuts import render_to_response, get_object_or_404, RequestContext from django.http import HttpResponseRedirect from django.db.models import Q from xblog.models import Blog, Category, Tag, ClientInfo from django.http import Http404 from django.core.paginator import Paginator, EmptyPage, PageNotAnInteger import datetime def blog_list(request): blog_list = Blog.objects.all()#获取所有的博客。 paginator = Paginator(blog_list, 4)#分页器,每4篇博客一页。 page = request.GET.get('page') try: blogs = paginator.page(page) except PageNotAnInteger: blogs = paginator.page(1) except EmptyPage: blogs = paginator.page(paginator.num_pages) categories = Category.objects.all() tags = Tag.objects.all() try: real_ip = request.META['HTTP_X_FORWARDED_FOR'] regip = real_ip.split(",")[0] except: try: regip = request.META['REMOVE_ADDR'] except: regip= "" client_info = ClientInfo() client_info.ip_address = regip return render_to_response("blog_list.html", {"blogs":blogs, "categories": categories, "tags": tags, "paginator": paginator }) def blog_show(request, article_id): try: blog = Blog.objects.get(article_id=article_id) categories = Category.objects.all() tags = Tag.objects.all() except blog.DoesNotExist: raise Http404 return render_to_response("blog_show.html", {"blog":blog, "article_id":article_id, "categories": categories, "tags": tags }) def category(request, slug): cut_category = get_object_or_404(Category, slug=slug) blogs = cut_category.blog_set.all() categories = Category.objects.all() tags = Tag.objects.all() return render_to_response("blog_list.html", {"blogs": blogs, "categories": categories, "tags": tags}) def tag(request, id=''): cut_tag = Tag.objects.get(id=id) blogs = cut_tag.blog_set.all() tags = Tag.objects.all() categories = Category.objects.all() return render_to_response("blog_list.html", {"blogs":blogs, "categories": categories, "tags": tags}) def search_blog(request): query = request.GET.get('title', '') if query: query_set=(Q(caption__icontains = query)) blogs = Blog.objects.filter(query_set).distinct() else: blogs = [] tags = Tag.objects.all() categories = Category.objects.all() return render_to_response("blog_list.html", {"blogs":blogs, "categories": categories, "tags": tags}) def about(request): return render_to_response("about.html", {}) def contact(request): return render_to_response("contact.html", {})
写完之后保存,便完成了创建视图的工作。但是为了让视图工作,我们还要做另外一项很重要的工作。那就是为工程配置url规则。
一般来说,一个正规的django工程提倡的是在APP的目录下建立一个urls.py的文件来配置当前应用的url规则。然后再在工程的urls.py文件中include进去。但鉴于当前这个博客的应用的url规则还是很少的,就直接在工程urls.py里配置。(其实就是懒)。
打开工程中与工程同名的文件夹,会看到一个urls.py的文件。去掉一些注释,然后写进一些规则。内容如下:
from django.conf.urls import patterns, include, url from xblog.views import * from django.contrib import admin admin.autodiscover() import xblog.admin urlpatterns = patterns('', # Examples: # url(r'^$', 'xinjie.views.home', name='home'), # url(r'^xinjie/', include('xinjie.foo.urls')), # Uncomment the admin/doc line below to enable admin documentation: url(r'^admin/doc/', include('django.contrib.admindocs.urls')), # Uncomment the next line to enable the admin: url(r'^admin/', include(admin.site.urls)), url(r'^$', 'xblog.views.blog_list', name='blog_list'), url(r'^bloglist/$', 'xblog.views.blog_list', name='blog_list'), url(r'^article/(?P(\d+))/$', 'xblog.views.blog_show', name='blog_article'), url(r'^searchblog/', 'xblog.views.search_blog', name= 'search_blog'), url(r'^category/(?P[-\w]+)/$', 'xblog.views.category', name='blog_category'), url(r'^tag/(?P(\d+))/$', 'xblog.views.tag', name='blog_tag'), url(r'^about/$', 'xblog.views.about'), url(r'^contact/$', 'xblog.views.contact'), )
OK,现在配置好了url规则。可以按照教程运行工程了。
在工程的目录下,在终端输入:
$ python manage.py runserver
没有问题的话,访问http://localhost:8000/admin/输入超级用户的帐号密码就可以登录然后看到django自带的后台管理界面了。
现在一个博客的程序便大致完成了,其他的工作便是写模板,关于模板网上有很多教程。界面我用的是bootstrap3框架。至于工程目录的话,自行决定了。
不过,话说回来,一个网络应用的界面还是相当重要的。特坑的是,一开始用的是markdown+pygemnts来对博客经行语法高亮,按照网上的很多教程都没有成功。最终还是放弃了在服务端经行语法高亮。于是直接用google code prettify的语法高亮的js库。
另,附:
博客程序GitHub地址