Django基礎(6): 模型Models高級進階必讀。

你或許已經早已讀過我們的原創文章Django基礎(1): 模型Models的介紹與設計,並已經知道一個模型的設計是一個app的核心。然而僅知道基礎知識是遠遠不夠的,在實際web開發過程中你需要掌握一些模型的高級技巧,比如靈活定義Meta選項,動態定義文件上傳路徑,使用Manager方法,重寫save方法,才能充分發揮Django的靈活優勢。今天小編我以親身經歷就來講下Django模型Models的高級進階,分享些實用技巧。另外送個粽子給大家,祝大家端午節快樂!!

一個最基本的django模型

我們來先看下一個新聞博客的Article模型。這個模型是最基本的django模型,裡面包括了各個欄位(fields),重寫了顯示文章對象名字的__str__方法(python內置的),並在Meta選項里給模型命名(verbose name)。我們建議每個django模型至少包括欄位,重寫的__str__方法和Meta選項。

from django.db import models
from django.contrib.auth.models import User
from django.urls import reverse
from django.utils.timezone import now

class Article(models.Model):

STATUS_CHOICES = (
(d, 草稿),
(p, 發表),
)

title = models.CharField(標題, max_length=200, unique=True)
slug = models.SlugField(slug, max_length=60)
body = models.TextField(正文)
pub_date = models.DateTimeField(發布時間, default=now, null=True)
create_date = models.DateTimeField(創建時間, auto_now_add=True)
mod_date = models.DateTimeField(修改時間, auto_now=True)
status = models.CharField(文章狀態, max_length=1, choices=STATUS_CHOICES, default=p)
views = models.PositiveIntegerField(瀏覽量, default=0)
author = models.ForeignKey(User, verbose_name=作者, on_delete=models.CASCADE)

tags = models.ManyToManyField(Tag, verbose_name=標籤集合, blank=True)

def __str__(self):
return self.title

class Meta:
verbose_name = "article"

基礎模型很多時候並不能滿足我們的需求

django的基礎模型很多時候並不能滿足我們的需求。試想我們打算使用django自帶的通用視圖創建文章,由於通用視圖在完成對象創建後需要跳轉到文章的absolute_url, 這時我們需要在模型里加入自定義的get_absolute_url方法。由於我們希望統計每篇文章瀏覽次數,我們還需自定義一個使瀏覽量自增1的viewed方法,並更新數據表(詳情見:django實戰,之開發頁面計數器。)

def get_absolute_url(self):
return reverse(blog:article_detail, args=[str(self.id)])

def viewed(self):
self.views += 1
self.save(update_fields=[views])

如果我們希望調用Article.objects.all()按時pub_date降序排列查詢結果,我們可以在Meta里加入ordering選項即可。

class Meta:
ordering = [-pub_date]
verbose_name = "article"

模型中自定義圖片和文件上傳路徑

Django模型中的ImageField和FileField的upload_to選項是必填項,其存儲路徑是相對於MEIDA_ROOT而來的。然而我們可能希望動態定義上傳路徑,比如把文件上傳到每個用戶名下的文件夾里,並對上傳文件重命名,這時我們可以定義一個user_directory_path方法。

from django.db import models
from django.contrib.auth.models import User
import uuid
import os

# Create your models here.

def user_directory_path(instance, filename):
ext = filename.split(.)[-1]
filename = {}.{}.format(uuid.uuid4().hex[:10], ext)
# return the whole path to the file
return os.path.join(instance.user.id, "avatar", filename)

class UserProfile(models.Model):
user = models.OneToOneField(User, on_delete=models.CASCADE, related_name=profile)
avatar = models.ImageField(upload_to=user_directory_path, verbose_name="頭像")

Django模型的Manager方法值得一看

Django模型自帶models.Manager方法,可以簡化我們的代碼。如下面案例中,我們可以使用Person.objects.all()查詢到所有人,而Person.authors.all和Person.editors.all()只返回所authors和editors。

class AuthorManager(models.Manager):
def get_queryset(self):
return super().get_queryset().filter(role=A)

class EditorManager(models.Manager):
def get_queryset(self):
return super().get_queryset().filter(role=E)

class Person(models.Model):
first_name = models.CharField(max_length=50)
last_name = models.CharField(max_length=50)
role = models.CharField(max_length=1, choices=((A, _(Author)), (E, _(Editor))))
objects = models.Manager()
authors = AuthorManager()
editors = EditorManager()

Django模型的save方法重寫

在很多應用場景中我們需要重寫django模型的save方法,比如本例中我們希望根據title生成slug,並在一個對象數據save完成後做其它事情(比如發送郵件或發送信號),我們可以按如下代碼重寫django模型的save方法,非常容易。

from django.template.defaultfilters import slugify

class Article(models.Model):
...

def save(self, *args, **kwargs):
if not self.slug or not self.id:
self.slug = slugify(self.title)
super().save(*args, **kwargs)

# do other things. send_mail()

一個完美的Django高級模型結構

一個完美的django高級模型結構如下所示,可以滿足絕大部分應用場景,希望對你有所幫助。

from django.db import models
from django.urls import reverse

# 自定義Manager方法
class HighRatingManager(models.Manager):
def get_queryset(self):
return super().get_queryset().filter(rating=1)

class Product(models.Model):
# CHOICES選項
RATING_CHOICES = (
("1", Very good),
("2", Good),
("3", Bad),
)

# 數據表欄位
name = models.CharField(name, max_length=30)
rating = models.CharField(max_length=1, choices=RATING_CHOICES)

# MANAGERS方法
objects = models.Manager()
high_rating_products =HighRatingManager()

# META類選項
class Meta:
verbose_name = product
verbose_name_plural = products

# __str__方法
def __str__(self):
return self.name

# 重寫save方法
def save(self, *args, **kwargs):
do_something()
super().save(*args, **kwargs)
do_something_else()

# 定義絕對路徑
def get_absolute_url(self):
return reverse(product_details, kwargs={pk: self.id})

# 定義其它方法
def do_something(self):

小編我寫篇文章不易,歡迎轉發點贊。下面我要去玩局王者榮耀犒勞下自己了。接下來我會寫URL配置,視圖,模板及表單的高級進階,歡迎關注我的微信號, 決不讓你失望。


推薦閱讀:

TAG:Django(框架) | Python入門 | Web開發 |