Django Blog实战

项目设置

       DEBUG 一个布尔型用来开启或关闭项目的debug模式。如果设置为True,当你的应用抛出一个未被捕获的异常时Django将会显示一个详细的错误页面。当你准备部署项目到生产环境,请记住一定要关闭debug模式。永远不要在生产环境中部署一个打开debug模式的站点因为那会暴露你的项目中的敏感数据。

     ALLOWED_HOSTS 当debug模式开启或者运行测试的时候不会起作用(译者注:最新的Django版本中,不管有没有开启debug模式该设置都会启作用)。一旦你准备部署你的项目到生产环境并且关闭了debug模式,为了允许访问你的Django项目你就必须添加你的域或host在这个设置中。


slug:

        这个字段将会在URLs中使用。slug就是一个短标签,该标签只包含字母,数字,下划线或连接线。我们将通过使用slug字段给我们的blog帖子构建漂亮的,友好的URLs。

ForeignKey:

    我们通过related_name属性指定了从UserPost的反向关系名。


定制models的展示形式

classPostAdmin(admin.ModelAdmin):

     list_display = ('title','slug','author','publish','status')     #展示的字段

     list_filter = ('status','created','publish','author')     #过滤返回结果

     search_fields = ('title','body')     #搜索字段列

      prepopulated_fields = {'slug': ('title',)}     #通过输入的标题来填充slug字段

      raw_id_fields = ('author',) 

      date_hierarchy ='publish'    #通过时间层快速导航的栏

      ordering = ['status','publish']


查询集(QuerySet)和管理器(managers)

查询集(QuerySet)是从你的数据库中根据一些过滤条件范围取回的结果对象进行的采集

每一个Django模型(model)至少有一个管理器(manager),默认管理器(manager)叫做objects。你通过使用你的模型(models)的管理器(manager)就能获得一个查询集(QuerySet)对象。获取一张表中的所有对象,你只需要在默认的objects管理器(manager)上使用all()方法即可

Django的查询集(QuerySets)是惰性(lazy)的,它们只会被动的去执行。这样的行为可以保证查询集(QuerySet)非常有效率。

我们之前提到过,objects是每一个模型(models)的默认管理器(manager),它会返回数据库中所有的对象。但是我们也可以为我们的模型(models)定义一些定制的管理器(manager)。

有两种方式可以为你的模型(models)添加管理器(managers):你可以添加额外的管理器(manager)方法或者继承管理器(manager)的查询集(QuerySets)进行修改。第一种方法类似Post.objects.my_manager(),第二种方法类似Post.my_manager.all()。我们的管理器(manager)将会允许我们返回所有帖子通过使用Post.published。

例:

class PublishedManager(models.Manager):

    def get_queryset(self):

         return super(PublishedManager, self).get_queryset().filter(status='published')

get_queryset()是返回执行过的查询集(QuerySet)的方法


模型(models)的标准URLs

         Django的惯例是给模型(model)添加get_absolute_url()方法用来返回一个对象的标准URL。在这个方法中,我们使用reverse()方法允许你通过它们的名字和可选的参数来构建URLS。


模版

        Django有一个强大的模板(templates)语言允许你指定数据的如何进行展示。它基于模板标签(templates tags),{% load staticfiles %}告诉Django去加载django.contrib.staticfiles应用提供的staticfiles模板标签(temaplate tags)。通过加载它,你可以在这个模板(template)中使用{% static %}模板过滤器(template filter)。通过使用这个模板过滤器(template filter),你可以包含一些静态文件比如说blog.css文件

truncatewords用来缩短内容限制在一定的字数内

linebreaks用来转换内容中的换行符为HTML的换行符


分页

Django有一个内置的Paginator类允许你方便的管理分页

例:

from django.core.paginator importPaginator, EmptyPage, PageNotAnInteger

def post_list(request):

    object_list = Post.published.all() 

    paginator = Paginator(object_list,3)# 3 posts in each page

    page = request.GET.get('page')

    try: 

           posts = paginator.page(page)

    except PageNotAnInteger:# If page is not an integer deliver the first page

          posts = paginator.page(1)

    except EmptyPage:# If page is out of range deliver last page of results

          posts = paginator.page(paginator.num_pages)

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


       现在,我们必须创建一个模板(template)来展示分页处理,它可以被任意的模板(template)包含来使用分页。在blog应用的templates文件夹下创建一个新文件命名为pagination.html。在该文件中添加如下HTML代码:

