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で完結させたほうが、わかりやすい気がする。