Note: I am not a proper python programmer... but I use python extensively. I do things like write classes with inheritance, use iterators and comprehension, etc. My point is that I do not have a full grasp of the language, e.g. what exactly constitutes an python object, why __init__.py
is needed other than to specify a module, etc. In relation to Django, I have written multi-app sites (with the help of S.O.) and have really enjoyed Django's templating system, blocks, and how they can be nested. Now are my apps fully decoupled and reusable? That this is subject of this post.
I state this disclaimer because a lot of the Django resources seem to assume that one knows these things. This makes understanding some of the documentation and S.O. questions difficult for a person who is just an (subpower)-user. So please answer this question with that in mind.
These questions are inspired by both the question When to create a new app with startapp in django? by @håkan and the answer given by @antti rasinen which links to James Bennett's 2008 PyCon presentation
A few key points from Bennett's presentation are:
Which directs me to his section "Project coupling kills re-use" that mentions:
A "module" in this case is just an app made of other apps?
(Apps with related functionality and shared models )
What should I do when apps share models?
In Barrett's slides he implies that user registration and user profiles are distinct and should be distinct apps. (He certainly states that profiles have nothing to do with user registration).
So if I wanted both, would my project have two apps like:
even though the app user-profile
will need the user model from user-registration
? Or do I make a single app (module
):
which contains both?
(Apps with distinct functions but shared models)
Extending the example from question 1, lets say that my main app (or some other app that is used by the main app) utilizes some aspect of the user model (e.g. recently active members if it was a chat site).
Clearly my main app gets this information from the user model. Does my main app now get bundled under the user-app
module?
This may not be the best example, but the point is as follows:
I have two apps app-dependency
and app-needs-dependency
, where each app does its one thing and one thing well... It is just that app-needs-dependency
needs information from app-dependency
. What do I do in this case, if everything else about app-needs-dependency
is completely decoupled from app-dependency
(so it could be used in other projects)?
(writing apps for flexibility)
Now I have my site with its couple of apps. Each app does its one thing and does it well. The main app serves as the landing page/ overview in this case.
I want all my other apps to use / inherit the static and template files of the main app.
Where do I store all the static files and templates? In the main app and set that as the default for the other apps? Or where should these static files / templates (e.g. base.css
, base.html
) go?
Do I make a copy of these files for each other app, so they can be run even though this is redundant?
Which makes my app more flexible?
A "module" in the Python context is simply a file that contains definitions and statements. So "related modules under a package" really just means "split your code into separate files based on what the code is doing".
Describing it as "an app made of other apps" is to start confusing Django's concept of an app with Python's concept of a module (which, as stated above is just a file that houses some code).
What should I do when apps share models?
You should still try and stick to the "apps do one thing and do it well" maxim. In this case separate profile and registration apps seems like a good idea - because they have quite different functions. A registration app is going to contain the logic for allowing users to register on your site. A profile app is all about what information you will store about a user.
There is nothing wrong with these two apps having a relationship to each other - see below.
Let's say that my main app (or some other app that is used by the main app) utilizes some aspect of the user model (e.g. recently active members if it was a chat site). Clearly my main app gets this information from the user model. Does my main app now get bundled under the user-app?
No. It should still be a separate app, with links to the other app.
The user model is actually a good example. Django allows you to specify a custom user model that lets you store whatever additional data you want about a user.
Now, there are loads of third party apps out there that do things like registration, authentication, etc for users. They are designed to work with any user model, not just Django's default one. The way they do that is to use get_user_model()
wherever they need to reference the User
model, instead of directly importing django.contrib.auth.models.User
.
This means that you can use those third party apps with whatever user model you have defined for your own project.
Django's get_user_model()
utility is there to serve a very common use case. However the same principle can be extended to your own apps. If there is a dependency between your apps that you think should be swappable, then you can provide a way to swap it out - e.g., a setting/configuration that allows any other project using your app to specify an alternative.
There are hundreds of examples of this kind of configurability in the Django ecosystem. For example, Django itself ships with its own django.contrib.auth
authentication app. However if you want to implement your own authentication logic, you don't have to reimplement the entire auth app again yourself (that would be a huge pain). Instead you specify an an authentication backend that it's auth app will use to authenticate. The auth app is designed to allow any project to swap out a core piece of its functionality with minimal effort.
So in your main
app, you might define a setting that controls which profile
model to use. This means that if someone else wants to use a different profile model, they simply change this setting and they're all set. They are no longer tied to your profile
app.
For example - let's say you have a main
app that has a view that displays some user data, but also provides a link to a registration view that is provided by a different app. You want anyone else to be able to use that app regardless of what registration app they are using. So you can make this view resuable like so:
In main/views.py
:
from django.contrib.auth import get_user_model
from django.conf import settings
from django.urls import reverse
class UserDetailView(DetailView):
# First of all, we're using get_user_model so that a project
# can specify whatever user model it wants, and still use this
# view.
model = get_user_model()
def get_context_data(self, *args, *kwargs):
ctx = super().get_context_data(*args, **kwargs)
# We want to add a link to a registration view into this template context.
# But we want this to be configurable.
# Your REGISTRATION_URL would be something like 'profile:registration'
ctx['registration_link'] = reverse(settings.REGISTRATION_URL)
return ctx
The main app serves as the landing page/ overview in this case. I want all my other apps to use / inherit the static and template files of the main app. Where do I store all the static files and templates?
You should store the templates in each respective app. If your main app is providing the base templates, then those should reside in the main app.
If your profile app is then providing a registration view, then the template for that should live in the profile app. There is nothing wrong with it extending the base template from the main app - this can easily be overridden by a project that wants to.
It's fine to make assumptions about how two apps are related to each other - as long as you're careful to allow overriding of those assumptions.
I have to admit your question is not a technical one but rather a conceptual and dogmatic one. No answer is absolute and universally valid and every detail about how you project is structured and should behave can change the perspective. As you wrote, each Django app does one thing and it does it well.
I would extend that to the point that each app should contain no more than one Model
and at most, it's closets dependents.
Ex: the Product
with it's Category
, Color
, Image
"What Changes together, stay together"
You will have plenty of logic to cover inside that app with only these ones.
Try to look at Django framework as a tool to create your project..this is the final goal...but if you want also to create reusable apps try to create them as independent as possible, or at least dependent to some Django features:
ex: a reusable app and totally independent would be an app that only requires User
Model, Sessions
, Groups
included in Django. You get the idea of dependent
but still autonomous app.
An app
is part of a project after all...either here or in other part after you build it. Look at it as if it would be a simple function...can run alone or can depend on other functions result...at what point you keep everything inside one function and when you decide to split them in 2 separate ones.
So:
An app is the smallest piece that can run by it's own...having models, views, templates, urls, static files.
It can depend also on other apps...so answer is YES
Always keep things separate by functionality... User Auth is dealing with user creation and their authentication
User Profile is dealing with personal data of the User
Nothing gets bundled. Everything stays at the same level as 2 different but dependents apps
You can do as you wish.
You can do static as a central place and templates specific for each app or everything central. No right answer here but only what scales well for your project.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With