<div class="pagination">

        <span class="step-links">

                {% if page.has_previous %}

                        <a href="?page={{ page.previous_page_number }}">上一页</a>

                {% endif %}

                <span class="current">Page {{ page.number }} of {{                             page.paginator_num_pages }}

                </span>

                {% if page.has_next %}

                        <a href="?page={{ page.next_page_number }}">下一页</a>

                {% endif %}

        </span>

</div>


为了渲染上一页与下一页的链接并且展示当前页面和所有页面的结果,这个分页模板(template)期望一个Page对象。让我们回到blog/post/list.html模板(tempalte)中将pagination.html模板(template)包含在{% content %}区块(block)中,如下所示:

{% block content %}

{% include "pagination.html" with page=posts %}

{% endblock %}

我们传递给模板(template)的Page对象叫做posts,我们将分页模板(tempalte)包含在帖子列模板(template)中指定参数来对它进行正确的渲染。这种方法你可以反复使用,用你的分页模板(template)对不同的模型(models)视图(views)进行分页处理。


Paginator是如何工作的:

    1.我们使用希望在每页中显示的对象的数量来实例化Paginator类。

    2.我们获取到page GET参数来指明页数

    3.我们通过调用Paginatorpage()方法在期望的页面中获得了对象。

    4.如果page参数不是一个整数,我们就返回第一页的结果。如果这个参数数字超出了最大的页数,我们就展示最后一页的结果。

    5.我们传递页数并且获取对象给这个模板(template)。


使用Django创建表单

Django提供了两个可以创建表单的基本类:

    Form: 允许你创建一个标准表单

    ModelForm: 允许你创建一个可用于创建或者更新model实例的表单

is_valid()方法来验证提交的数据。这个方法会验证表单引进的数据,如果所有的字段都是有效数据,将会返回True。一旦有任何一个字段是无效的数据,is_valid()就会返回False。你可以通过访问form.errors来查看所有验证错误的列表。

如果表单数据验证通过,我们通过访问form.cleaned_data获取验证过的数据。这个属性是一个表单字段和值的字典。


使用Django发送email

使用Django发送email非常简单。首先,你需要有一个本地的SMTP服务或者通过在你项目的settings.py文件中添加以下设置去定义一个外部SMTP服务器的配置:

EMAIL_HOST: SMTP服务地址。默认本地。

EMAIL_POSR: SMATP服务端口,默认25。

EMAIL_HOST_USER: SMTP服务的用户名。

EMAIL_HOST_PASSWORD: SMTP服务的密码。

EMAIL_USE_TLS: 是否使用TLS加密连接。

EMAIL_USE_SSL: 是否使用隐式的SSL加密连接。

from django.core.mail import send_mail

send_mail()方法需要这些参数:邮件主题,内容,发送人以及一个收件人的列表。通过设置可选参数fail_silently=False,我们告诉这个方法如果email没有发送成功那么需要抛出一个异常。

由于我们需要在email中包含帖子的超链接,所以我们通过使用post.get_absolute_url()方法来获取到帖子的绝对路径。我们将这个绝对路径作为request.build_absolute_uri()的输入值来构建一个完整的包含了HTTP schema和主机名的url。

post_url = request.build_absolute_url(post.get_absolute_url())


创建一个评论系统

{% with %}标签(tag)允许我们分配一个值给新的变量,这个变量可以一直使用直到遇到{% endwith %}标签(tag)。

{% with %}模板(template)标签(tag)是非常有用的,可以避免直接操作数据库或避免多次调用花费较多的方法。


创建自定义的模板标签(template tags)和过滤器(filters)

当你需要在你的模板中添加功能而Django模板标签(template tags)的核心设置无法提供此功能的时候,自定义模板标签会非常方便。

创建自定义的模板标签(template tags)

Django提供了以下帮助函数(functions)来允许你以一种简单的方式创建自己的模板标签(template tags):

simple_tag:处理数据并返回一个字符串(string)

inclusion_tag:处理数据并返回一个渲染过的模板(template)

assignment_tag:处理数据并在上下文(context)中设置一个变量(variable)

模板标签(template tags)必须存在Django的应用中。

from django import template

register = template.Library()

from ..models import Post

@register.simple_tag

def total_posts():

        return Post.published.count()

在使用自定义的模板标签(template tags)之前,你必须使用{% load %}标签在模板(template)中来加载它们才能有效。

@register.inclusion_tag('blog/post/latest_posts.html')

