Successfully reported this slideshow.
We use your LinkedIn profile and activity data to personalize ads and to show you more relevant ads. You can change your ad preferences anytime.

Fat query sets and Skinny Models

82 views

Published on

This presentation is a part of Sunscrapers' weekly talks. Michał presents and evaluates different approaches to organising business logic code in a Django Project.

  • Be the first to comment

  • Be the first to like this

Fat query sets and Skinny Models

  1. 1. sunscrapers.comYour favored tech partner. Thick QuerySets and Thin Models, or Where to Put Business Logic in Django Michał Nakoneczny 2017-05-19
  2. 2. sunscrapers.comYour favored tech partner. A layer which encodes the real-world business rules that determine how data can be created, displayed, stored, and changed. Business Logic Layer
  3. 3. sunscrapers.comYour favored tech partner. Idea 1: Fat Models
  4. 4. sunscrapers.comYour favored tech partner. A Company Blog class Post(Model): STATUS_DRAFT, STATUS_APPROVED, STATUS_PUBLISHED = range(3) STATUS_CHOICES = ( (STATUS_DRAFT, _('Draft')), (STATUS_APPROVED, _('Approved')), (STATUS_PUBLISHED, _('Published')) ) title = models.CharField(max_length=255) text = models.TextField() status = models.PositiveSmallIntegerField( choices=STATUS_CHOICES, default=STATUS_DRAFT )
  5. 5. sunscrapers.comYour favored tech partner. BL: Approving and Publishing class Post(Model): ... def approve(self): self.status = Post.STATUS_APPROVED self.save() def publish(self): if self.status != Post.STATUS_APPROVED: raise PostInvalidStatusError() self.status = Post.STATUS_APPROVED self.save()
  6. 6. sunscrapers.comYour favored tech partner. Pros: ● Testable; ● Readable; ● DRY? Cons: ● Unmaintanable in a large code base; ● Leads to unoptimised solutions. Idea 1: Fat Models
  7. 7. sunscrapers.comYour favored tech partner. Idea 2: Forms/Views/Serializers
  8. 8. sunscrapers.comYour favored tech partner.
  9. 9. sunscrapers.comYour favored tech partner. Idea 3: Services
  10. 10. sunscrapers.comYour favored tech partner. BL: Approving and Publishing def approve_post(post): post.status = Post.STATUS_APPROVED post.save() def publish_post(post): if post.status != Post.STATUS_APPROVED: raise PostInvalidStatusError() post.status = Post.STATUS_APPROVED post.save()
  11. 11. sunscrapers.comYour favored tech partner. Pros: ● Testable; ● Readable?; ● DRY Cons: ● Unstructured in a large code base; ● Can lead to unoptimised solutions. Idea 3: Services
  12. 12. sunscrapers.comYour favored tech partner. Idea 4: QuerySets/Managers
  13. 13. sunscrapers.comYour favored tech partner. BL: Approving and Publishing class PostQuerySet(QuerySet): def approve(self): return self.update(status=Post.STATUS_APPROVED) def publish(self): return self.filter(status=Post.STATUS_APPROVED).update( status=Post.STATUS_PUBLISHED) class Post(Model): ... objects = PostQuerySet.as_manager()
  14. 14. sunscrapers.comYour favored tech partner. Pros: ● Testable; ● Readable; ● DRY; ● Optimised (unless you do something stupid). Cons: ● Checking Business Logic rules is more complicated. ● Integrations get more difficult. Idea 4: QuerySets/Managers
  15. 15. sunscrapers.comYour favored tech partner. Business Logic Rules def publish(self): return self.filter(status=Post.STATUS_APPROVED).update( status=Post.STATUS_PUBLISHED) def publish(self): if self.exclude(status=Post.STATUS_APPROVED).exists(): raise PostInvalidStatusError() return self.update(status=Post.STATUS_PUBLISHED)
  16. 16. sunscrapers.comYour favored tech partner. Integrations def pay(self): Posts_data = … pay_service = PayService() try: pay_service.pay_batch(posts_data) return self.update (status=Post.STATUS_PAID) except …: ...
  17. 17. sunscrapers.comYour favored tech partner. Thanks! Questions?

×