in Computer Science @ UFSC - Principal Software Engineer @ Cheesecake Labs Passionate about coding, no matter the stack. Besides Python frameworks I have already worked with: - Delphi, PHP, Java, Node.js, Rust… - Angular, React, React native, Vue…
for any project; Easy to extend and remove - Pre-configured packages The best settings for Django and Django Rest framework; Error monitoring; OpenAPI… - Styleguide Comprehensive documentation offering detailed architectural insights, best practices, and conventions. What's the Django Starter
flow. Why should we implement this every project? - Architecture Variance Developers might kick-off projects with their own preferences. How about we we standardize it and avoid having to learn and maintain different structures? - Time to focus on business rules Some projects took up a month to be set and to get a minimal authentication flow. Maybe we should have basic apps that can be extended and focus on the clients' core requirements? What problems does the Django Starter solve?
core app and other apps. The main goal is to ensure that all apps, besides the core app, remain independent and decoupled. - The Core App Serves as the backbone of our project, contains essential components that are required across the entire application. - Other Apps Should only interact with core and themselves.
The core app is the appropriate place to store Django settings that are common to the entire project - Common Code Base classes, mixins, and utility functions, which can be utilized by other apps - Dependency Management Other apps within the project should ideally have imports only from the core app and themselves
its specific functionality and not rely on imports from other apps (aside from Core) - Code snippets that are used across multiple apps should ideally be extracted to the core app. However, it's acceptable to have some duplicated code
add a very specific property to a core model, utilize a Proxy Model. from core.models import User as CoreUser class AuthenticationUser (CoreUser): def my_app_specific_property (self): ... class Meta: proxy = True
in: ✅ - Use-cases - Services - Model properties & methods - Model clean method for additional validations In Django, business logic should not live in: ❌ - Views. - Serializers - Signals.
sets the created, modified, and id of uuid type fields and resides in core - Always call full_clean before saving an object def course_create(name: str, start_date: date, end_date: date) -> Course: course = Course(name=name, start_date=start_date, end_date=end_date) course.full_clean() course.save() return course
Django's constraints, then you should aim for that. - Model properties are great way to quickly access a derived value from a model's instance. - Model methods are also very powerful tool, that can build on top of properties.
View: Handles the incoming requests and returns the appropriate responses. - Use-case: The business logic of the API. - Doc: Documentation specified for DRF-Spectacular - Tests: Integration tests that ensure the correctness and reliability of APIs - Request and Response Serializers: Request and response serializers help in data validation and transformation.
data validation and transformation for our APIs. They provide a structured approach to validate incoming request data and serialize outgoing response data. - Request and Response Separation:: Each API should have a dedicated request serializer and a dedicated response serializer. - Unique Serializer Names: Avoid having two serializers with the same name, as this can impact the generation of OpenAPI documentation and lead to confusion.
password = serializers.CharField(trim_whitespace=False) class SignupResponseUserSerializer(serializers.ModelSerializer): class Meta: model = User fields = ("id", "email", "full_name") class SignupResponseSerializer(BaseResponseSerializer): data = inline_serializer( name="SignupResponseDataSerializer", fields={"user": SignupResponseUserSerializer()} )
and encapsulate specific functionalities within the software. - Inherits from BaseUseCase: All use-cases should inherit from BaseUseCase, which provides essential common functionality and ensures consistency across use-cases.