Django: How to use apps installed with pip - python

I want to make use of Django's modularity and integrate some external apps that I installed using pip. However, I am encountering difficulties in understanding how can I integrate and use or extend their urls, views, models. There isn't much on this subject, I can't figure why.
Let's take the example of changuito-cart:
Do i create a folder named "changuito" in root and create urls/views in here, or should I just create a new app named like it?
In settings.py I added "changuito" to my installed apps list and I got "no module named 'changuito'" error. How do I add it correctly?
What are the basic steps required to integrate it?

After pip installing the app and adding it to your INSTALLED_APPS you should be good to go. There are cases where the name you need to add to your INSTALLED_APPS is different from the package name. Such cases should be apparent from the documentation, otherwise you need to look at the module structure itself. In your case the package is called "django-changuito" and you have to include "changuito" in your INSTALLED_APPS. Be also aware that this particular package depends on MIDDLEWARE_CLASSES settings. Please read the documentation!
Make also sure that the correct virtual environment is activated while installing if you use one.
In general you would not modify the external app itself. This would be quite dangerous since it will start to differ from the upstream and break down the road. If you want to subclass or extend classes of the external app you need to import these classes into your own app before extending or monkey patching. In this case you will create a different class in a different, your app.
Finally, some apps allow for extending templates. Django will search for templates and statics in your project structure first. If you recreate the folder structure of an external app and put new templates in the exact right place. Django will use those.

Related

Django : Why should I add package name inside INSTALLED_APPS?

In Djano, why should I add third-party package names inside the INSTALLED_APPS for some packages such as django-filter, DRF, debug-toolbar etc, while I don't want to add for some packages such as Celery, Requests etc ?
I couldn't figure out why should add them to a specific list, even though they all are similar pip packages and I installed them in the same way. Thanks in advance!
From docs :
Package? App?
A Python package provides a way of grouping related Python code for
easy reuse. A package contains one or more files of Python code (also
known as “modules”).
A package can be imported with import foo.bar or from foo import bar.
For a directory (like polls) to form a package, it must contain a
special file init.py, even if this file is empty.
A Django application is just a Python package that is specifically
intended for use in a Django project. An application may use common
Django conventions, such as having models, tests, urls, and views
submodules.
From above statements we understand that every well-written python code could be a package, now if this package is a bunch of python code in a directory, installing it would mean just copy the directory in your project and import them wherever needed in code.
But now there is this package which was already a django app and maybe used some special advantages of being one. Like exposing a restful API or delivering some sort of static resources or even working with special django-specific classes. these kind's of operation's need your direct permission in settings.py so that your project will know how to deal with this package. or even they may require to include their url path's to your project so that people visiting your site could access them.
I assume all this manual job is an act of security.
You need to add apps with models(non-abstract), templates, templatetags or management commands so that django-admin finds and loads them

How to include prerequisite apps in INSTALLED_APPS

