読者です 読者をやめる 読者になる 読者になる

Djangoroidの奮闘記

python,django,angularJS1~三十路過ぎたプログラマーの奮闘記

Angular4 + Django1.11 vol.6

参考サイト

https://www.codingforentrepreneurs.com/projects/angular-django/ http://www.django-rest-framework.org/api-guide/generic-views/#listapiview http://qiita.com/kura07/items/c9fa858870ad56dfec12

Better Backend Queries

  • featuredのqueryをmodelsでやるようにする。
from django.db import models
from django.db.models.signals import pre_save
# Create your models here.

from .utils import unique_slug_generator

class VideoQuerySet(models.query.QuerySet): # models.query.QuerySetを継承した、VideoQuerySet classを作成する
    def featured(self): # featuredメソッドを追加する。
        return self.filter(featured=True) # featuredメソッドは、querysetにfeatured=Trueのfilterをかけて、その結果を返す。

class VideoManager(models.Manager): #models.Managerを継承したVideoManagerClassを作成する。
    def get_queryset(self): # get_querysetで、VideoQuerySetのinstanceを返すようにセットする。
        return VideoQuerySet(self, using=self._db)

    def featured(self):
        return self.get_queryset().featured() # featuredメソッドは、VideoQuerySetのfeaturedメソッドの値を返すメソッド。

class Video(models.Model):
    name = models.CharField(max_length=220)
    slug = models.SlugField(unique=True, blank=True)
    embed = models.CharField(max_length=120, help_text='Youtube Embed Code', null=True, blank=True)
    featured = models.BooleanField(default=False)
    timestamp = models.DateTimeField(auto_now_add=True)

    objects = VideoManager() # objectsには、VideoManagerのinstanceを代入する。

    def __str__(self):
        return self.name

    def title(self):
        return self.name


def video_pre_save_receiver(sender, instance, *args, **kwargs):
    if not instance.slug:
        instance.slug = unique_slug_generator(instance)


pre_save.connect(video_pre_save_receiver, sender=Video)
  • views.pyを以下のように修正する。
class VideoFeatured(generics.ListAPIView):
    queryset                = Video.objects.all()
    serializer_class        = VideoSerializer
    permission_classes      = []
    authentication_classes  = []

    def get_queryset(self):
        query = self.request.GET.get("q")
        if query:
          qs = Video.objects.filter(name__icontains=query).featured()
        else:
          qs = Video.objects.featured()
        return qs
  • 次はsearchメソッドを追記する。まずは、models.pyにsearchメソッドを追加する。
from django.db.models import Q
...
class VideoQuerySet(models.query.QuerySet):
    def featured(self):
        return self.filter(featured=True)

    def search(self, query):
        return self.get_queryset().filter(
            Q(name__icontains=query) |
            Q(slug__icontains=query) |
            Q(embed__icontains=query)
        )


class VideoManager(models.Manager):
    def get_queryset(self):
        return VideoQuerySet(self.model, using=self._db)

    def featured(self):
        return self.get_queryset().featured()

    def search(self, query):
        return self.get_queryset().search(query)
  • views.pyに追記する。
class VideoList(generics.ListAPIView):
    queryset                = Video.objects.all()
    serializer_class        = VideoSerializer
    permission_classes      = []
    authentication_classes  = []

    def get_queryset(self):
        query = self.request.GET.get("q")
        if query:
        #   qs = Video.objects.filter(name__icontains=query)
          qs = Video.objects.search(query)
        else:
          qs = Video.objects.all()
        return qs

class VideoFeatured(generics.ListAPIView):
    queryset                = Video.objects.all()
    serializer_class        = VideoSerializer
    permission_classes      = []
    authentication_classes  = []

    def get_queryset(self):
        query = self.request.GET.get("q")
        if query:
          qs = Video.objects.featured().search(query)
        else:
          qs = Video.objects.featured()
        return qs
  • activeフィールドも追加して、最終的にmodels.pyは以下のようになった。
from django.db import models
from django.db.models import Q
from django.db.models.signals import pre_save
# Create your models here.

from .utils import unique_slug_generator

class VideoQuerySet(models.query.QuerySet):
    def active(self):
        return self.filter(active=True)

    def featured(self):
        return self.filter(featured=True)

    def search(self, query):
        return self.get_queryset().filter(
            Q(name__icontains=query) |
            Q(slug__icontains=query) |
            Q(embed__icontains=query)
        )


class VideoManager(models.Manager):
    def get_queryset(self):
        return VideoQuerySet(self, using=self._db)

    def all(self):
        return self.get_queryset().active()

    def featured(self):
        return self.get_queryset().featured().active()

    def search(self, query):
        return self.get_queryset().search(query).active()


class Video(models.Model):
    name            = models.CharField(max_length=220)
    slug            = models.SlugField(unique=True, blank=True)
    embed           = models.CharField(max_length=120, help_text='Youtube Embed Code', null=True, blank=True)
    active          = models.BooleanField(default=True)
    featured        = models.BooleanField(default=False)
    timestamp       = models.DateTimeField(auto_now_add=True)

    objects = VideoManager()

    def __str__(self):
        return self.name

    def title(self):
        return self.name


def video_pre_save_receiver(sender, instance, *args, **kwargs):
    if not instance.slug:
        instance.slug = unique_slug_generator(instance)


pre_save.connect(video_pre_save_receiver, sender=Video)
  • error 発生! _metaがmanagerにはないとのこと。どうもquerysetの箇所を以下のように修正する必要があるようだ。
class VideoManager(models.Manager):
    def get_queryset(self):
        return VideoQuerySet(self.model, using=self._db)

まとめ

  • VideoManager と、VideoQuerySetをsetで使うと、better queryを作成できる。こちらの方がrobustのようだ。確かに、queryは、modelで完結させたほうが、わかりやすい気がする。