The has been a popular choice for web development with for many years. And for good reason: it leverages Python's ease of modularity to offer a very flexible solution for a variety of applications. Django Framework Python Django's core features include a model-view-controller architecture, an ORM, a templating system, caching, internationalization, and many other things you'd expect in a modern web framework. "Applications" distributed with the system add features for authentication, an administrative interface which automatically provides CRUD operations for data models, multi-site support, and mitigation from common security threats. Possibly Django's greatest strength is that just about all of its features can be extended or overridden. This means you'll rarely feel restricted when implementing a feature, making it an ideal choice for complex and ever-growing applications. Here are some tips for making the best use of Django in your next SaaS app. SaaS Keep Your "Apps" Organized Every system built on top of Django is written as one or more "applications", as the framework calls them. Each application is a bundle of models, views, templates, and any other custom code needed to run some aspect of the website. The built-in administrative system is one such application. There are plenty of others freely available online. Each is enabled in the settings file and their URL routes can be registered as part of your main configuration. When building a custom site it may seem natural to write everything into one such application. You'll quickly find your code growing as you add features. Just as it's a best practice to separate and organize your code by its responsibility, applications should be broken down in a similar way in Django. This allows each to stay focused on their primary task and also makes them much easier to and debug. unit test For example, let's say your site lets users manage subscriptions, has a section for authenticated users to view premium content, and public pages for marketing purposes. I would build each as a separate Django application. Since Django applications are Python modules, they can include functionality from each other as needed. The premium content app can leverage the model defined in the subscription app to check if a user should be allowed access. Use Django REST Framework for APIs The (DRF) is a highly flexible and customizable extension to Django for exposing APIs. With very little code it can expose CRUD operations directly against your data model. You can also write your own endpoints that leverage its other features, such as authentication and automatic documentation. Django REST framework I often write APIs that do not exactly match my data model and require customization. For me the biggest benefits of using Django REST framework over rolling my own solutions are the authentication, caching, and throttling options. The automatic documentation and extensions for things like are an added bonus. Swagger The small learning curve for DRF makes it well worth the investment for the value it adds. Throttle APIs Based on User Subscriptions A common business model of many SaaS applications today includes user subscriptions to APIs. Access to these APIs can be restricted to specific endpoints or rate limited based on subscription levels. Django REST framework supports both. When adding s to I decided to throttle requests at different levels depending on subscription tier. This is not natively built into the framework. Fortunately just about every aspect of the system can be overridden. API SocialSentiment.io I chose to extend the DRF class: UserRateThrottle rest_framework.throttling UserRateThrottle scope = super().__init__() request.user.is_authenticated: user_daily_limit = get_user_limit(request.user) user_limits: self.duration = self.num_requests = user_daily_limit : self.rate : self.key = self.get_cache_key(request, view) self.key : self.history = self.cache.get(self.key, []) self.now = self.timer() self.history self.history[ ] <= self.now - self.duration: self.history.pop() len(self.history) >= self.num_requests: self.throttle_failure() self.throttle_success() from import : class SubscriptionRateThrottle (UserRateThrottle) # Custom scope required by DRF "subscription" : def __init__ (self) : def allow_request (self, request, view) """ Override rest_framework.throttling.SimpleRateThrottle.allow_request """ if if # Override the default from settings.py 86400 else # No limit == unlimited plan return True # Original logic from the parent method... if is None return True if is None return True # Drop any requests from the history which have now passed the # throttle duration while and -1 if return return In this example a function will need to be written to retrieve a daily rate limit from the user's subscription. This class then needs to be added to the array within in . With just a few dozen lines of code we now have custom API rate throttling! get_user_limit DEFAULT_THROTTLE_CLASSES REST_FRAMEWORK settings.py Cache, Cache, Cache The key to a fast website is sending responses to the browser as fast as possible. Application level caching should be a component of this strategy. Django includes a caching interface which can be backed by just about anything. I recommend using via for a few reasons. Redis django-redis Redis has already proven itself as a fast, efficient, and convenient key-value store. As your SaaS system scales it will eventually need multiple servers / . By using a shared cache such as Redis across all instances you'll conserve resources. At launch you might even choose to warm the cache with certain information before the application starts to process requests. containers Redis has multiple options for . This means if you need to restart or move your system you do not need to lose all of your cached information. persistence Django's cache system offers built-in view level caching. Just about anything else, including data model instances, can be manually cached as well. Carefully leverage this wherever possible for huge performance gains. Settings for Each Environment Django loads its configuration from a file provided by your application. Secure information such as database passwords and keys can be stored here and should never be committed to your project's code repository. It's also very likely developer environments and test systems will need certain settings to differ from production deployments. settings.py There are two ways to handle this. Both are equally convenient and flexible. One solution is to use environment variables. being another Python file can simply inspect the mapping from the built-in module. With this method the settings file can still be committed to code and deployed as usual. This plays very nicely with deployments which often use environment variables for custom settings. settings.py environ os docker Another solution is to create a or similar file for common settings and a custom file which imports the base and overrides variables as needed. This may be more or less convenient depending on the details of your deployments to various environments. settings_base.py settings.py Settings to consider for SaaS applications include database parameters, user sessions, static file locations such as a CDN, and the cache configuration. Conclusion Python plus Django provides a robust and flexible solution for SaaS applications. They've proven their value and have a great community of support. I highly recommend trying it out for your next major project. I learned many of these lessons while building SocialSentiment.io, an application which performs social media sentiment analysis of stocks . Django has been a great choice and I'll share more lessons soon.