68
60

More than 5 years have passed since last update.

【Django】Model定義周辺の小ネタ

Last updated at Posted at 2017-12-15

今年に入ってDjangoをやり始めたヒヨっこですが、そのヒヨっこがDjangoでアプリケーションを開発するにあたって「これはよいかもなー」などと思った、Model定義周辺の知見を書いていきます。
すでに長年使われている方々にとっては「何を今更」という話題かもしれませんが。
あと、ほとんどTwo Scoops of Django 1.11の受け売りです。

TimeStampedModelを定義する

DjangoでModleを定義するにあたって、大抵の場合レコードが作成された時の日時を格納するフィールドと、レコードが更新された時に日時を格納するフィールドを持っていると思います。
んで、Model定義ごとにそれらを定義してもいいんですが、テンプレートを作って、それを継承させたほうが楽だよね、という話です。

core/models.py
from django.db import models

class TimeStampedModel(models.Model):
    created = models.DateTimeField(auto_now_add=True)
    modified = models.DateTimeField(auto_now=True)

    class Meta:
        abstract = True

abstract = Trueにしておくと、マイグレーションしてもテーブルが作られることはない。

んで、これを以下のように継承するという感じです。take it easy.

apps/models.py
from django.db import models

from core.models import TimeStampedModel

class Sample(TimeStampedModel):
    title = models.CharField(max_length=200)

ENUMを使って定数/選択肢を定義する

通常、Modelに定数/選択肢を設定する場合は、以下のように書くと思います。

apps/models.py
from django import models

class Idol(models.Model):
    ATTRIBUTE_CUTE = 'cu'
    ATTRIBUTE_COOL = 'co'
    ATTRIBUTE_PASSION = 'pa'

    ATTRIBUTE_CHOICES = (
        (ATTRIBUTE_CUTE, 'Cute'),
        (ATTRIBUTE_COOL, 'Cool'),
        (ATTRIBUTE_PASSION, 'Passion')
    )

    name = models.CharField(maxlength=255)
    attribute = models.CharField(
        max_length=2,
        choices=ATTRIBUTE_CHOICES
    )

この場合、attributeを条件にオブジェクトを取得する場合、以下のようになります。

pa_idols = Idol.objects.filiter(attribute=Idol.ATTRIBUTE_PASSION)

Python3.4以降には標準ライブラリとして、enumが追加されており、これを使って、定数/選択肢を記述することができます。(3.4以前の場合はpip install enum34をする必要があります)

apps/models.py
from django import models
from enum import Enum

class Idol(models.Model):
    class ATTRIBUTE(Enum):
        cute = ('cu', 'Cute')
        cool = ('co', 'Cool')
        passion = ('pa', 'Passion')

        @classmethod
        def get_value(cls, member):
            return cls[member].value[0]


    name = models.CharField(maxlength=255)
    attribute = models.CharField(
        max_length=2,
        choices=[x.value for x in ATTRIBUTE]
    )

オブジェクトの取得の仕方については、以下のようになります。

passion = Idol.ATTRIBUTE.get_value('passion')
pa_idols = Idol.objects.filter(passion)

Model Managerをカスタマイズする

DjangoのORMはModel ManagerというI/Fを使用していて、このI/Fを通してDBにアクセスしている、ということを最近知りました。
んで、このModel Manager自体をカスタマイズすることもできるとのこと。

例えば、models.pyに以下のように書く。

apps/models.py
from django.db import models
from django.utils import timezone

class PublishedManager(models.Manager):

    use_for_related_fields = True

    def published(self, **kwargs):
        return self.filter(pub_date__lte=timezone.now(), **kwargs)

class Sample(models.Model):
    review = models.CharField(max_length=255)
    pub_date = models.DateTimeField()

    objects = PublishedManager()

このようにしておくと、以下のようにして、pub_dataが現在時刻以前のオブジェクトのみを取得することができる。

Sample.objects.published()

いちいち、filter()やexclude()を使わなくてもよくなる。

68
60
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
68
60