Hacker News new | ask | show | jobs
by cjohnson318 1288 days ago
I do a similar thing. Here's the style-guide I learned from: https://phalt.github.io/django-api-domains/styleguide/

Basically, you have an api class for each Django app, and you use this class for all external interactions. The api class calls the service class, and the service class deals with the Django ORM. I added a view class, which is my DjangoRestFramework layer; so when a request comes in, it's caught by my view class, and passed onto the api class. I have DRF serializers for outgoing data, and pydantic schemas for incoming data. I also have a selector class for read-only views of my data.

It's a lot of typing, but I know exactly where everything is when something goes wrong, or I need to add a small adjustment somewhere, also it's easy for new devs to learn and use. One downside is that an api change require you to touch a dozen files.

1 comments

Thanks a lot. The Django API Domains Styleguide looks great. Do you perhaps know some open source projects that follow this structure?
Not really, no. But it is pretty straightforward. My projects have: - apis.py - the "external" surface of the app - views.py - DRF layer on top of apis.py - services.py - the layer that writes to the Django ORM - selectors.py - provides "read-only" views or filters of data - serializers.py - serialized outputs, using DRF - schemas.py - pydantic classes that control incoming JSON types - models.py - Django model declaration - urls.py - url endpoints, pointing to views.py - core.py - maybe another file with more business logic, used by apis.py

I have had trouble using Django API Domains interfaces.py, so I left them out. The main point is, figure out the right balance of concise code and separation of concerns for your taste, and your stack. Good luck!

Thank you, that's very helpful. Do I understand correctly that the REST component uses 2 different data structures? schemas.py for the incoming JSON and serializers.py for the return data?
Yes, according to the way I did it. You could put DRF serializers and Pydantic schema into the same file and call that "serializers.py", or you could just use DRF for incoming form validation.

Similarly, you could collapse "selectors.py" into "services.py". I put read-only operations into "selectors.py" and write operations into "services.py", but you don't have to. I got that idea from this styleguide: https://github.com/HackSoftware/Django-Styleguide which is in the Appendix of the Django Domain API docs.