在網站中分享內容
此章內容:
- 創建一個many-to-many(多對多)關系
- 定制表單(form)的行為
- 在 Django 中使用 jQuery
- 創建一個 jQuery 書簽
- 通過使用 sorl.thumbnail 來生成縮略圖
- 實現 AJAX 視圖(views)并且使這些視圖(views)和 jQuery 融合
- 為視圖(views)創建定制化的裝飾器 (decorators)
- 創建 AJAX 分頁
建立一個能為圖片打標簽的網站
我們將允許用戶可以在我們網站中分享他們在其他網站發現的圖片,并且他們還可以為這些圖片打上標簽。為了達到這個目的,我們將要做以下幾個任務:
- 定義一個模型來儲存圖片以及圖片的信息
- 新建一個表單(form)和視圖(view)來控制圖片的上傳
- 為用戶創建一個可以上傳他們在其他網站發現的圖片的系統
創建圖片模型
新建應用 django-admin startapp images
添加應用
編輯models文件
from django.db import models
from django.conf import settings
# Create your models here.
class Image(models.Model):
user = models.ForeignKey(settings.AUTH_USER_MODEL,related_name='images_created')#標記了這張圖片 User 對象。
title = models.CharField(max_length=200)#標題
slug = models.SlugField(max_length=200,blank=True)# slug 表示的是只有字母、數字、下劃線和連字符的標簽
url = models.URLField()# 圖片的源url
image = models.ImageField(upload_to='images/%Y/%m/%d')# 圖片文件
description = models.TextField(blank=True)#描述
created = models.DateField(auto_now_add=True,db_index=True)#auto_now_add ,當對象被創建時候時間和日期將會被自動設置,我們使用了 db_index=True ,所以 Django 將會在數據庫中為這個字段創建索引
數據庫索引改善了查詢的執行。考慮為這個字段設置 db_index=True 是因為你將要很頻繁地使用 filter(),exclude(),order_by() 來執行查詢。ForeignKey 字段或者帶有unique=True的字段表明了一個索引的創建。你也可以使用Meta.index_together來為多個字段創建索引。
我們將要重寫 Image 模型的 save()方法來自動的生成slug字段。這個 slug字段基于title字段的值。像下面這樣導入slugify()函數, 然后在 Image 模型中添加一個 save() 方法:
from django.utils.text import slugify
class Image(models.Model):
# ...
def save(self, *args, **kwargs):
if not self.slug:
self.slug = slugify(self.title)#使用了 Django 提供的slugify()函數在沒有提供slug字段時根據給定的圖片標題自動生slug,然后,我們保存了這個對象。我們自動生成slug,這樣的話用戶就不用自己輸入slug字段了。
super(Image, self).save(*args, **kwargs)
建立多對多關系
我們將要在 Image 模型中再添加一個字段來保存喜歡這張圖片的用戶。因此,我們需要一個多對多關系。因為一個用戶可能喜歡很多張圖片,一張圖片也可能被很多用戶喜歡。
在 Image 模型中添加以下字段:
user_like = models.ManyToManyField(settings.AUTH_USER_MODEL,
related_name='images_liked',
blank=True)
當你定義一個ManyToMany字段時,Django 會用兩張表主鍵(primary key)創建一個中介聯接表(譯者注:就是新建一張普通的表,只是這張表的內容是由多對多關系雙方的主鍵構成的)。ManyToMany字段可以在任意兩個相關聯的表中創建。
同ForeignKey字段一樣,ManyToMany字段的related_name屬性使我們可以命名另模型回溯(或者是反查)到本模型對象的關系。ManyToMany字段提供了一個多對多管理器(manager),這個管理器使我們可以回溯相關聯的對象比如:image.users_like.all()或者從一個user中回溯,比如:user.images_liked.all()。
再數據表建立遷移
在admin中注冊
from django.contrib import admin
from .models import Image
class ImageAdmin(admin.ModelAdmin):
list_display = ['title', 'slug', 'image', 'created']
list_filter = ['created']
admin.site.register(Image, ImageAdmin)
從其他網站上傳內容
我們將使用戶可以給從他們在其他網站發現的圖片打上標簽。用戶將要提供圖片的 URL ,標題,和一個可選的描述。我們的應用將要下載這幅圖片,并且在數據庫中創建一個新的 Image 對象。
我們從新建一個用于提交圖片的表單開始。在images應用的路徑下創建一個 forms.py 文件,在這個文件中添加如下代碼:
from django import forms
from .models import Image
class ImageCreateForm(forms.ModelForm):
class Meta:
model = Image
fields = ('title', 'url', 'description')
widgets = {
'url': forms.HiddenInput,
}
這個表單只包含了 title,url,description字段。我們的用戶不會在表單中直接為圖片添加 URL。相反的,他們將會使用一個 JavaScript 工具來從其他網站中選擇一張圖片然后我們的表單將會以參數的形式接收這張圖片的 URL。我們覆寫 url 字段的默認控件(widget)為一個HiddenInput控件,這個控件將會被渲染為屬性是 type="hidden"的 HTML 元素。使用這個控件是因為我們不想讓用戶看見這個字段。
清潔表單字段
在form類中添加
def clean_url(self):
url = self.cleaned_data['url']
valid_extensions = ['jpg', 'JPG']
extension = url.rsplit('.', 1)[-1]
if extension is not in valid_extensions:
raise forms.ValidationError('圖片url不合法')
return url
驗證(validation)url的結尾是不是jpg或者JPG
覆寫模型表單中的save()方法
把save()方法加入ImageCreateForm中:
from urllib import request
from django.core.files.base import ContentFile
from django.utils.text import slugify
def save(self, force_insert=False,
force_update=False,
commit=True):
image = super(ImageCreateForm, self).save(commit=False)
image_url = self.cleaned_data['url']
image_name = '{}.{}'.format(slugify(image.title),
image_url.rsplit('.', 1)[1].lower())
# 從給定的 URL 中下載圖片
response = request.urlopen(image_url)
image.image.save(image_name,
ContentFile(response.read()),
save=False)#image是Image對象,image.image是一個image字段,這個字段是一個文件對象,保存需要使用這樣的方式來
if commit:
image.save()
return image
創建views
from django.shortcuts import render, redirect
from django.contrib.auth.decorators import login_required
from django.contrib import messages
from .forms import ImageCreateForm
@login_required
def image_create(request):
"""
View for creating an Image using the JavaScript Bookmarklet.
"""
if request.method == 'POST':
# form is sent
form = ImageCreateForm(data=request.POST)
if form.is_valid():
# form data is valid
cd = form.cleaned_data
new_item = form.save(commit=False)
# assign current user to the item
new_item.user = request.user
new_item.save()
messages.success(request, 'Image added successfully')
# redirect to new created item detail view
return redirect(new_item.get_absolute_url())
else:
# build form with data provided by the bookmarklet via GET
form = ImageCreateForm(data=request.GET)
return render(request, 'images/image/create.html', {'section': 'images',
'form': form})
創建urls
from django.conf.urls import url
from . import views
urlpatterns = [
url(r'^create/$', views.image_create, name='create'),
]
主urls中導入
urlpatterns = [
url(r'^admin/', include(admin.site.urls)),
url(r'^account/', include('account.urls')),
url(r'^images/', include('images.urls', namespace='images')),
]
創建html文件
{% extends "base.html" %}
{% block title %}Bookmark an image{% endblock %}
{% block content %}
<h1>Bookmark an image</h1>

<form action="." method="post">
{{ form.as_p }}
{% csrf_token %}
<input type="submit" value="Bookmark it!">
</form>
{% endblock %}