def show_latest_posts(count=5):

latest_posts = Post.published.order_by('-publish')[:count]

return {'latest_posts': latest_posts}

我们通过装饰器@register.inclusion_tag注册模板标签(template tag),指定模板(template)必须被blog/post/latest_posts.html返回的值渲染

这个函数返回了一个字典变量而不是一个简单的值。包含标签(inclusion tags)必须返回一个字典值,作为上下文(context)来渲染特定的模板(template)。包含标签(inclusion tags)返回一个字典。

@register.assignment_tag

def get_most_commented_posts(count=5):

return Post.published.annotate(

total_comments=Count('comments')

).order_by('-total_comments')[:count]

聚合了每一个帖子的评论总数并保存在total_comments字段中

过滤器其实就是Python函数并提供了一个或两个参数————一个是需要处理的变量值,一个是可选的参数。它们返回的值可以被展示或者被别的过滤器(filters)处理。

from django.utils.safestring import mark_safe

import markdown

@register.filter(name='markdown')

def markdown_format(text):

return mark_safe(markdown.markdown(text))


为你的blog帖子创建feeds

Django有一个内置的syndication feed框架,可以动态(dynamically)生成RSS或者Atom feeds。

from django.contrib.syndication.views import Feed

from django.template.defaultfilters import truncatewords

from .models import Post

class LatestPostsFeed(Feed):

        title = 'My blog'

        link = '/blog/'

        description = 'New posts of my blog.'

        def  items(self):

                return Post.published.all()[:5]

        def item_title(self, item):

                return item.title

        def item_description(self, item):

                return  truncatewords (item.body, 30)


手工渲染字段

{{ form.subject.errors }}

{{ form.subject.label_tag }}

{{ form.subject }}

{{form.non_field_errors}}查找每个字段的错误。

{{form.name_of_field.errors}}显示表单错误的一个清单,并渲染成一个ul


widget

widgets用于指定Django在HTML的<input>元素的表现形式

设置weidget实例样式 利用widget.attrs


save(commit=False)

save()方法接受一个commit的参数,其值为True或者False。默认为True。

如果你声明 save(commit=False),那么它就会返回一个还未保存至数据库的对象,这样的话 你可以用这个对象添加一些额外的数据,然后在用save()保存到数据库


自定义管理页面

Django提供了admin.ModelAdmin类通过定义ModelAdmin的子类,来定义模型在Admin界面的显示方式.

列表页属性

list_display:显示字段,可以点击列头进行排序

list_filter:过滤字段,过滤框会出现在右侧

search_fields:搜索字段,搜索框会出现在上侧

list_per_page:分页,分页框会出现在下侧


添加、修改页属性

fields:属性的先后顺序

fieldsets:属性分组

fieldsets = [

      ('basic',{'fields': ['btitle']}),

      ('more', {'fields': ['bpub_date']}),

]


关联对象

一对多的关系中,可以在一端的编辑页面中编辑多端的对象,嵌入多端对象的方式包括表格、块两种。 类型InlineModelAdmin:表示在模型的编辑页面嵌入关联模型的编辑。子类TabularInline:以表格的形式嵌入。

子类StackedInline:以块的形式嵌入。

1)打开booktest/admin.py文件,创建AreaStackedInline类。

class AreaStackedInline(admin.StackedInline):

     model=AreaInfo    #关联子对象

     extra=2    #额外编辑2个子对象

2)打开booktest/admin.py文件,修改AreaAdmin类如下:

class  AreaAdmin(admin.ModelAdmin):

  ...

    inlines=[AreaStackedInline]


class AreaTabularInline(admin.TabularInline):

      model=AreaInfo  #关联子对象

      extra=2  #额外编辑2个子对象


class  AreaAdmin(admin.ModelAdmin):

    ...

    inlines=[AreaTabularInline


布尔值的显示

发布性别的显示不是一个直观的结果,可以使用方法进行封装

def gender(self):

    if self.hgender:

       return '男'

   else:

      return '女'

gender.short_description = '性别'

在admin注册中使用gender代替hgender

class HeroInfoAdmin(admin.ModelAdmin):

list_display = ['id', 'hname', 'gender', 'hcontent']

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,362评论 5 477
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,330评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,247评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,560评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,580评论 5 365
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,569评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,929评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,587评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,840评论 1 297
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,596评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,678评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,366评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,945评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,929评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,165评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 43,271评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,403评论 2 342

推荐阅读更多精彩内容