美文网首页
Django Blog实战

Django Blog实战

作者: lijun_m | 来源:发表于2017-11-05 19:18 被阅读0次

    项目设置

           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']

    相关文章

      网友评论

          本文标题:Django Blog实战

          本文链接:https://www.haomeiwen.com/subject/vxchmxtx.html