Enhancing Your Blog With Advanced Features

Photo by Sergo Karakozov on Unsplash

Form

Django 提供了两种不同的Form:

  • ModelForm: 可以直接根据Model生成Form
  • Form: 自定义Form

ModelForm

示例:

1
2
3
4
5
6
from .models import Comment

class CommentForm(forms.ModelForm):
class Meta:
model = Comment
fields = ('name', 'email', 'body')

ModelForm在View中可以直接保存,不用经过转化为Model的步骤。

1
2
3
4
5
6
7
def post_detail(request):
if request.method == 'POST':
form = CommentForm(request.POST)
if form.is_valid():
form.save()
# comment = form.save(commit=False)
# comment.save()

Form

示例:

1
2
3
4
5
6
7
from django import forms

class EmailPostForm(forms.Form):
name = forms.CharField(max_length=25)
email = forms.EmailField()
to = forms.EmailField()
comments = forms.CharField(required=False, widget=forms.Textarea)

每个Field都有一个默认的widget,CharField默认的render为<input type="text">comment制定了Textarea,则会被render为textarea。

在view中用form接收post或get方法如下:

1
2
3
4
5
6
7
8
9
10
11
12
def post_share(request, post_id):
post = get_object_or_404(Post, id=post_id)

if request.method == 'POST':
form = EmailPostForm(request.POST)
if form.is_valid():
cd = form.cleaned_data
# ...
else:
form = EmailPostForm()

return render(request, 'blog/post/share.html', {'post': post, 'form': form})

发送邮件

发送邮件需要现在项目的settings.py里定义email的设置,以QQ邮箱的配置为例:

1
2
3
4
5
6
# Email
EMAIL_HOST = 'smtp.qq.com'
EMAIL_HOST_USER = 'yarving@qq.com'
EMAIL_HOST_PASSWORD = 'secret-key'
EMAIL_PORT = 465
EMAIL_USE_SSL = True

发送邮件的代码:

1
2
3
from django.core.mail import send_mail

send_mail('subject', 'email body', 'sender@email.com', ['reciver-address@email.com'], fail_silently=False)

拼凑完整URL

Django的request.build_absolute_uri()方法可以拼凑出完整的url,包含http schema和hostname。

示例:

1
2
3
def post_share(request, post_id):
# ...
psot_url = request.build_absolute_uri(post.get_absolute_url())

在model中reverse url的示例:

1
2
3
4
5
6
7
from django.core.urlresolvers import reverse
from django.db import models

class Post(models.Model):
# ...
def get_absolute_url(self):
return reverse('blog:post_detail', args=[self.publish.year, self.publish.slug])

Template filters

pluralize

用法如下,在模板文件中:

1
{{ total | pluralize }}

  • 当total为1时,后面不加任何东西
  • 当total为0或者比1大时,后面加一个s

forloop

forloop要放在模板的for语句中,有下列函数可以使用

counter和empty

用法如下,在模板文件中:

1
2
3
4
5
{% for comment in comments %}
{{ forloop.counter }} by {{ comment.name }}
{% empty %}
<p>Display some content when no content in for loop</p>
{% endfor %}

  • forloop.counter会显示循环的序号,从1开始
  • empty表示如果for语句中的comments为空的时候,显示下面的内容

last

如:

1
2
3
{% for tag in post.tags.all %}
{% if not forloop.last %}, {% endif %}
{% endfor %}

join

示例

1
{{ post.tags.all | join: ", "}}

将post的所有tag都用,连接成字符串

Taggit

当要为django搭建的博客的博文创建tag时,可以用django-taggit来实现

  • 安装:pip install django-taggit
  • 添加到settings.py的INSTALLED_APPS

添加进model

1
2
3
4
5
from taggit.managers import TaggableManager

class Post(models.Model):
# ...
tags = TaggableManager()

可以进行如下操作:

1
2
3
post.tags.add('music', 'jazz', 'django')
post.tags.all()
post.tags.remove('music')

Queryset

values_list()

函数原型:values_list(*fields, flat=False, named=False)

API链接

可以将值传递为列表,示例用法如下:

1
2
psot_tags_ids = post.tags.values_list('id', flat=True)
# return flat list like [1, 2, 3, 4]

annotate

示例

1
posts.annotate(same_tags=Count('tags')).order_by('-same_tags', '-publish')[:4]

用QuerySet查询集的方式一直比较低端,只会使用filter/Q函数/exclude等方式来查询,数据量比较小的时候还可以,但是如果数据量很大,而且查询比较复杂,那么如果还是使用多个filter进行查询效率就会很低。

提高查询数据库效率的方案有两种:

第一种,是使用原生的SQL语句来进行查询,这样的优点在于能够完全按照开发者的意图来执行,效率会很高,但是缺点也很明显:

  1. 开发者需要非常熟悉SQL语句,加大开发者的工作量,同时,夹杂着SQL的项目也不利于以后程序的维护,增大程序的耦合度。
  2. 若查询条件是动态变化的,则会使开发变得更加困难。

django为了解决这一难题,提供了aggregate(聚合函数)和annotate(在aggregate的基础上进行GROUP BY操作)。

参考资料

0%