I like Eclipse for a number of reasons. One of them is, when I'm doing a java project, I can copy and paste my project or rename it, to make a new one, and it will update all the names of everything.
I'm trying to do something similar for a django project.
I can set an APPNAME variable with the following code
APPNAME = os.path.basename(os.path.dirname(__file__))
and then I could import this in any file that needed to know the name of the application. This isn't an ideal solution however but it would work for my settings.py file as well as my urls.py files.
It won't work for situations where I need to import something from somewhere like so:
from myproject.someapp import forms
Is there a way for django/python to know what "myproject" is? Or can I use an import statement relative to the current app?
Or maybe there's a better way to copy django projects.
EDIT: I imagine there are also database dependencies as well that I'd have to deal with.
I follow a couple of rules to keep my applications portable. I'll list them below in the hope that someone finds them useful.
Include my apps in the PYTHONPATH rather than my projects. This way I can execute from app import forms rather than from project.app ....
Following #1, I always import from app only. This means I can reuse my apps in other projects without having to change import statements within the app or in other dependent apps.
If you stick to #1 and #2 you can generally copy and paste projects without too much trouble. You'll still have to modify settings.py though.
Related
I have a general question about project structure in Django. I have several apps on my website. Let's say App A & App B
I have now an API code which I want to import in both apps. I couldn't find a page answering me this question so I want to ask you here. Where in the project folder should I store this SOMEAPI.py file to import it in both app?
Don't overthink it, it's not that important and it can be changed easily. If the file is mostly related to A, I'll put in A and use import some_api from A wherever you need it. Same thing if it's mostly related to B. If it's really independent from both apps, what I often do is create another app common which contains all the code common to the other apps (usually some function helpers), like common.some_api, common.helpers etc...
Should a component be its own application?. So we have separate our apps for that reason.
Now reusability does matter in Django. It is trivial to make our apps reusable when each module in the apps does not depends on another apps.
However, It is common to refer a model in another apps by adding ForeignKey('appname.MyModel'). It creates a hard dependency of the Django apps with another apps.
The same thing happened with import of another apps (i.e. from appname import MyModel). It creates a dependencies of the apps to another apps.
If the app contains such dependency of another apps, then it does not seems to be viable to share our apps (i.e. Not reusable).
What do I have to do to make the dependencies loose. And allow me to share my apps without having to hardcode another apps in the app.
So, it's worth noting that we don't really need to depend on your specific apps. We depend instead on having something that satisfies the same interfaces your apps expose.
This is the 'Pythonic' way to do things (sometimes referred to as duck typing as 'if it walks like a duck and quacks like a duck... it must be a duck').
You've had in comments how to solve the ForeignKey problem
To summarise, you can just add the value in settings.py:
MY_FK_MODEL = 'someapp.SomeModel'
and then use it in your models.py like so:
from django.conf import settings
class ReusableAppModel(models.Model):
some_model = models.ForeignKey(settings.MY_FK_MODEL)
So far, so easy; now to solve the import.
We actually already have an example of this from Django itself. Which is the get_user_model() method.
We could make something like that by adding the following in settings.py:
MY_APP_DEPENDENCY = 'myapp.my_module.MyClass'
along with a helper function similar to get_user_model() somewhere in your reusable app. Let's say reusable_app/helpers.py for the sake of argument:
from django.conf import settings
from pydoc import locate
def get_my_app_dependency():
dependency = locate(settings.MY_APP_DEPENDENCY)
# locate() returns None if the class is not found,
# so you could return a default class instead if you wished.
return dependency
Then you can get that class wherever you need it by calling the method:
from reusable_app.helpers import get_my_app_dependency
MyAppDependency = get_my_app_dependency()
app_dep_instance = MyAppDependency()
The summary here is that you can allow users to specify a class/method/whatever as a string in settings.py and then use that to refer to your dependency.
This lets users 'inject' a dependency into your app.
One final note:
Whenever you have an app/module that has lots of dependencies on others, it's worth double checking to see if they really should be separate. You want to avoid creating one giant module satisfying lots of disparate responsibilities, but likewise you want to avoid artificially breaking code up when it doesn't make sense. It's a careful balance.
I am working on a django app that needs a directory to download and store files.
I want to keep my app reusable so I do not want to hard code the path of this directory.
So I want to make this path a setting/a global variable that can be set up.
Where could I put this setting/global variable?
Is this kind of approach good ?
http://blog.muhuk.com/2010/01/26/developing-reusable-django-apps-app-settings.html
Thanks for your advice!
I use the following methodology:
# some file in your app:
from django.conf import settings
MY_APP_SETTING = getattr(settings, 'MY_APP_SETTING', 'some default value')
This effectively allows end-users to customized the setting in their own settings.py, but still ensures that there's always some default value set. You can now use MY_APP_SETTING at will in the rest of your code.
UPDATE
The link in your question was taking too long to load, so I just went ahead and answered. As it turns out, the method I suggested is the same as what it suggests, so yes, I'd consider that approach good ;).
My django project has two environments - development and test. Today I carelessly overwrote the settings.py in test with the one in development. It took me a while to correct the settings in test, which could have been avoided if I have a good way to maintain the two sets of settings separately.
I was thinking to keep two separate copies of settings.py and rename/move them when needed. This, however, is kinda caveman approach. Are there any smarter ways of dealing with this problem?
At the end of your settings.py file, add this:
try:
from settings_dev import *
except ImportError: pass
Where settings_dev.py will contain the dev settings. And in your production env, do not push settings_dev (just ignore it in .gitingore or your source code versioning system.)
So, when ever settings_dev.py is present, the settings.py will be overwritten by the settings_dev.py file.
One more approach by setting the environment variable:
if os.environ.get('DEVELOPMENT', None):
from settings_dev import *
mentioned here: Django settings.py for development and production
I prefer the first one, it's simple and just works.
Split your settings as documented here:
https://code.djangoproject.com/wiki/SplitSettings#SimplePackageOrganizationforEnvironments
OK -- I've been working with Django for a few months now and have come across a weird issue. To set it up, here's my webapp structure.
The main Django project is called cpm.
I have a bunch of django apps in the cpm folder. Within each app, I have my models.py file.
Now, when I want to create/use models from other apps I would do something like:
from cpm.products.models import *
assuming an app named products was present. Recently, I started to get some errors saying things like, cannot import XYZ from products. So, after much searching, I changed the line:
from cpm.products.models import *
to
from products.models import *
I just dropped the cpm. part and now it works.
Can someone tell me why this is happening? It seems to be happening on only portions of my apps (I have a bunch within the CPM project). I want to make sure my syntax is accurate as I move forward.
Thanks!
The project root's directory got removed from the python path somewhere along the way, or you removed the __init__.py file from it's root.
On a side note, importing * will lead to issues, especially when you start adding lots of apps. Consider doing from products import models as prod_models. Then doing prod_models.MyModel where you need to reference your models.