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開發 |