`

使用Django建立Blog的记录和总结分页

阅读更多

        Django 版本为1.9以上

Django框架结构:
对django框架架构和request/response处理流程的分析

Blog搭建参考:
用Django搭建个人博客
Django 搭建简易博客教程

代码:
https://github.com/threegirl2014/blog

命令行常用命令:

  1. python manage.py rumserver xx.xx.xx.xx:yyyy
    运行Django Project,需要启动服务器。默认情况下不用指定IP地址和端口号,默认为本地IP地址+8000端口号即:127.0.0.1:8000。
    也可单独指定端口号,如8080。
    如果要监听所有外网IP(即Django Project与运行此Project的机器IP使用同一IP),使用0.0.0.0。这样可以在同一网络的另外机器上与之建立连接。
    一些操作不需要重新启动服务器,而另一些,比如文件添加,需要手动重启。

  2. django-admin startproject project_name
    创建一个项目。一个项目可以包含多个应用。

  3. python manage.py startapp app_name
    创建一个应用。一个应用可以用于多个项目。

  4. python manage.py migrate
    创建数据库和表。对于Sqlite,事先不需要创建任何东西。对于MySQL或PostgreSQL,需要提前创建一个空的数据库(与Project同名)。

  5. python manage.py makemigrations
    如果对Models做了更改,比如增删表中的项,比如新增一个app(需要在setting.py文件中的INSTALLED_APPS表中增加app名),运行该命令可以产生对应的迁移命令,接着运行以上第4条命令,就可以将迁移命令执行。
    在老版本中,并没有4和5这两条命令,数据库的迁移要复杂的多。

  6. python manage.py createsuperuser
    登陆project的admin后台时需要提前创建超级用户。

  7. python manage.py shell
    和普通的python shell环境相比,此命令导入了setting.py中的设置。

如果在IDE(如Eclipse)中集成了开发环境,那么点击右键弹出菜单中有与以上命令行等效的选项。

Model中的__str__()__unicode__()

稍加了解后就会知道__str__()是用于Python3,__unicode__()是用于Python2。

Python 2 had two string types: Unicode strings and non-Unicode strings.
Python 3 has one string type: Unicode strings.

由于以上区别,在Python3中,使用__str__()直接返回Model中的字段就可以了。

但是在Python2中,两者的返回类型是不同的:

    def __str__(self):
        return self.title.encode('utf-8')

    def __unicode__(self):
        return self.title

按规矩,在Python2中使用__unicode__()就不会出现什么问题了。
但是如果选择__str__()的话,平常情况也没啥问题,因为它本质上是override了基类django.db.models.Model中的同名函数。

不过使用中文时,又会遇到老生常谈的encode和decode问题。
当模型中有外键时(如Blog模型中使用taggit.manager.TaggableManager类型作为tag外键时,ManytoMany),删除模型记录时(某一篇Blog),就会报错:

DjangoUnicodeDecodeError: 'ascii' codec can't decode byte 0xe4 in position 0: ordinal not in range(128). You passed in <TaggedItem: [Bad Unicode data]> (<class 'taggit.models.TaggedItem'>)

错误报告的大意就是传入的字符,无法decode。
我猜测是在程序中调用了__str__(),传入的utf-8类型的字符程序无法正确decode,从而导致了错误。(虽然我找了大半天都没找到在哪调用的,网上也没有相关解答。。。/(ㄒoㄒ)/~~)

结论就是,在Python2中,使用__unicode__()就对了。

(20160925补充)在Django文档中也有介绍:

__str__
还是 __unicode__
?
对于Python 3来说,这很简单,只需使用__str__() 
对于Python 2来说,你应该定义__unicode__() 方法并返回unicode
值。
Django 模型具有一个默认的__str__() 方法,它会调用__unicode__() 并将结果转换为UTF-8 字节字符串。
这意味着unicode(p)
将返回一个Unicode 字符串,而str(p)
将返回一个字节字符串,其字符以UTF-8编码。
Python 的行为则相反:对象
__unicode__
方法调用__str__
方法并将结果理解为ASCII 字节字符串。
这个不同点可能会产生困惑。

defaultdict相关

python defaultdict

时间设置

    #pub_date = models.DateTimeField('date published', auto_now_add=True)
    #if set auto_now=True or auto_now_add=True, the time variable is read-only.
    #default=timezone.now(), can auto set the time and also give the choice to change it
    #to support this function, we should set USE_TZ=False
    pub_date = models.DateTimeField('date published', default=timezone.now())
    last_edit_date = models.DateTimeField('last edited', auto_now=True)

auto_now=True是每次修改都会更新时间,是“最后一次修改的时间”。 auto_now_add=True是自动添加时间,是“创建的时间”。二者设置之后,DateTimeField就变成只读模式。

若要可以自动设置为创建时间,还能够在之后进行修改,则使用default=timezone.now(),前提是在setting.py中设置USE_TZ=False,防止冲突报错。

报错local variable 'xxx' referenced before assignment

categorys = Category.objects.all()
def archive(request,name=''):
    args = dict()
    args['data'] = []
    blogs = Blog.objects.exclude(title__in=exclude_blog)
    if name != '':
        categorys_filtered = categorys.filter(short_name=name)
    else:
        categorys_filtered = categorys
    for category in categorys_filtered:
        bloglist = get_sorted_bloglist(blogs,category)
        if len(bloglist) > 0:#to make sure the category have related blogs
            args['data'].append((category,bloglist))
    args['categorys'] = categorys    
    return render(request, 'css3two_blog/archive.html', args)

如果没有新建变量categories_filtered,那么就会报此错误。
即如下所示情况下,categorys将会被认为是函数内的变量,而不是global变量:

    if name != '':
        categorys = categorys.filter(short_name=name)

转义

参考:django的转义总结:escape,autoescape,safe,mark_safe

何谓转义?就是把html语言的关键字过滤掉。例如,<div>就是html的关键字,如果要在html页面上呈现<div>,其源代码就必须是<div> PS:转义其实就是把HTML代码给转换成HTML实体了!

也就是说,如果我们要返回一个HTML格式的文本,一定要将转义开关设置为关闭,否则类似<div>这种格式就无法正确返回。

常见的几种方法:

  1. filter
    @register.filter(is_safe=True),设置为safe,不用自动转义。
  2. template
    使用{% autoescape off %} ...{% endautoescape %} 即可关闭自动转义。
  3. mark_safe
    from django.utils.safestring import mark_safe
    return mark_safe(str)
    标记为safe,不用自动转义。

MEDIA_ROOT和MEDIA_URL,以及类似的STATIC、TEMPLATE

MEDIA_ROOT表示路径,MEDIA_URL表示目录。
需要在setting.py中设置:

MEDIA_URL = '/media/'
MEDIA_ROOT = os.path.join(BASE_DIR,'media')

同时,为了能够获取url,还需要在urls.py中设置:

urlpatterns = [
    url(r'^admin/', admin.site.urls),
]+ static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)

表示,如果遇到了MEDIA_URL,要到MEDIA_ROOT路径下去寻找。

STATIC也是同样的道理。
STATIC_URL = '/static/'
在DEBUG=True时,Django会到Project中的各个app中寻找对应的目录。例如在Aproject中有Bapp,那么Django会到Bapp中寻找static目录下是否有Bapp目录,也就是说目录为:./Aproject/Bapp/static/Bapp/xxx。
在DEBUG=False时,有另外的处理方式。

TEMPLATE则需要在setting.py中的TEMPALTES列表中的’DIR'中加上templates所在的目录,Django会到各个app下寻找。

字段Field

普通的有CharField,DateTimeField,TextField。
有点特殊的见下。

models.SlugField

Slug 是一个新闻术语(通常叫做短标题)。一个slug只能包含字母、数字、下划线或者是连字符,通常用来作为短标签。通常它们是用来放在URL里的。

URL中不能有中文,还有一些特殊字符,如果一篇Blog需要靠title来生成URL,则需要用到Slug。
用法如下,其中unidecode将一个Unicode编码的对象音译成一个ASCII对象(在实际中若没有对应的ASCII码,则需要将原始Unicode码对应的字符进行音译,然后再转化为ASCII码,对应关系如:“你好”和“nihao”):

from unidecode import unidecode
self.slug = slugify(unidecode(self.title))

taggit.managers.TaggableManager

用于Blog的标签。
需要到setting.py中的INSTALLED_APPS增加'taggit’。

models.FileField

如果有文件相关操作,就会用到models.FileField。models.ImageField继承自它。

FileField.upload_to是一个路径,它将附加到MEDIA_ROOT后面来确定url属性的值,也就是说,它实际上是MEDIA_ROOT下的一个子路径。数据库中存储该值,而实际上的文件本体存储在该路径下。
除直接给出路径外,还可以设置成一个可调用对象如函数,这个可调用对象必须有两个参数:FileField所在的模型实例,filename(带有前向/)。
如:

def get_upload_md_name(obj,filename):
    if obj.pub_date:
        year = obj.pub_date.year
    else:
        year = datetime.now().year
    upload_to = mdfile_upload_dir % (year, obj.slug + '.markdown')
    return upload_to
class Blog(models.Model):
    md_file = models.FileField(upload_to=get_upload_md_name,blank=True)

若需要使用url属性,以上述的md_file为例,则是object.md_file.url。

FieldFile.
save
(name, content, save=True),其中content应该是django.core.files.File的一个实例,而不是Python内建File对象。save参数表示关联的文件被修改时是否保存,默认True。

self.md_file.save(self.slug + '.markdown', ContentFile(self.body.encode('utf-8')), save=False)

ModelForm

model表示Form和Model的关联。
widgets表示admin界面显示效果。
exclude表示不显示哪些参数,fields表示显示哪些参数。二者必须有其一。

class BlogAdminForm(forms.ModelForm):
    class Meta:
        model = Blog
        widgets = {
                   'body' : Textarea(attrs={'cols':100, 'rows':100}),
                   }
        exclude = ()

最后,在Model对应的Admin类中进行form的关联。

class BlogAdmin(admin.ModelAdmin):
    form = BlogAdminForm

保存操作

model需要自定义保存,可实现如下函数:

    def save(self, *args, **kwargs):
        do_something()
        super(Blog,self).save(*args,**kwargs)
        do_something()

同时,在model相关的admin中也有保存函数:

class BlogAdmin(admin.ModelAdmin):
    def save_model(self, request, obj, form, change):
        obj.save()
        print obj.slug, "save successfully"

obj即为该model的实例对象,form就是上述提到的BlogAdminForm,change表示类型。

分页

分页是一个很常见的功能。可以手工实现,Django也提供了更方便的方法。

from django.core.paginator import Paginator, EmptyPage, PageNotAnInteger
def home(request,page='1'):
    raw_blogs = Blog.objects.filter(status='p')
    paginator = Paginator(raw_blogs,5)
    page = int(page)
    try:
        blog_list = paginator.page(page)
    except PageNotAnInteger:
        # If page is not an integer, deliver first page.
        blog_list = paginator.page(1)
    except EmptyPage:
        # If page is out of range (e.g. 9999), deliver last page of results.
        blog_list = paginator.page(paginator.num_pages)
...

首先获得原始blogs列表。根据此列表,设定每页最多显示五条,生成一个Paginator对象。page是传入对象,表示在请求哪一页的blogs。根据page的输入返回结果。

markdown

markdown编辑器会将写好的markdown文本,转换为html文本,然后在浏览器上我们就可以看到非常漂亮的结果。
我使用python中的markdown库来完成编辑器的作用。Using Markdown as a Python Library
见下方的代码,mark_safe表示返回的不需要转义的字符串。
markdown.markdown(text [, **kwargs])。text为传入值,必须是Unicode类型。extensions参数是一系列扩展,fenced_code是识别代码用的;codehilite是代码高亮,具体使用哪种css需要在template中写明。safe_mode见上述转义章节。enable_attributes默认为True,在safe_mode为True时,默认为False,即将attributes的转换打开或关闭,具体什么是attributes未找到,存疑。还有其他一些参数。

templatetag

在Django的Template中可以使用过滤器来对内容进行过滤。内置过滤器参考
也可以自定义。自定义模板标签和过滤器
自定义的templatetag必须包含在某个app中,在这个app中需要建立一个templatetags目录,在目录中需要有一个__init__.py文件来使得该目录可以作为Python的包。
在template文件中使用该过滤器时,需要使用{% load xxx %}来导入,其中xxx为templatetags目录下的某个模块名字。

register是template.Library()的一个实例,所有的标签和过滤器都是在其中进行注册的。
custom_markdown(value, ...)就是自定义的过滤器函数,当然在未注册前它只是一个普通的函数。其中value表示输入的变量,后面还可以设定有其他参数。
为了能够使用它,需要在register中将其注册为过滤器。
使用装饰器方法@register.filter(),filter的意思就是过滤器。如果filter中对name参数进行了设置,那么Django就是用name值来作为过滤器的名字;如果没有,则使用函数的名字来作为过滤器。is_safe参数详见上述转义章节。由于返回的是经过markdown处理后的html,所以此处不转义。
另一个装饰器@stringfilter表示该模板过滤器只希望用一个字符串来作为第一个参数,那么在被传入过滤器函数前,将会把value值转化为字符串值。

import markdown

from django import template
from django.template.defaultfilters import stringfilter
from django.utils.safestring import mark_safe

register = template.Library()

@register.filter(is_safe=True)
@stringfilter
def custom_markdown(value):
#     print type(value)
    return mark_safe(markdown.markdown(value,
    extensions = ['markdown.extensions.fenced_code', 'markdown.extensions.codehilite'],
                                   safe_mode=True,
                                   enable_attributes=False))

RSS

RSS需要设置好返回的item的值具体是model中的什么。详情可直接搜索获得。

mail

发送邮件需要指定SMTP主机和发送端口,在setting.py中使用EMAIL_HOST和EMAIL_PORT来给二者赋值。给EMAIL_HOST_USER和EMAIL_HOST_PASSOWRD赋值用来验证SMTP主机。如果需要使用加密链接,则需要给EMAIL_USE_TSL或EMAIL_USE_SSL赋值。
send_mail

send_mail
(subject, message, from_email, recipient_list, fail_silently=False, auth_user=None, auth_password=None,connection=None, html_message=None)

subject是邮件的标题;message是邮件的正文;from_email是发送者邮箱地址,若赋值为None,则使用在setting.py中设置的DEFAULT_FROM_EMAIL来赋值;recipient_list是接收者的邮箱地址列表。
需要注意的是from_email设置的邮箱地址,必须和SMTP主机相匹配,否则无法使用。

以上是开发者手动发送邮件。有些情况下,Django有自动发送邮件的场景。比如在DEBUG=False时,无法直接看到错误报告,Django会为ADMINS设置中的用户发送邮件。
所以,为了发送邮件,除了上述提到的SMTP配置之外,还需要在ADMINS元组中添加接收者的相关信息(格式是(name,email)),设置SERVER_EMAIL来确定发送者的邮件地址。
如果有启用BrokenEmailLinksMiddleware,那么就需要设置MANAGERS,它的格式与ADMINS相同,用来接收死链报告。

form

在Template中使用<form action="xx" method="yy">...</form>来构建表单。
action属性指定的URL用来指出将表单数据发送到何处,若为空则是表单所在页面来处理。method指定是GET还是POST方法(只能是二者其一),通常会更改系统状态的请求需要使用POST方法。

Django 会处理表单工作中的三个显著不同的部分:
准备数据、重构数据,以便下一步提交。
为数据创建HTML 表单
接收并处理客户端提交的表单和数据

以下是一个用来发送邮件的例子,由于包含一些敏感信息,使用POST方法。
forms.py如下:

from django import forms

class ContactForm(forms.Form):
    subject = forms.CharField(label='Subject:', max_length=100)
    message = forms.CharField(label = 'Message:', widget=forms.Textarea)
    email = forms.EmailField(label='E-mail:')
    name = forms.CharField(label='Name:',max_length=50,required=False)

views.py如下:

def contact(request):
    if request.method == 'POST':
        form = ContactForm(request.POST)
        if form.is_valid():
            subject = form.cleaned_data['subject']
            sender = form.cleaned_data['email']
            message = form.cleaned_data['message']
            recipients = [settings.DEFAULT_FROM_EMAIL,sender]
            send_mail(subject=subject, message=message, recipient_list=recipients,from_email=None)
            return HttpResponseRedirect('/thanks/')
    else:
        form = ContactForm()    
    return render(request, 'css3two_blog/contact.html', {'form' : form, 'categorys' : categorys})

首先在forms.py中定义一个Form类。
如果访问的视图是GET请求,那么Form类将创建一个空的表单实例然后放置到要渲染的模板的上下文中。
如果是POST请求,则使用request.POST对新创建的Form实例进行填充,这叫做“绑定数据到表单”。
然后调用is_valid()方法,它会为所有的表单数据进行验证。如果为False,那么就会将现有数据进行返回。如果为True,那么验证后的表单数据将会被放入cleaned_data属性中。

Admin Action

自定义django的admin后台action
Admin 界面上的Action

method_splitter

Django ------ 高级 view 和 URLconf 配置 额外URLconf参数技术应用到自己的工程

locals()函数

Django:locals()小技巧
django-using-locals

 

分享到:
评论

相关推荐

    Django1.6 官方文档

    **Django 1.6 官方文档** 是学习和使用 Django 的重要资源之一。该文档由 Django 软件基金会官方编写,旨在帮助开发者快速入门并掌握 Django 的核心概念和技术细节。 #### 二、文档结构 文档按照章节组织,主要...

    python django官方手册

    - **获取帮助**:在学习和使用 Django 过程中遇到问题时,可以参考文档中的这一章节来寻找答案或指引。 - **入门步骤**:这部分介绍了如何快速上手 Django,包括安装环境配置、基本概念介绍等。 - **模型层**:模型...

    django1.11英文手册

    除了核心功能外,Django 还支持许多常用的 Web 应用工具,如缓存、日志记录、分页等。这部分内容提供了对这些工具的详细说明,并展示了如何在 Django 项目中有效地集成它们。 ##### 1.16 其他核心功能 这部分涵盖...

    分页+模糊查询(简单易学)

    分页的实现通常涉及数据库查询的LIMIT和OFFSET关键字,或者使用特定的ORM(对象关系映射)库提供的方法,如Java的Spring Data JPA的Pageable接口或Python的Django框架的Paginator类。分页的优点在于减少了网络传输的...

    利用Python的Django框架中的ORM建立查询API

    在当今的Web开发实践中,Python的Django框架是一个广泛使用的全栈Web框架,它提供了一套完整的工具,允许开发者快速创建高质量的应用程序。Django框架的一个核心组件是其对象关系映射器(Object-Relational Mapper,...

    网页开发很炫的分页显示

    在后端,常见的Web框架如Spring Boot、Django、Ruby on Rails等都内置了分页功能。例如,Spring Data JPA 提供了`Pageable`接口,可以通过设置页码和每页大小来获取分页数据。 六、分页优化技巧 1. **缓存策略**:...

    django_rest_tutorial:从https学习Django REST框架

    在这个教程中,我们将深入探讨Django REST框架的核心概念和使用方法。 一、Django REST框架基础 1. **安装**:首先,你需要通过pip安装Django REST框架,命令为`pip install djangorestframework`。确保已经安装了...

    Django-Model数据库操作(增删改查、连表结构)详解

    在Django框架中,Model是...以上就是Django-Model数据库操作的详解,包括增删改查和连表结构的使用,以及各种字段类型的介绍。这些基础知识对于任何Django开发者来说都至关重要,能帮助构建高效、稳定的数据库应用。

    Official_Django_REST_Framework_tutorial

    DRF是一个用于构建Web API的高级框架,它建立在Django之上,提供了丰富的工具集,如序列化、认证、权限管理、分页和过滤等功能。它的设计目标是简化API的开发过程,同时保持灵活性,使开发者能够快速构建高质量的API...

    利用python3.4搭建的bbs

    - **模板(Template)**:负责页面的布局和展示,可以使用Django模板语言(Django Template Language, DTL)。 - **视图(View)**:处理HTTP请求,调用模型并渲染模板,实现具体功能。 项目可能涉及的Django功能...

    ORM查询优化.zip

    在处理大数据时,应尽量避免使用`get()`,因为它会引发`DoesNotExist`或`MultipleObjectsReturned`异常,而`filter()`和`exists()`则更加高效,特别是`exists()`仅检查是否存在匹配的记录,不返回实际对象。...

    python课程设计,python爬虫,爬小说,存入mysql数据库

    在实际项目中,还需要考虑性能优化,如使用缓存减少数据库查询,设置合理的爬虫速度避免对目标网站造成压力,以及利用Django的分页功能来改善用户体验。 通过以上步骤,我们可以实现一个完整的Python课程设计项目...

    基于Python实现的实验信息综合管理系统_python实验室_python管理系统_实验室管理系统_实验室管理

    5. **日志和错误处理**:为了追踪系统运行状态和调试,日志记录是必不可少的。Python的logging模块可以帮助我们实现这一功能,同时异常处理(try-except语句)可以确保系统在遇到问题时能够优雅地处理。 6. **性能...

    sql-使用python开发的sql查询平台-优质项目.zip

    总的来说,"sql-使用python开发的sql查询平台-优质项目"结合了Python的便利性和SQL的强大功能,为用户提供了一个高效、安全的数据库查询环境。无论是数据分析师、开发人员还是管理人员,都能从中受益,快速获取和...

    android 手机聊天室

    9. **状态管理**:随着聊天记录增加,可能需要实现数据分页加载,这涉及到Android的数据绑定和状态管理。LiveData或Room Persistence Library可以帮助管理数据状态并简化内存管理。 10. **错误处理与日志记录**:...

    数据库课程设计源代码 课程设计

    - 主键与外键:每个表可能有一个主键,用于唯一标识记录,而外键则用于建立表之间的关联。 3. SQL操作: - SELECT语句:用于查询员工信息,如根据部门、职位筛选员工。 - INSERT语句:添加新员工到数据库。 - ...

    ExtJs_servlet_JDBC 做的增删查改

    同时,随着技术的发展,现在更多的应用倾向于使用RESTful API和现代的前端框架(如React或Vue.js)来替换ExtJs,后端则可能选择Spring Boot或Django等框架,以简化开发流程并提升效率。不过,理解基础的ExtJs、...

    小型用户登入系统下下下

    2. **显示留言**:在前端展示留言列表,可能需要学习如何动态加载和分页。 3. **添加和删除留言**:用户可以提交新留言或删除自己的留言,这涉及到前后端交互和数据库操作。 4. **权限控制**:确保只有登录用户...

    Python-近实时监控Github敏感信息泄露并发送告警通知

    为避免此问题,可以使用Github提供的分页功能,以及适当的缓存策略。 8. **扩展性**:系统设计应考虑扩展性,允许添加更多敏感信息类型、仓库或集成其他告警方式。 通过以上技术点的综合运用,这个Python项目能...

    图书管理系统

    2. 关系模型:通过外键建立各表之间的关联,例如图书信息表与借阅记录表之间通过图书ID关联。 三、功能模块 1. 图书管理:包括图书的录入、修改、删除、查询等功能,支持按不同条件(如书名、作者等)快速查找。 2....

Global site tag (gtag.js) - Google Analytics