Upgrade to Pro
— share decks privately, control downloads, hide ads and more …
Speaker Deck
Sign up for free
Menu
Search
Features
All features
Private URLs
Password Protection
Custom URLS
Scheduled publishing
Remove Branding
Restrict embedding
Deck Collections
Notes
Features
All features
Private URLs
Password Protection
Custom URLS
Scheduled publishing
Remove Branding
Restrict embedding
Deck Collections
Notes
Explore
Featured decks
Featured speakers
Programming
Technology
Storyboards
Explore
Featured decks
Featured speakers
Programming
Technology
Storyboards
Pricing
Search
Sign in
Sign up for free
Developing custom QuerySet methods
Search
Gennady Chibisov
November 20, 2012
Programming
150
0
Share
Embed
Copy iframe code
Copy JS code
Copy link
Start on current slide
Developing custom QuerySet methods
https://github.com/chibisov/events-site-example
Gennady Chibisov
November 20, 2012
Other Decks in Programming
See All in Programming
Jetpack Compose Mechanisms
skydoves
3
820
Web Framework Benchmark Battle 2026, Any%
a_matsuda
2
2.1k
AIで開発が速くなった先で、開発チームは何を目指すか
shihochan
0
1.2k
月間100万人のサービス刷新で、 技術選定をHonoに振り切った話
yutobara
8
6.6k
コードで差別化できない時代の ソフトウェアエンジニアリング / Software Engineering in an Era Where Code Doesn’t Differentiate
kishida
2
180
個人開発者よ、Honoを使え(おじさんver)
tanahiro2010
2
260
Rでドレミ/Do-Re-Mi_with_R
florets1
0
130
Compiling a real-world CLI tool to native with Static Hermes
tmikov2023
0
120
The Rails Doctrine Decade
koic
2
590
外から家のPCの電源入れたい!をPHPで解決する
kawashimo0
1
130
Workers Cache を知る
syumai
0
360
[2026-09-26]空論ジェネリックプロセス~テスト資産とAIで紡ぐ、再現可能なパフォーマンスチューニングの話~
tosite
0
270
Featured
See All Featured
Jess Joyce - The Pitfalls of Following Frameworks
techseoconnect
PRO
1
450
Marketing Yourself as an Engineer | Alaka | Gurzu
gurzu
0
330
Redefining SEO in the New Era of Traffic Generation
szymonslowik
1
480
Claude Code どこまでも/ Claude Code Everywhere
nwiizo
68
59k
Winning Ecommerce Organic Search in an AI Era - #searchnstuff2025
aleyda
2
2.2k
ピンチをチャンスに:未来をつくるプロダクトロードマップ #pmconf2020
aki_iinuma
128
56k
From π to Pie charts
rasagy
1
400
The Organizational Zoo: Understanding Human Behavior Agility Through Metaphoric Constructive Conversations (based on the works of Arthur Shelley, Ph.D)
kimpetersen
PRO
0
500
The innovator’s Mindset - Leading Through an Era of Exponential Change - McGill University 2025
jdejongh
PRO
1
380
Tell your own story through comics
letsgokoyo
1
1.1k
Google's AI Overviews - The New Search
badams
0
1.6k
Design in an AI World
tapps
1
350
Transcript
Developing custom QuerySet methods Chibisov Gennady
https://github.com/chibisov/events-site-example !
Model methods 1. Instance methods 2. Class methods 3. QuerySet
methods 4. Manager methods
Instance methods class Event(models.Model): ! name = models.CharField(max_length=255)! slug
= models.SlugField(unique=True)! date_start = models.DateTimeField()! ! def __unicode__(self):! return self.name ! ! @property! def is_published(self):! # uses current instance data! return (self.date_start <=! datetime.datetime.now())! ! ! >>> yac2012 = Event.objects.get(slug='yac2012')! >>> yac2012.__unicode__()! 'Yet another Conference 2012'! >>> yac2012.is_published! True!
Class methods class Event(models.Model): ! name = models.CharField(max_length=255)! slug
= models.SlugField(unique=True)! date_start = models.DateTimeField()! ! @classmethod! def get_fields_for_csv(cls):! return ['name', 'slug']! ! ! >>> Event.get_fields_for_csv()! ['name', 'slug']!
QuerySet methods Event.objects.filter(id__lte=10).delete()!
QuerySet methods Event.objects.all().get_or_create(…)! Event.objects.all().create(…)! Event.objects.all().bulk_create(…)
Manager methods class RegionManager(models.Manager):! def sync_with_geobase(self):! for region in
regions_from_geobase():! try:! region_instance = self.model.objects.get(geobase_id=region.id)! # can modify any instance! region_instance.name_ru = region.name! region_instance.name_en = region.ename! region_instance.save()! except self.model.DoesNotExist:! # can create new instances! region_instance = self.model.objects.create(! geobase_id=region, ! name_ru=region.name, ! name_en=region.ename! )! # can remove instance! if region.is_deprecated:! region_instance.delete()! ! ! >>> Region.objects.sync_with_geobase()!
Manager methods # app/management/commands/sync_with_geobase.py! class Command(BaseCommand):! help = u"""Syncs
regions with geobase"""! ! def handle(self, *args, **options):! Region.objects.sync_with_geobase()! ! ! $ ./manage.py sync_with_geobase! !
This talk 1. Instance methods 2. Class methods 3. QuerySet
methods 4. Manager methods
What for?
What for? 1. Readability
Readability L events = Events.objects.all()! # filter for current
site type! if settings.IS_INTERNAL_SITE:! events = events.filter(! Q(is_published_external=True) | ! Q(is_published_internal=True)! )! else:! events = events.filter(! is_published_for_external=True! )!
Readability J events = Events.objects.filter_for_current_site_type()!
Readability L yac2012 = Events.objects.get(slug='yac2012')! ! # is for
current site type?! if settings.IS_INTERNAL_SITE:! is_for = (yac2012.is_published_for_internal ! and yac2012.is_published_for_external)! else:! is_for = yac2012.is_published_for_external!
Readability J yac2012.is_for_current_site_type!
What for? 1. Readability 2. Reusability
Reusability J class EventDetailView(DetailView): ! queryset = (Event.objects! .filter_for_current_site_type())!
! ! class EventListView(ListView):! queryset = (Event.objects! .filter_for_current_site_type())!
First manager # apps/events/managers.py ! from datetime.datetime import now!
from django.db.models.query import QuerySet! from django.db import models! ! ! class EventQuerySet(QuerySet):! def filter_by_published(self):! return self.filter(date_start__lte=now())! ! ! class EventManager(models.Manager):! def get_query_set(self):! return EventQuerySet(self.model, ! using=self._db)!
First manager # apps/events/models.py! from django.db import models! from
apps.events.managers import EventManager! ! ! class Event(models.Model):! name = models.CharField(max_length=255)! slug = models.SlugField(unique=True)! date_start = models.DateTimeField()! ! objects = EventManager()!
First manager >>> Event.objects.all().filter_by_published()! ! [<Event: Yet another Conference
2012>, ! <Event: iSubbotnik in Moscow 2012>]!
Oops… >>> Event.objects.filter_by_published()! ! Traceback (most recent call last):!
File "<console>", line 1, in <module>! AttributeError: 'EventManager' object has no attribute 'filter_by_published'!
Add proxy method class EventManager(models.Manager):! def get_query_set(self):! return EventQuerySet(self.model,
! using=self._db)! ! def filter_by_published(self):! return (self.get_query_set()! .filter_by_published())!
Or try to proxy all not found class EventManager(models.Manager):!
def get_query_set(self):! return EventQuerySet(self.model, ! using=self._db)! ! def __getattr__(self, name):! if name.startswith('_'):! raise AttributeError(name)! else:! return getattr(self.get_query_set(), ! name)!
OK >>> Event.objects.filter_by_published()! ! [<Event: Yet another Conference 2012>,
! <Event: iSubbotnik in Moscow 2012>]!
More docs.djangoproject.com/en/dev/topics/db/managers/!
apps.events.models class EventType(models.Model):! """! Example: Yet Another Conference! """!
name = models.CharField(max_length=255)! slug = models.SlugField(unique=True)! is_moderated = models.BooleanField(default=False)!
/events/ • Yet another Conference • I.Subbotnik
• ECIR
apps.events.models class Event(models.Model):! """! Example: Yac 2012! """! name
= models.CharField(max_length=255)! slug = models.SlugField(unique=True)! type = models.ForeignKey(EventType)! date_start = models.DateTimeField()!
/events/yac/ • Yac 2010 • Yac 2011
• Yac 2012
/events/yac/2012/
/events/ class EventTypeListView(ListView):! queryset = EventType.objects.all()!
/events/ • Yet another Conference • I.Subbotnik
• ECIR (not moderated)
EventType QuerySet method class EventTypeQuerySet(QuerySet):! def filter_by_published(self):! return self.filter(is_moderated=True)!
!
/events/ class EventTypeListView(ListView):! queryset = (EventType.objects! .filter_by_published())!
/events/ • Yet another Conference • I.Subbotnik
/events/yac/ • Yac 2010 • Yac 2011
• Yac 2012 (too early)
Event QuerySet method import datetime! from datetime.datetime import now!
! class EventQuerySet(QuerySet):! def filter_by_it_time_to_publish(self):! d = now() + datetime.timedelta(days=2)! return self.filter(date_start__lte=d)!
/events/yac/ class EventTypeDetailView(DetailView):! queryset = (EventType.objects! .filter_by_published())!
/events/yac/ # /templates/events/eventtype_detail.html! ! {% for e in object.event_set!
.filter_by_it_time_to_publish %}! <p>{{ e }}</p>! {% endfor %}!
/events/yac/ • Yac 2010 • Yac 2011
/events/yac/2012/
/events/yac/2012/ Show if
/events/yac/2012/ Show if • It is Tme to
publish
/events/yac/2012/ Show if • It is Tme to
publish • Yac EventType is published
/events/yac/2012/ else 404
/events/yac/2012/ class EventDetailView(DetailView):! queryset = (Event.objects! .filter_by_it_time_to_publish())! !
/events/yac/2012/ class EventDetailView(DetailView):! queryset = (Event.objects! .filter_by_it_time_to_publish())! ! def
get_queryset(self):! q = super(EventDetailView, ! self).get_queryset()! return q.filter(type__is_moderated=True)!
L EventType.objects.filter_by_published() not reused
/events/yac/2012/ class EventDetailView(DetailView):! queryset = (Event.objects! .filter_by_it_time_to_publish())! ! def
get_queryset(self):! q = super(EventDetailView, ! self).get_queryset()!
/events/yac/2012/ class EventDetailView(DetailView):! queryset = (Event.objects! .filter_by_it_time_to_publish())! ! def
get_queryset(self):! q = super(EventDetailView, ! self).get_queryset()! pks = (EventType.objects! .filter_by_published()! .values_list('pk', flat=True))!
/events/yac/2012/ class EventDetailView(DetailView):! queryset = (Event.objects! .filter_by_it_time_to_publish())! ! def
get_queryset(self):! q = super(EventDetailView, ! self).get_queryset()! pks = (EventType.objects! .filter_by_published()! .values_list('pk', flat=True))! return q.filter(type__pk__in=pks)!
L 2 DB queries Ugly
/events/yac/2012/ class EventDetailView(DetailView):! queryset = (Event.objects! .filter_by_published())!
Pre\y 1 query Reuse filter_by_published
HOW?
Q object
class EventTypeQuerySet(QuerySet):! def filter_by_published(self):! return self.filter(Q(is_moderated=True))! ! ! class EventQuerySet(QuerySet):!
...! def filter_by_with_published_type(self):! return self.filter(Q(type__is_moderated=True))!
class EventTypeQuerySet(QuerySet):! def filter_by_published(self):! return self.filter(Q(is_moderated=True))! ! ! class EventQuerySet(QuerySet):!
...! def filter_by_with_published_type(self):! return self.filter(Q(type__is_moderated=True))! Diff
class EventTypeConditions(object):! @classmethod! def is_published(cls):! return Q(is_moderated=True)! Move Q to
funcTon
class EventTypeConditions(object):! @classmethod! def is_published(cls, prefix=None): ! return Q(is_moderated=True)! Prefix
as param
class EventTypeConditions(object):! @classmethod! def is_published(cls, prefix=None):! if prefix:! field =
'%s__is_moderated' % prefix! else:! field = 'is_moderated'! ! return Q(is_moderated=True)! Field name with prefix
class EventTypeConditions(object):! @classmethod! def is_published(cls, prefix=None):! if prefix:! field =
'%s__is_moderated' % prefix! else:! field = 'is_moderated'! ! return Q(**{field: True})! Use prefixed field
>>> EventTypeConditions.is_published()!
>>> EventTypeConditions.is_published()! Q(is_moderated=True)!
>>> EventTypeConditions.is_published()! Q(is_moderated=True)! ! >>> EventTypeConditions.is_published(! ... prefix='type'! ... )!
>>> EventTypeConditions.is_published()! Q(is_moderated=True)! ! >>> EventTypeConditions.is_published(! ... prefix='type'! ... )!
Q(type__is_moderated=True)!
class EventTypeQuerySet(QuerySet):! def filter_by_published(self):! return self.filter(! EventTypeConditions.is_published()! )! Use it
for EventType
May I? class EventQuerySet(QuerySet):! ...! def filter_by_with_published_type(self):! return self.filter(!
EventTypeConditions.is_published(! prefix='type’! )! )!
NO
NO EventTypeCondiTons is for EventType
NO EventTypeCondiTons is for EventType Create
EventCondiTons for Event
class EventConditions(object):! @classmethod! def is_with_published_type(cls):! event_prefix = 'type' ! return
EventTypeConditions.is_published(! prefix=event_prefix! ) ! Create Event condiTons
class EventConditions(object):! @classmethod! def is_with_published_type(cls, prefix=None): ! event_prefix = 'type'
! return EventTypeConditions.is_published(! prefix=event_prefix! )! Prefix as param
class EventConditions(object):! @classmethod! def is_with_published_type(cls, prefix=None):! event_prefix = 'type' !
if prefix:! prefix = '%s__%s' % prefix, event_prefix! else:! prefix = event_prefix! ! return EventTypeConditions.is_published(! prefix=event_prefix! )! Add prefix
class EventConditions(object):! @classmethod! def is_with_published_type(cls, prefix=None): event_prefix = 'type'! if
prefix:! prefix = '%s__%s' % prefix, event_prefix! else:! prefix = event_prefix! ! return EventTypeConditions.is_published(! prefix=prefix! )! Use prefix
>>> EventConditions.is_with_published_type()!
>>> EventConditions.is_with_published_type()! Q(type__is_moderated=True)! !
>>> EventConditions.is_with_published_type()! Q(type__is_moderated=True)! ! >>> EventConditions.is_with_published_type(! ... prefix=’event’! ... )!
>>> EventConditions.is_with_published_type()! Q(type__is_moderated=True)! ! >>> EventConditions.is_with_published_type(! ... prefix=’event’! ... )!
Q(event__type__is_moderated=True)!
Use it for Event class EventQuerySet(QuerySet):! ...! def filter_by_with_published_type(self):!
return self.filter(! EventConditions.is_with_published_type()! )!
Lets refactor class EventQuerySet(QuerySet):! ...! def filter_by_it_time_to_publish(self):! d =
now() + datetime.timedelta(days=2)! return self.filter(date_start__lte=d)!
class EventConditions(object):! @classmethod! def is_with_published_type(cls, prefix=None):! ...! ! @classmethod! def
is_it_time_to_publish(cls, prefix=None): ! if prefix:! field = '%s__date_start__lte' % prefix! else:! field = 'date_start__lte'! ! d = now() + datetime.timedelta(days=2) ! return Q(**{field: d})!
Aaer refactor class EventQuerySet(QuerySet):! ...! def filter_by_it_time_to_publish(self):! return self.filter(!
EventConditions.is_it_time_to_publish()! )!
Combining methods
class EventConditions(object):! @classmethod! def is_with_published_type(cls, prefix=None):! ...! ! @classmethod! def
is_it_time_to_publish(cls, prefix=None): ! ...!
class EventConditions(object):! @classmethod! def is_with_published_type(cls, prefix=None):! ...! ! @classmethod! def
is_it_time_to_publish(cls, prefix=None): ! ...! ! @classmethod! def is_published(cls, prefix=None):! return (! cls.is_with_published_type(prefix) & ! cls.is_it_time_to_publish(prefix)! )! !
>>> EventConditions.is_published()! !
>>> EventConditions.is_published()! Q(date_start__lte=datetime(23,11,2012)) &! Q(type__is_moderated=True)! !
>>> EventConditions.is_published()! Q(date_start__lte=datetime(23,11,2012)) &! Q(type__is_moderated=True)! ! >>> EventConditions.is_published(! ... prefix=’event’!
... )!
>>> EventConditions.is_published()! Q(date_start__lte=datetime(23,11,2012)) &! Q(type__is_moderated=True)! ! >>> EventConditions.is_published(! ... prefix=’event’!
... )! Q(event__date_start__lte=datetime(23,11,2012))&! Q(event__type__is_moderated=True)!
Model instance methods
How to reuse condiTons?
How to reuse condiTons? class Event(models.Model):
... @property def is_with_published_type(self): return EventConditions.is_with_published_type(model_instance=self) @property def is_it_time_to_publish(self): return EventConditions.is_it_time_to_publish(model_instance=self) @property def is_published(self): return EventConditions.is_published(model_instance=self)!
True and False = True & False
How to reuse condiTons?
True or False = True | False
How to reuse condiTons?
More https://github.com/chibisov/events-site-example ! /apps/accounts/models.py /apps/accounts/managers.py /apps/events/models.py
/apps/events/managers.py
How to test
Use makers • make_published • make_not_published
Use makers class TestEventIsPublished(TestConditionBase):! def test_1(self):! makers.event.make_with_published_type(self.instance)! makers.event.make_it_time_to_publish(self.instance)! !
self.assertConditionTrue(msg=msg)! ! def test_2(self):! makers.event.make_with_published_type(self.instance)! makers.event.make_not_it_time_to_publish(self.instance)! ! self.assertConditionFalse(msg=msg)! ! def test_3(self):! makers.event.make_it_time_to_publish(self.instance)! makers.event.make_not_with_published_type(self.instance)! ! self.assertConditionFalse(msg=msg)!
More https://github.com/chibisov/events-site-example ! /apps/accounts/makers/ /apps/accounts/tests/condiTons/ /apps/events/makers/
/apps/events/tests/condiTons/
class DistributionSendedConditions(object):! @classmethod! def is_ready_to_start_with_in_progress_status(cls, prefix=None):! k = {! 'prefix':
prefix! }! ! return (! (cls.is_with_status(status='in_progress', **k)) &! ((cls.is_last_message_sended_more_than_5_minutes_ago(**k)) |! (cls.is_not_has_messages(**k) & ! cls.is_started_sending_more_than_5_minutes_ago(**k)))! )! More complex condiTons
Спасибо