Backend architecture for SaaS product in django - python

I'm writing the backend for a SaaS application in django. Need some guidance on the architecture.
So the product will have 2 offerings: a general one where all users will share the same database and a premium one with a dedicated database. How I'm planning to translate this to django is the following:
Within the django project, there'll be one app for the general offering.
For every premium client, there'll be a separate app.
Each app has the same models.
Every app communicates with a separate database. Achieved this using: stackoverflow post and django documentation
I'll write views for all the APIs in the project's views.py, not inside any app and decide on the basis of a token which app's models to communicate to.
The problems I see right now with this architecture:
In all of the views, I'll have to write a lot of conditional statements once the number of premium clients increases.
Onboarding of new premium clients requires quite a bit of code change.
Code duplication in models.py of all the different apps. But it's almost similar to writing statements for creating tables in a new database every time a premium client signs up. Comments?
Please advise me on the architecture as a whole. I went through a lot of articles and stack overflow posts before going this way, but none were completely specific to django so I'm not 100% confident. Much thanks in advance.

If the functionality of the free and premium offerings will be exactly the same you shouldn't need any code duplication. This is of course a big IF, because it's very conceivable that you'll add extra features to the premium offering.
If the functionality will be exactly the same then all you need to do is add any new premium databases to your settings.py and use a middleware to determine which database your models should communicate with (using the using attribute), and for the shared database add an owner column to every table that records who the owner of that row is so you can filter querysets appropriately.

Related

How does a django project use multiple databases with the same structure to read and write, distinguished by url

I have a django project and want to divide it into multiple databases with the same structure.
Use url to distinguish different databases. When the admin management page logs in, log in to different databases according to different urls.
For example: 127.0.0.1/admin uses the admin database, 127.0.0.1/admin2 uses the admin2 database.
Does django implement this function? What do I need to do, Can you give me some suggestions or ideas? thank you very much
TL;DR
As far as a single django project is considered, there is no default way to achieve multiple database.
Scenario 1
From your very limited explaination I will assume that you want to seperate data of one admin dashboard from the data of second admin dashboard, to achieve data isolation with respect to permissions & other models, this is called multitenancy.
Very briefly: In a Multitenant architecture you can have multiple tenants whose structure is defined by your models.py and you can control all this tenant via a main superadmin, these tenants can have their own admin dashboard where the data stored in them are only specific to their tenant users. In more simpler terms you can have a SaaS app with this method, where you can have multiple organizations and these organizations have their own users with their specific permissions/groups.
Multitenancy can be achieved in django via a Schema seperated database using POSTGRESql and this awesome package that has already done most of the heavy lifting for you. You can achieve seperate logins via url or subdomain. If your tenants have users who part of more than one organisation and you want a single login for all of them then you can use this package that goes along with django-tenants. It provides a public user table with permission modules separate for each tenant.
Scenario 2
From your very limited explaination I will assume that you still want seperate databases for your app, in such case you need to rethink your approach to the problem because it is not something you will fancy after deployment as there is not direct way provided by django. Instead you should look into micro-service architecture.

Is a django project only meant to be for a single website or can the different apps be different sites. What is perferable and advisable?

I have been using django for a while, but there is something im not quite clear on.
How big should a django app be. If for example a django app should only be user authentication or if it should be an entire website in one app.
If I have a project with several apps and each app is a whole website with a lot of code, is that the way it suppose to be or should all apps related to a single site within a project ?
Im thinking of creating one django project for each site, but im now wondering if I should be creating one project where each app is one site. Can anyone please comment on this, what it the preferred way to do it ?
In the django documentation one app is only used for a poll, so it seems to be that, according to the documentation, that each app should be some part of functionality on the site.
An app is a submodule of a project which contains functionality (views, models, urls etc) for a specific part of the larger site and is as decoupled from the other apps as possible. The project as a whole is the website and your apps make up the separate parts of functionality for your site.
If your sites are going to basically contain the same functionality, it might be worth looking into the Sites framework which django provides.
So taking the polls example further.
Lets say the website is a survey site. There would be the polls app, which would contain the relevant models and views for creating and recording poll results. Then you might need to view the data, so you could create an analysis app, which would store the views for displaying dashboards and contain functions for data processing. Then we could take things a bit further, and have users be able to log in and see their own results (and give us the chance to link users to poll results), so you would make an accounts app, which would hold views for logging in/out, maybe a profile page etc.
So each of these different parts of functionality would be separated out into distinct apps, which would make up the project (site) as a whole.
If the apps have been decoupled properly, you could reuse the different apps in other projects (e.g. the accounts app could be dropped into a new project do provide logging in/out functionality)
In my experience so far, an app should be a reusable entity. There many guiding principles for choosing what to go and what not in an app. Separating authentication is one example. A projcet is one big collection of may apps and a reusable app can be in many projects.
Nowadays, there is a trend to move to micro service architecture, which is next level of separation of functionality with each service doing best one thing.
Each project is a unit in itself, not an individual app. So you host the project, not the app. I recommend using different project for each site and using micro-service architecture. A lot depends on your existing codebase too.

