mardi 11 mai 2021

What are standard architectural patterns to centrally encapsulate chain of Django Model calls to avoid duplication & increase maintainability?

A good colleague of mine asked this question a while ago which I'm now publicizing and sharing my own answer for, not only for the sake of future reference, but also to learn from the answers of the community.


I would like to use some kind of a database layer in the app. Most of the applications use ORM and it is possible to build complex queries there. What if I don’t want to use a query builder and prefer encapsulating it in a function or in a class? For example instead of:

def get(category_id: int) -> HttpResponse:
    posts = list(
        Post.objects.filter(category_id=category_id)
            .filter(deleted_at__isnull=True)
            .filter(published_at__gte=yesterday)
    )
    return HttpResponse(posts)

I'd like to do something along the lines of:

def recent_posts_from_category(category_id: int) -> List[Post]:
    return list(
        Post.objects.filter(category_id=category_id)
            .filter(deleted_at__isnull=True)
            .filter(published_at__gte=yesterday)
    )

def get(category_id: int) -> HttpResponse:
    posts = recent_posts_from_category(category_id)
    return HttpResponse(posts)

How would you call this approach/pattern? Where would you put the code?

Creating a module or a namespace called database sounds too broad. I don’t want to put these functions into utils or helpers namespaces either cause they are clearly not utilities.

Does the term Repository fit here? I would not go that far as to encapsulate everything (reads and writes), using ValueModels instead of ORM models (ActiveRecord) with an abstract goal to be able to replace the ORM if needed, building custom units of work is also out of scope.

But I'm looking for some DRY helpers, you know, to avoid searching the whole repository in order to find all similar use-cases if I need to change the behavior slightly. To avoid duplicating the chain of ORM calls.

Aucun commentaire:

Enregistrer un commentaire