Django best practice: number of model classes per file / directory structure - django

Another best-practice question to those with experience: How many models do you put in one file?
I've seen many examples that stuff all model classes into a single "models.py" file, which really feels wrong to me. In previous projects using other stacks I've gone with one file per model class. How is it done properly in Django for non-trivial applications with, say, 20 model classes? What would the directory structure look like?

Many people, especially those coming from the Rails world, get hung up on the term "application" and start throwing absolutely everything into a single app. In Django, an application is a single-use module that does one thing and does it well. Each application should be describable in one or two short sentences. A "project" is a collection of applications unified by a settings file. Even for something as complicated as an online store , something I'm discovering now, having more than four or five models in a single application is a warning sign: It was better that the store application (which has the shopping cart) be dependent upon upon the product application than have both in the same app. The same was true of invoices and payments, and so on.
Take a look at Django in the Real World, Jacob Kaplan-Moss's presentation about how to write Django applications.
A Django application is encapsulation: it describes one simple object (or collection of objects) and its API. Having 20 models sounds like you don't have a clean API, and therefore a clear concept, of what this app does.
The answer you want is "it depends on what your application does." To that end, what the Hell does an application with 20 models do, anyway? Grab your copy of Refactoring and have fun.

Related

Should I use an internal API in a django project to communicate between apps?

I'm building/managing a django project, with multiple apps inside of it. One stores survey data, and another stores classifiers, that are used to add features to the survey data. For example, Is this survey answer sad? 0/1. This feature will get stored along with the survey data.
We're trying to decide how and where in the app to actually perform this featurization, and I'm being recommended a number of approaches that don't make ANY sense to me, but I'm also not very familiar with django, or more-than-hobby-scale web development, so I wanted to get another opinion.
The data app obviously needs access to the classifiers app, to be able to run the classifiers on the data, and then reinsert the featurized data, but how to get access to the classifiers has become contentious. The obvious approach, to me, is to just import them directly, a la
# from inside the Survey App
from ClassifierModels import Classifier
cls = Classifier.where(name='Sad').first() # or whatever, I'm used to flask
data = Survey.where(question='How do you feel?').first()
labels = cls(data.responses)
# etc.
However, one of my engineers is saying that this is bad practice, because apps should not import one another's models. And that instead, these two should only communicate via internal APIs, i.e. posting all the data to
http://our_website.com/classifiers/sad
and getting it back that way.
So, what feels to me like the most pressing question: Why in god's name would anybody do it this way? It seems to me like strictly more code (building and handling requests), strictly less intuitive code, that's more to build, harder to work with, and bafflingly indirect, like mailing a letter to your own house rather than talking to the person who lives there, with you.
But perhaps in easier to answer chunks,
1) Is there REALLY anything the matter with the first, direct, import-other-apps-models approach? (The only answers I've found say 'No!,' but again, this is being pushed by my dev, who does have more industrial experience, so I want to be certain.)
2) What is the actual benefit of doing it via internal API's? (I've asked of course, but only get what feel like theoretical answers, that don't address the concrete concerns, of more and more complicated code for no obvious benefit.)
3) How much do the size of our app, and team, factor into which decision is best? We have about 1.75 developers, and only, even if we're VERY ambitious, FOUR users. (This app is being used internally, to support a consulting business.) So to me, any questions of Best Practices etc. have to factor in that we have tiny teams on both sides, and need something stable, functional, and lean, not something that handles big loads, or is externally secure, or fast, or easily worked on by big teams, etc.
4) What IS the best approach, if NEITHER of these is right?
It's simply not true that apps should not import other apps' models. For a trivial refutation, think about the apps in django.contrib which contain models such as User and ContentType, which are meant to be imported and used by other apps.
That's not to say there aren't good use cases for an internal API. I'm in the planning process of building one myself. But they're really only appropriate if you intend to split the apps up some day into separate services. An internal API on its own doesn't make much sense if you're not in a service-based architecture.
I cant see any reason why you should not import an app model from another one. Django itself uses several applications and theirs models internally (like auth and admin). Reading the applications section of documentation we can see that the framework has all the tools to manage multiple applications and their models inside a project.
However it seems quite obvious to me that it would make your code really messy and low-performance to send requests to your applications API.
Without context it's hard to understand why your engineer considers this a bad practice. He was maybe referring to database isolation (thus, see "Working multiple databases" in documentation) or proper code isolation for testing.
It is right to think about decoupling your apps. But I do not think that internal REST API is a good way.
Neither direct import of models, calling queries and updates in another app is a good approach. Every time you use model from another app, you should be careful. I suggest you to try to separate communication between apps to the simple service layer. Than you Survey app do not have to know models structure of Classifier app::
# from inside the Survey App
from ClassifierModels.services import get_classifier_cls
cls = get_classifier_cls('Sad')
data = Survey.where(question='How do you feel?').first()
labels = cls(data.responses)
# etc.
For more information, you should read this thread Separation of business logic and data access in django
In more general, you should create smaller testable components. Nowadays I am interested in "functional core and imperative shell" paradigm. Try Gary Bernhardt lectures https://gist.github.com/kbilsted/abdc017858cad68c3e7926b03646554e

Django - How to Modularize a large web Application?