Django: How to properly handle two websites at the same time with a shared database?

I've researched on how to handle multiple websites with Django but nothing seemed really convincing to me: here, here and here
Here is what I have now:
A single Django project running on a server, with two apps. One for the API (with django REST Framework) and an other app which basically consumes the API and display the datas (retrieved directly in the database). My database is Oracle and on a separate server for robustness reasons.
Here is what I would like to have:
Two websites, one would be the API (certain users use only the API) and the other one would be the website (for the other users).
I obviously need those two websites to share the same database (but this shouldn't be to hard to handle in the settings.py file), and I also need to use the same Models, Admin, etc...
How can I handle that with being as DRY as possible ? If I make two django project, I'll have to duplicate my models, my admin, and certain business classes and functions... Which could be a pain to maintain.
The alternative would be to play around with virtualhosts and url redirections to make it seamless.
What do you think is the best solution ? And can you provide an example of implementation ?
Thanks!
There are few options:
Create 2 projects and a django application. You create the django application for the common code, like the models. Then you create 2 projects and use that application in both of them.
Create 1 project with 3 applications 1 application for common code, 1 for API and 1 for app. The API and app application will use the common code application.
Create just 1 project with 1 application. You'll have to create different views for the API and for the app and map a different url for each one.
The options are sorted by overhead while the first option has the most overhead, but it's the most organized solution.
Which is best? it depends on the size of your project. The bigger - the more the overhead will pay off. If you don't know what is going to be the size of the project in the future, then I would start with the third option, and as the project grows, move towards the second and first options.

Django : Project consuming data from REST API, How to use external apps in this system?

I have a Django web front-end that consumes data from a REST API backend.
Even the users are made and created on the backend.
My Problem :
How to use 3rd party apps within this system, that heavily depend on django models/ORM ?
Is there something that can provide some bridge between the REST API resources and the ORM?
How can this problem be dealt with ?
Update
DRY principal seems to be failing in this situation.
Probably things have changed since this question has been originally posted. Now there are a couple of interesting related questions on StackOverflow about this topic.
To code yourself a solution as explained in this answer, you can create an external service layer (aka services.py) and write there the logic to access the external resources. Your views will consume this layer, and make the proper actions. There are other questions that provide help on how to pass information from the original request received by the django-view to the external service like this or this
There is also a django app that takes this situation into account as explained in this answer. django-roa uses the Resource Oriented Architecture paradigm to solve this.
I'm facing a similar obstacle with a new ecommerce project.
The project is a front end to a full-fledged store management software (CMS+ERP+CRM). It needs to use the master product database, but have its own entries for product reviews, ratings and so on.
The initial thought was to make a cached copy of the master database. The website will benefit from fast loading times for the cached items, but the implementation is not trivial.
After some considerations, the selected approach was updating the website's DB from the management program. This way the website's copy will always be correct, and most of the implementation doesn't need to worry about REST services (it'll still be used for user registration, shipment tracking etc.)
In your case, where you can't have the service update your own database remotely, you need to come up with a mechanism that allows you to refer to REST recourses like regular models, and that caches them in the background.
Important note: research for a way to make sure the cache is always correct (non-dirty)...
I'm not sure I completely understand your question or requirements. The way I am reading it, you have a primary back-end which is basically a black-box, and you want to use some 3rd-party apps in your project which use the Django ORM.
I am unclear as to why there would be a need for being able to have a two-way synchronization between the two data-stores. The users of your project would be returned data from your primary back-end, and from the project's ORM.
Since you are concerned about saving the "ORM" data in your primary back-end, maybe you would consider creating a Transaction Middleware that would fire any time ORM data gets updated, which could serialize the structure being saved and transmit it to your REST API. This REST API, I assume, is able to accept arbitrary data structures?
You'll probably at least want to use some form of middleware, and maybe a utility module/class to help form the "bridge".

Django multi-user saas

I'm creating a small saas for learning purposes... I know that the best way to go is to have a separate schema for each user... But my saas is a small app and I really don't need separate schemas plus it would complicate stuff (later alterations to the schema)... So I'm going to use the same schema for all users and just append each user's ID to the entry and then display only the user's entries upon login.
Is there a way I can "prepend" user's ID upon login through middleware? Or do I need to adjust all the queries (filter by user's ID)? I already store the user's ID to his entries... so I need this only for select's.
Thank you!
I don't know of any way to automatically filter querysets based on request.user. This is because the ORM is not coupled with django.contrib.auth.
I tried two SaaS designs:
1 database for all sites, and manual filtering on all querysets. Of course this made django.contrib.admin not possible out of the box. It might be possible to enable django.contrib.admin with a really tight setup of django-authority or maybe even other django per-object permission packages (google cached version because djangopackages.com is down ATM).
1 database per site, that's just easier, keeps the code cleaner, and enables django.contrib.admin out of the box, which can be really cool if you install a django admin theme. Also I enabled django.contrib.admindoc as well as django-dbtemplates.
(Apparently in your case, 1 site = 1 user, but the concept is the same)
I prefer the second implementation because it's obviously a lot less development work, which is compensated by a little system administration.

Categories