I have a Django App I'm building, which we will call foo.
Because of the way Foo is built, it requires a number of third-party django apps to function. For example, to run Foo an install apps might look like:
INSTALLED_APPS = ('prereq1',prereq2','foo')
In fact, for Foo to even be functional, 'prereq1', prereq2' have to be installed in django. Now, I can add requirements to requirements.txt or setup.py to make sure the libraries are installed when someone goes to install Foo, but I can't figure out if there is a way to have them installed in Django itself.
The reason for this is if someone wants to use Foo, I don't want to include instructions like:
In your INSTALLED_APPS add foo but also add scary_looking_library_name and thing_you_dont_understand.
So is it possible for an app in INSTALLED_APPS to somehow require or inject further apps into that list?
I agree with Daniel Roseman's answer about the system checks framework being an optimal place for these checks. The system checks framework was introduced Django 1.7.
However, assuming you have documentation, you can also document these prerequisites such as Django REST Framework did in their installation instructions.
You can then do something like the below in your code (django-mptt used as an example):
try:
from mptt.fields import TreeForeignKey
from mptt.models import MPTTModel
except ImportError:
raise ImportError(
'You are using the `foo` app which requires the `django-mptt` module.'
'Be sure to add `mptt` to your INSTALLED_APPS for `foo` to work properly.'
)
This is the method I have seen used in multiple applications. The onus of reading the documentation lies on the developer.
Perhaps this is an unwanted/unnecessary opinion, but the injection of dependencies into the INSTALLED_APPS is nothing that I feel you should be handling with your application.
I typically try to follow the Zen of Python when designing applications:
"Explicit is better than implicit."
Have the developer manually enter the dependencies in INSTALLED_APPS
"If the implementation is hard to explain, it's a bad idea."
Trying to figure out a way to inject the dependencies into the INSTALLED_APPS is hard to explain. If the third-party dependencies are complicated, let the developer decide.
"Simple is better than complex."
It is easier to document the dependencies and require the developer to add them to the INSTALLED_APPS.
"There should be one-- and preferably only one --obvious way to do it."
The common practice is to have the developer add the third party apps to the INSTALLED_APPS - which is why there is no obvious way to do what you want (injection).
If a developer wants to activate an app, they will. As you so eloquently stated in your example, scary_looking_library_name and thing_you_dont_understand is the responsibility of the developer to understand. Choosing to install it for developer is imposing an unnecessary security risk. Let the developer choose to use your application and initialize its dependencies.
I think the system check framework would be a good place for this. You can write a check that verifies the presence of those apps in the settings and raises an error if they are not there.
I prefer to do dependency check, however i think you demand the below code to inject your desired apps into the django site.
you must put it somewhere to execute, and do a check not to re-execute when the dependencies are loaded.
also if you use it, the 'someapp' in settings.INSTALLED_APPS will not work correctly. maybe you need to also alter it.
from django.apps import apps
installed_apps = [app.__name__ for app in apps.get_apps()]
new_installed_app = installed_app + ['your desired app1', 'your desired app2', ...]
apps.set_installed_apps(new_installed_apps)

Any issues with using "<namespace>.django.<app-name>" for django applications?

I know Django applications are typically named django-appname, however, our non-django packages are released under a namespace for our company (eg. company.modulename). Our Django applications are currently structured in a "django" namespace within that namespace (eg. company.django.appname).
We are evaluating our structure before releasing Django apps. Regardless of the internal path structure, which do you think would be a better project name convention for Django apps and why?
"django-company-appname" <-- more like community naming
"company.django.appname" <-- matches the internal structure and non-django python packages we release.
Edit:
Let me make this a little more clear. We already are using namespaces--our django apps are imported using "company.django.appname". What we are trying to decide, is if the name we use to release that app, as defined in setup.py and listed in PyPI/Github will be "company.django.appname" like our other Python releases or if we should do "django-company-app" instead.
We use a company.modulename style namespace for a few django apps and have encountered no problems.
In the __init__.py files we declare the namespace.
import pkg_resources
pkg_resources.declare_namespace(__name__)
and it's worked fine so far.
Forcing absolute imports will remove any chance of issues due to reuse of package names.

How to override an app in Django properly?

I'm running Satchmo. There are many apps and I've changed some of the source in the Product app.
So my question is how can I override this properly because the change is site specific. Do I have to copy over the whole Satchmo framework and put it into my project or can I just copy one of the apps out and place it in say Satchmo>App>Products? (Kinda like with templates)
Thanks
What I have done which works is to copy the application that I have changed. In this case satchmo\apps\product.
I copied the app into my project folder
Amended my setting.py INSTALLED_APPS from 'product', to 'myproject.product',
This now carries the changes I've made to this app for this project only and leaves the original product app untouched and still able to be read normally from other projects.
When you add a 'Django App' to INSTALLED_APPS in your settings.py file, you're telling Django that there exists an importable python module with that name on your "python path". You can view your python path by viewing the contents of the list stored at sys.path.
Whenever Python (and in this case Django) attempts to import a module it checks each of the directories listed in sys.path in order, when it finds a module matching the given name it stops.
The solution to your problem then is too place your customized Django Apps, e.g., the Satchmo product module, into a location in your python path which will be checked before the "real" Satchmo product module.
Because I don't know how you have your directory structure laid out I'm basically making a guess here, but in your case, it sounds like you have the Satchmo apps living somewhere like /satchmo/apps/ and your project at /my_custom_path/my_project/. In which case you might want to add your customized product module to /my_custom_path/my_project/product/. Because the path at which your Django settings.py file lives is always checked first, that should mean that your customized product module will be found first and imported instead of the built in Satchmo one.
FYI: To check and see the order in which your Satchmo installation is checking directories for modules run python manage.py shell and then in the prompt do import sys; print sys.path.
Normally, I'd say the best thing is to fork Satchmo and keep a copy with your changes.
If you are willing to play with the python path, make sure that your app's directory appears before the other (default) directory. From my tests, if you have two apps/modules with identical names, the first one found is used.

Why are django projects python packages?

Why aren't they simply directories? Any good advice says to keep as much as possible in the apps and not to couple them to the project. The very ability to import an app as project.application discourages this. Why does django-admin.py create the __init__.py at all? The project is perfectly useful without it. What is the justification?
We have a single project that we "subclass" of sorts for other projects. So we have other projects that import stuff from the main project. I guess for us it provides the common namespace that contains all the other apps.
We could move to a package with all our apps in it separate from the projects i guess. Our system has grown rather than been planned.
So I guess my answer is, it provides a good root namespace. (for our needs) :)
The core of a project is a settings.py and a root urls.py. Both of those are Python modules, thus they need to be importable somehow. You can put the project directory directly on the Python path and thus make them importable as top-level modules, but that's arguably even worse practice. Better to have the project be a package and the settings and urls be modules within it.
There isn't a requirement that apps be inside the project's namespace, to my knowledge. Just that they be on the $PYTHONPATH. As such, they are usable by any other code on the system which shares the same PYTHONPATH.
I think the idea is that you can reuse the applications but you don't need to move them from the project where they were initially created. If the project weren't a package you would need to copy/move the application you want to reuse to a python package. Because of that being the project itself a proper python package you can reuse the applications in it without moving the applications to other place.

Categories

Resources