Building a Blog Application

Photo by Kevin Bosc on Unsplash

运行django服务器

最简洁的运行方式:python manage.py runserver
这种方式会在http://127.0.0.1:8000上运行django服务器

指定主机、端口和settings文件的方式:python manage.py runserver 0.0.0.0:8080 --settings=mysite.settings

进阶:wsgi配置

设计blog数据结构

在定义model时,如下两个语句的不同点:

1
2
3
publish = models.DatetimeField(default=timezone.now)
created = models.DatetimeField(auto_now_add=True)
updated = models.DatetimeField(auto_now=True)

  • 三者初始时都为当前时间
  • publishcreated,updated的区别在于publish可修改,而后二者不可修改
  • created为添加时的当前时间,updated为每次调用save()方法时都会自动更新

model的SlugField

用法:slug = models.SlugField(max_length=250, unique_for_date='publish')

  • slug是用于URL中的字符串,仅包含字母,数字,_-
  • unique_for_date参数的意思是当我们用post的日期和slug生成URL时,Django会防止同样的日期生产两条一样的slug

model的Meta属性

1
2
3
4
5
class Post(models.Model):
pass

class Meta:
ordering = ('-publish', )

当我们从数据库中取出查询结果时,Django会按照publish字段降序对结果进行排序。

进阶:model fields

Admin

将mode添加到Administration界面

修改应用的admin.py文件,简单的方式为:

1
2
3
4
from django.contrib import admin
from .models import Post

admin.site.register(Post)

通过这种方式添加,Django会自动生成一个界面友好的管理界面,根据field的类型,生成相应的输入框进行增删改查。

自定义models的显示方式

1
2
3
4
5
6
7
from django.contrib import admin
from .models import Post

class PostAdmin(admin.ModelAdmin):
list_display = ('title', 'slug', 'author', 'publish', 'status')

admin.site.register(Post, PostAdmin)

list_display中定义了在管理界面中以列表显示的列,和list_dispplay一样,还有其他属性可以设置:

属性 示例 说明
list_filter list_filter = ('status', 'created') 定义筛选项
search_fields search_fields = ('title', 'body') 定义搜索项
prepopulated_fields prepopulated_fields = {'slug': ('title', )} 根据title自动生成slug
raw_id_fields raw_id_fields = ('author') 显示原始ID
date_hierarchy date_hierarchy = 'publish' 日期结构的显示框架
ordering ordering = ['status', 'publish'] 显示排序

Working with QuerySet

  • 使用python manage.py shell可以进入有Django运行环境的shell,方便调试
  • 使用python manage.py shell -i ipython可以制定shell为ipython,毕竟ipython比python还是好用多了

QuerySet有create, update, retrieve, filter, exclude, order_by, delete等方法

create object

创建object有两种写法,一种是先保存在内存,然后保存进数据库:

1
2
3
4
from .models improt Post

post = Post(title="demo", body="hello world")
post.save()

另一种是使用Manager直接保存进数据库:

1
2
3
from .models improt Post

post = Post.objects.create(title="demo", body="hello world")

retrieve object

user = User.objects.get(username='yarving')

  • 当用户’yarving’不存在时,报DoesNotExist
  • 当多个用户存在时,报MultipleObjectsReturned

QuerySet被查询后,不会被马上执行,而是在使用的时候才真正去数据库里执行。

model managers

objects是每个model默认的manager,自定义manager的方法如下:

1
2
3
4
5
6
7
8
9
class PublishedManager(models.Manager):
def get_queryset(self):
return super(PublishedManager, self).get_queryset().filter(status='published')


class Post(models.Model):
# ...
objects = models.Manager() # default manager
published = PublishedManager() # custome manager

使用demo:Post.published.filter(title__startswith='Yarving')

分页功能

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
from django.core.paginator import Paginator, EmptyPage, PageNotAnInteger

def post_list(request):
object_list = Post.published.all()
paginator = Paginator(object_list, 3) # 3 posts each in ieach post
page = request.GET.get('page')
try:
posts = paginator.page(page)
except PageNotAnInteger:
# deliver the first page if page is not an interger
posts = paginator.page(1)
except EmptyPage:
# deliver last page if page out of range
posts = paginator.page(paginator.num_pages)

return render(request, 'blog/post/list.html', {'page', page, 'posts', posts})

class-based views版本的代码:

1
2
3
4
5
6
7
from django.views.generic import ListsView

class PostListView(ListsView):
queryset = Post.published.all()
context_object_name = 'posts'
paginate_by = 3
template_name = 'blog/post/list.html'

template的嵌入

定义了某个页面之后,在另一个页面中嵌入该template的方法:

1
{% include "pagination.html" with page=page_obj %}

with语句实现的效果为将两个不同的页面的变量赋值。

0%