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.allPerson.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配置,视图,模板及表单的高级进阶,欢迎关注我的微信号, 决不让你失望。

猜你喜欢

转载自blog.csdn.net/weixin_42134789/article/details/80752986
今日推荐