Issue #1
I'm looking for the best practice in order to declare the additional data in a Django project. Imagine I need to store a huge list of choices to use in app1/models.py (I have seen a lot of best practices keep declaring those choices in the body of the models). In another scenario, Imagine I need to keep tens of config data in order to use them in my views.py. Is it common to declare them in the function/class?
In my opinion, there would be two common methods in order to do that. (Not sure even recommended at all)
Method #1
I can actually keep them all in my settings.py file and access them with importing (like from django.conf import settings).
settings.py:
...
NBA_TEAMS = (
("red", "Bulls"),
("yellow", "Lakers"),
...
)
Method #2
Keep them all in a file named data.py right next to the settings.py, and try importing it at the end of the settings file like this.
settings.py
...
try:
from .data import NBA_TEAMS, ..
except:
pass
Issue #2
Is there any best practice for creating modules in a Django project? Imagine I need to create a data validator function that receives string data from a form submission in views.py. Where should I keep those kinds of functions/validators/generators?
views.py
from --- import validateUsername
def submission(request):
...
form = ContactForm(request.POST)
if validateUsername(form.cleaned_data['username']):
...
Is there any best practice for these issues? Thank you.
As per my suggestions for both your issues you should create one constants.py and one utils.py file.
Now depends on your use case if you want to use the same constants in multiple apps within your project then define it at the root next to manage.py or if the constants are specific to app then create it under the specific app folder next to views.py file.
Same for utils.py you should define all the utility functions / methods in one utils.py file and use it in all the apps within your project.
Related
In Django you name your files like models.py, views.py, urls.py and so on. I wonder, if this naming convention is mandatory for Django. Will Django's functionality break if you place your models in a file called foo.py? I mean, only the import-line should change, right? Or is there any magic with this named files done by the framework?
Of course, I won't give my files shitty names; but I am just curious.
views, urls can be configured.
url: You can defined your one urls by setting <project>.settings.ROOT_URLCONF, and include your apps' urls.
views: Import your views or use view names as you want.
But for models, there's assumption about the model module name in the django code and other third-party apps. (https://github.com/django/django/blob/stable/1.7.x/django/apps/config.py#L9)
The best is to create modules instead for a couple of reasons:
you'll keep it consistent with Django conventions making it easier for others to work on it
you can give more descriptive appropriate names to your files
you will avoid really long files
So you'd have:
- my_application
- urls
- sub_set_urls_1.py
- etc.
- models
__init__.py <= import your models in here
sub_set_models_1.py
etc.
- views
sub_set_views_1.py
etc.
It's a bit more involved for the models, you need to import the models in __init__.py. Another way is to have a models.py file and put your models somewhere else: Split models.py into several files
I want to store some system constants which do not change so frequently.
I have made an settings table in my database using django models to store them but this table will have only single entry and I change these settings with django admin.
Is there an alternate way to store some variables without having to create a database?
You want, I quote, some system constants which do not change so frequently. For this, you can defined your own variables in the settings.py file (or another files apart) and use them by importing them.
The most appropriate way would be to create a new file and import them into settings.py:
SETTING_1 = "/home/path/to/an/executable"
SETTING_2 = False
and then, in the settings.py:
from settings_site import *
It will make SETTING_* variables (give them useful names though) accessible in the settings of your project and you will be able to change the file even if you are using a VCS (SVN, Git...).
Otherwise, you can still implement a solution based on a configuration file, editable through a custom view, but it will require to create an application to manage that. But, coupled with the cache system, it can be as efficient as the use of the settings.py if you are parsing the file only when it is needed (at the startup and at every changes)
I plan to build my project in Django framework. However, I noticed that all Django packages have models.py file. Now, let say I have a set of general purpose functions that I share between several apps in the project and I plan to put these functions definitions in a separate package (or app for that matter?). So, should I create an app "general" and copy-paste these functions into the models.py file? Or can I just create a general.py file in the "general" app directory and leave models.py empty? What is the "Django" way to do that?
Thanks.
models.py file is used to define the structure of database. So you should leave it for defining your database entries. You can make an app named generals and put general.py in that app, and from there you can use it by calling it in any app.
I usually create a utils.py file under my main app that is created from the django-admin.py when starting the project.
I plan to put these functions definitions in a separate package (or app for that matter?)
Before you decide to make this an app (and if you do decide to make it an app), I recommend you take a look at James Bennet keynote on Developing reusable apps and hist post on laying out an application. From one of his slides:
Should this be its own application?
Is it orthogonal to whatever else I’m doing?
Will I need similar functionality on other sites?
Yes? Then I should break it out into a separate application.
If you're cramming too much functionality in one single general purpose app, it might be better to split your general purpose app into multiple reusable apps.
Going back to your original question, Django is expecting a models.py file in every app. So you must have the file even if it's empty.
Inside your models.py, you should only have the application’s model classes. So, you wouldn't be following a best practice if you put inside models.py some miscellaneous code you want to reuse.
From the laying out an application post I mentioned before:
At the application level, I usually drop in a few more files depending on exactly what the application is going to be using:
If the application defines any custom manipulators, I put them in a file called forms.py instead of in the views file.
If there are multiple custom managers in the app, I put them in a file called managers.py instead of the models file.
If I’m defining any custom context processors, I put them in a file called context_processors.py.
If I’m setting up any custom dispatcher signals, they go in a file called signals.py.
If the application is setting up any syndication feeds, the feed classes go in a file called feeds.py. Similarly, sitemap classes go in sitemaps.py.
Middleware classes go in a file called middleware.py.
Any miscellaneous code which doesn’t clearly go anywhere else goes in a file or module called utils.
All of this does not answer directly your original question:
can I just create a general.py file in the "general" app directory and leave models.py empty?
But I hope this gives you additional information to make a decision that better fits your project and requirements.
I have been reading some django tutorial and it seems like all the view functions have to go in a file called "views.py" and all the models go in "models.py". I fear that I might end up with a lot of view functions in my view.py file and the same is the case with models.py.
Is my understanding of django apps correct?
Django apps lets us separate common functionality into different apps and keep the file size of views and models to a minimum? For example: My project can contain an app for recipes (create, update, view, and search) and a friend app, the comments app, and so on.
Can I still move some of my view functions to a different file? So I only have the CRUD in one single file?
First, large files are pretty common in python. Python is not java, which has one class per file, rather one module per file.
Next, views, even as the standard used, is a python module. A module need not be a single file. It can be a directory containing many files, and __init__.py
And then, views.py is only a convention. You, the application programmer are referring to it, and django itself doesn't refer anywhere. So, you are free to put it in as many files and refer appropriate functions to be handed over, the request to, in the urls.py
They don't have to go in views.py. They have to be referenced there.
views.py can include other files. So, if you feel the need, you can create other files in one app that contain your view functions and just include them in views.py.
The same applies to models.py.
Django apps lets us separate common
functionality into different apps and
keep the file size of views and models
to a minimum? For example: My project
can contain an app for recipes
(create, update, view, and search) and
a friend app, the comments app, and so
on.
I don't know about the "to a minimum" part - some apps are just big in views, others big in models. You should strive to partition things well, but sometimes there is just a lot of code. But other than that, this is a fair summary of Django apps, yes.
I also very much dislike long files.
Of course what you read in the other answers is true, but I exploit some very nifty python equivalence:
views.py
and
views/__init__.py
are pretty much functionally equal - by that I mean that if the both contain def my_view() then
from views import my_view
will work the same in both cases!
From there it's easy to structure your long files into smaller ones, yet keeping the naming convention that every django developer is used to:
views/__init__.py
views/largemodel_view.py
then in __init__.py don't forget to import the views from largemodel_view.py.
With large applications I do the same with models though you must remember to set the Meta.app_name:
class MyModel(models.Model):
...
class Meta:
app_name = 'yourappname'
because django will not pick it up magically otherwise for the Admin (but it will still load it, thanks to Python!)
so my apps usually end up looking something like:
project/settings/__init__.py
/..othersettings..
/app_1/models/__init__.py
/...
/views/__init__.py
/...
/templates/
/static/
urls.py
/urls.py
etc.
though of course there's no limit (urls could be split too, etc.etc.)
is there some pythonic way to load a django app trough an alias name? This I think would be one way to make an app more "pluggable-friendly".
there is a pattern used in settings.py:
INSTALLED_APPS = ('... ','...', )
where INSTALLED_APPS is a tuple containing names of apps.
That's fine, but I don't want to put in certain apps explicitly this way.
I would like to have an app handle named say external_login_app mapping to drupal_login or mediawiki_login (to be supplied by the end user or a third party), where name of the actual custom module/app is provided by a string variable in settings.py
The pluggable part (e.g. mediawiki_login) must be a full-fledged app with it's own views, models, forms, etc, while external_login_app must be accessible anywhere in the rest of the code.
The goal here is to decouple distributed code from plugins like that.
edit 1: here is what I'm trying:
in settings.py
EXTERNAL_LOGIN = __import__(EXTERNAL_LOGIN_APP)
#setting name must be upper case according to
#django docs
but my custom login app depends on the settings file too, so looks like I have a circular import problem with errors like module external_login does not have attribute views.
This problem seems to be very insidious, as I am unable to use even simple things like render_to_response shortcut in views imported with __import__ statement in settings.py.
edit 2: after trying a while I found that using __import__() in settings.py call won't work because of almost inevitable circular dependencies
The best working method I found so far is to place __import__() calls into other .py files of the app providing the generic "consumer" interface - the one that calls the plugin functions:
in settings.py: as Michał suggests in his answer
EXTERNAL_LOGIN_APP = 'drupal_login'
INSTALLED_APPS = (
'...',
EXTERNAL_LOGIN_APP,
)
e.g. in app/views.py:
from django.conf import settings
EXTERNAL_LOGIN = __import__(settings.EXTERNAL_LOGIN_APP, \
[], [], ['api','forms'])
def login_view(request, external=False):
if external:
form = EXTERNAL_LOGIN.forms.LoginForm(request.POST)
if form.is_valid():
login = form.cleaned_data['login']
password = form.cleand_data['password']
if EXTERNAL_LOGIN.api.check_password(login, password):
#maybe create local account,
#do local authentication
#set session cookies for the
#external site to synchronize logins, etc.
Set
LOGIN_APP_NAME = 'drupal_login' # or 'mediawiki_login', or whatever
early enough in settings.py, then put LOGIN_APP_NAME (without any quotes around it!) in your INSTALLED_APPS instead of the name of the actual app.
If you need more complex functionality involved in determining what app to use, how about putting something like external_login_app() (a function call -- put no quotes around it!) in INSTALLED_APPS and having the external_login_app function return whatever it is that it should return based on a setting in settings.py, or maybe the contents of a config file somewhere or whatever? (EDIT: Tobu's answer shows what such a function might need to return and how it might go about achieving that with __import__.)
Anyway, I'm not sure that much is achieved in this way in terms of decoupling parts of the site -- if the user still needs to modify settings.py, why not have him / her put in the name of the appropriate app in the right place? (EDIT: OK, so now I sort of see what could be gained with the right solution here... I guess the discussion continues as to how best to do what is required.)
EDIT: I posted this prior to the Original Poster amending the question with any edits, and now edit 2 includes the idea of moving the name of the login app to a separate variable in settings.py and including the variable in INSTALLED_APPS. Now that the two edits to the original question are in place, I guess I can sort of see the problem clearer, although that just makes me think that what the situation calls for is an abstract_login app with backends to support the '*_login' modules dealing with drupal, mediawiki etc. login schemes. Well, I can't say I can provide that sort of thing right now... Hope somebody else can. Will edit again should I believe I have a bright idea simplifying the whole thing beyond the OP's edits.
Defining the app name in settings(as Michał and your edit do) works well:
EXTERNAL_LOGIN_APP = 'drupal_login'
INSTALLED_APPS = (
'...',
EXTERNAL_LOGIN_APP,
)
Also in settings, or in a common module, you could then factor in importing the app:
def external_login_app():
return __import__(EXTERNAL_LOGIN_APP, …)
And use it after your imports:
external_login_app = settings.external_login_app()