1. 程式人生 > >Models模型(下)

Models模型(下)

ima lte 字段 跳轉 root fault tor 所有 utils

一、最基本的django模型

1、先看下一個新聞博客的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 # Create your models here. 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"

2、基礎模型很多時候並不能滿足需求。試想打算使用django自帶的通用視圖創建文章,由於通用視圖在完成對象創建後需要跳轉到文章的absolute_url, 這時需要在模型裏加入自定義的get_absolute_url方法。由於希望統計每篇文章瀏覽次數,還需自定義一個使瀏覽量自增1的viewed方法,並更新數據表。

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。

from django.db import models

# Create your models here.


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方法。

from django.db import models
import hashlib


class UserInfo(models.Model):
    username = models.CharField("用戶名", max_length=64, unique=True)
    password = models.CharField("密碼", max_length=64)
    uid = models.CharField(verbose_name=個人唯一ID, max_length=64, unique=True)

    wx_id = models.CharField(verbose_name="微信ID", max_length=128, blank=True, null=True, db_index=True)

    def save(self, *args, **kwargs):
        # 創建用戶時,為用戶自動生成個人唯一ID
        if not self.pk:
        # 存在就更新,不存在就創建
            m = hashlib.md5()
            m.update(self.username.encode(encoding="utf-8"))
            self.uid = m.hexdigest()
        super(UserInfo, self).save(*args, **kwargs)

五、完美的Django高級模型結構

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

# Create your models here.

# 自定義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):
    pass

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


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

Models模型(下)