I'm trying to figure out the best way to build a large web application, but keeping the various logical sections modularized. For example, there will be a number of different logical sections:
Estimates
Work Orders
Accounting
Contacts
etc...
As much as possible, I want to have the code for each of these modules disconnected from all the other modules. If code from one section starts to throw errors or cause incorrect data, I don't want that to affect other modules.
My first thought is just to separate by using Django 'apps'. Each module is its own app. Then, if I build each app to be "pluggable", then the code is self sufficient. However, the problem with this approach is that the modules will likely need to access the models of other modules. For example, the 'Accounting' module will need access to the 'Contacts' model, since we want to send invoices to people in our contacts list.
I looked into having a completely separate Django project for each module, but that poses problems (I think) for user authentication. Plus, to my knowledge, multiple Django projects can't (easily) share one database.
Just wondering if there are any good ways or best practices to make logically separate 'modules' while, as much as possible, keeping the code from one module completely isolated from the rest, but still having a cohesive web application.

How independent should Django apps be from one another?

I'm having trouble determining how I should split up the functions of my project into different apps.
Simple example: We have members, and members can have one more more services. Services can be upgraded, downgraded, other services added on, and can also be cancelled. (This is extremely simplfied, were it that simple in reality I'd use a pre-made solution)
My first thought was to make this into a 'member' application, and then a 'services' app that takes care of renewals, up/downgrades and cancellations.
I then thought I should probably make a renewal app, an up/downgrade app, and a cancellation app. But, these apps would all depend on the same table(s) in the DB (members and services). I thought applications were supposed to be independent from one another. Is it ok to make applications that are heavily dependent on other apps models?
Along the same lines, which application should I use to store the models to create the services table if so many apps use it?
I think you first thought was right: you don't get so many benefits of splitting everythin into multiple apps, and on the contrary it could become messy and hard to mantain.
The Django way of doing things depends a lot of the models. Each object is mapped to an entity on the data model. Your apps are mostly organised in relation to such data model. So, if you have an entity (service) that has different pieces, it is better to understand such pieces as parts of the same thing. The other entity (member) should be another one since it is a different thing.
There is no penalty of importing models from different apps. The most important thing is anyway building data model to be consistent.
The point of apps is to allow code which is intended to be reused as an addon by third parties. You probably won't want to split your projects up much, if at all into apps.

better architecture in django is different apps. or single App for different components?

I have intended to have an app. where I want to have different things having relations with each other and want to know that whether I should have them as just different models or as differnt apps. Obviously if this is student, teacher in LMS then they are necessary component of LMS while if this is Job, Professional and Company then there can be different things associated with a job , a professional can have his full profile with different features, company can have different directory listing e.t.c. like features.
So Company and professionals who are users also should be as diff. apps. and job as different app.? Will this way be fine? as Jobs app. don't always everywhere need to have professional data or employer all data other than just name. So it seems like it is more convenient to have them as diff. apps, so that it can be used somewhere else.So is that right way?
Or
As I also want this project to be flexible so will the above make it more complex? And should I just treat them as diff. models instead of diff. apps. as Company and Professional are users , for which django gives Profile features also. So is this right way?
Which way is better one?
thanks in advance.
There is no exact answer here, so it's my opinion.
It is always good to have several apps rather than one big app. Reasons:
apps becomes smaller and it's easier to maintain small pieces of code;
project structure becomes more clear, I just need to look at the file manager to see main parts of the project;
interaction between apps become explicit: easy to test and prevent unnecessary coupling.
Not every Django app should be pluggable. It's ok to have two apps that depend on each other (if you aren't going to distribute them seperately). It's like having two dependent functions: nothing is wrong with it.

How to decide how to split up your Django project into apps

I have a project that I wrote in PHP/symfony that uses 45 tables. I'm in the process of porting it to Python/Django.
There's a belief I've held for years that you should split up your projects into a bunch of small files rather than a few huge files. From what I understand, that's not an odd thing to believe. In Rails and symfony, there's a one-model-per-file convention. In Django, however, it seems that most developers put all of each app's models in one file.
This makes sense to me if your apps are each small enough. It doesn't make sense to me for large apps, though, and what I have is at least one large app.
Out of the 45 tables my project uses, 35 are closely related. I have a script that imports data from CSV files. For each line in each CSV file, I save 50-80 pieces of data into 30-35 different tables in one fell swoop.
Maybe I'm just thinking about this the wrong way but it would seem incredibly odd to me to divide my project into 6 or 7 different apps when almost all my tables are inextricably linked. When I touch one table, I touch all 35 tables. The delineations would have to be arbitrary. What would be the point of that?
Please forgive me if I come off as biased because I certainly am biased. I'm not having this problem in symfony and I wouldn't be having it in Rails. (I chose Django because of GeoDjango and Python's GIS capabilities.)
In a perfect world, I would have one model per file.
If I try to have one model per file, I get circular reference problems.
I could avoid the circular reference problems by putting all my models in one file but that feels wrong to me.
I could avoid putting all my models in the same file by splitting them into separate apps, but in order to end up with sufficiently small apps, I'd have to break up my project in arbitrary (and therefore pointless) ways.
What should I do?
If having one model per file would be the perfect answer for you, there's an app for that.
I've never done it on a scale of 80 model files but I can certainly point you towards another stack question:
About 20 models in 1 django app
http://djangosnippets.org/snippets/1838/
What kind of circular reference problems are you having by the way? If it's with ForeignKey definitions, here's a way around that...
http://docs.djangoproject.com/en/dev/ref/models/fields/#django.db.models.ForeignKey
You can also look into django.db.loading.get_model, but some may frown on this.