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()
Related
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.
I need to use sub-domains (i think) on Django. I have many "room" on my project and i need to build url with name of room.
Example : If i have a room named "microsoft" and my domain is http://toto.fr i want to have a final url like : "http://microsoft.toto.fr" to go in room of microsoft. I can have few room then few differents url.
How its possible to have this ? Django Sub-Domains can do this ?
Thanks you !
About subdomains
I don't think there is a need in your case for subdomains. You can very well handle the separation of rooms this way:
http://toto.fr/microsoft/
http://toto.fr/room2/
http://toto.fr/room3/
The difficulty will increase (slightly) if you need to generate these urls (e.g users create new rooms).
Using subdomains
Reroute from Apache, Nginx etc.
This is the way I would go and recommend you.
Each service has its way of doing it so you would need to post a specific question related to the service you will use in production.
--- edit ---
The idea here is to have your urls.py work the way Django is meant to:
# urls.py
from django.urls import path
from . import views
urlpatterns = [
path('microsoft/', views.microsoft),
]
So this means on your localhost you will access urls that look like this:
https://localhost:8000/microsoft/something
This is how it is going to work behind the scenes. But you can setup your http server (Apache for example) to allow your users to use:
https://microsoft.example.com/something
Here's an example of configuration (disclaimer I am very much not an expert in this, this might not be exactly the correct syntax):
<VirtualHost *:80>
ServerName microsoft.example.com
RedirectPermanent / http://example.com/microsoft
</VirtualHost>
So when your user types https://microsoft.example.com/something, Apache knows it has to call https://localhost:8000/microsoft/something internally.
--- end edit ---
Use a django extension
django-subdomains does not seem to be active.
--- edit ---
Before going with third party code like django-subdomains you should always check if it is being maintained. You can see on their pypi page that it is not compatible with Django 2 and 3 (and therefore not compatible with python 3). So this should tell you to not go with it.
It would mean for you to start with components that are not being actively maintained and have potential security holes.
--- end edit ---
I tried very quickly to set it up with Django 3 and could get it to work.
There is the this fork that claims compatibility with Django 3 but seems pretty inactive also.
You can handle as many rooms as you want with a variable:
urlpatterns = [
...
path('foo/<str:theroom>/bar/', view_room, name="view-room"),
...
]
If for instance you access
http://youraddress/foo/ubuntu/bar/
then Django will call your view function
def view_room(request, theroom):
with theroom = ubuntu.
If you prefer defining subdomains like http://ubuntu.youraddress, you will have to define one subdomain per room in the httpd config file, but also, to declare these subdomains in an authoritative DNS. That might be complicated, and is not a good idea IMHO, since subdomains are rather used to specify which app is called.
This question has been troubling me for some days now and I've tried asking in many places for advice, but it seems that nobody can answer it clearly or even provide a reference to an answer.
I've also tried searching for tutorials, but I just cannot find any type of tutorial that explains how you would use a reusable third-party django app (most tutorials explain how to write them, none explain how to use them).
Also, I've taken a look here:
How to re-use a reusable app in Django - it doesn't explain how to actually use it IN a project itself
and here:
How to bind multiple reusable Django apps together? - the answer by aquaplanet kind of makes sense, but I thought I would ask this question to solve the mental block I am facing in trying to understand this.
In order to best explain this, let me do so by example (note, it is not something I am actually building).
I am creating a project that acts like Reddit. I will have users, links and voting/points. Based on this crude example, I will want to reuse 3 (arbitrary) third-party apps: user, voting/points and links.
I decide to use each of them as any other python package (meaning that they will be treated as a package and none of their code should be touched) [would this method actually work? Or do you have to be able to edit third-party apps to build a project??)
With these apps now within my project, I will use a main app to handle all the template stuff (meaning everything I see on the frontend will be in a single app).
I will then either use that same main app for custom logic (in views.py) or I will break up that logic among different apps (but will still use a single frontend-only app).
From the 3 paragraphs above, is this structure applicable (or can it work) ?
Now lets say that this structure is applicable and I am using a single main app for the frontend and custom logic.
What would I write in models.py? How would I integrate things from the 3 reusable apps into the main models.py file?
How would I reference the reusable apps in views.py? Lets take the example of contrib.auth
With this built-in app, for logging out I would write:
from django.contrib.auth import logout
from django.contrib.auth.decorators import login_required
from django.shortcuts import redirect
#login_required
def user_logout(request):
logout(request)
return redirect('/home/')
Although the above code is simple, is that basically how things would be done with any reusable app?
My question is very long, but I think that this reusable app issue is something a lot of developers aren't quite clear about themselves and maybe this answer will help a lot of others who have heard about the promises of reusable apps, but fail to understand how to actually use them.
TL;DR:
Nope & it depends...
Some (Very) Common Reusable Apps
django.contrib.admin
django.contrib.auth
django.contrib.staticfiles
... those are all reusable Django apps, that happen to be shipped with Django (most of them were not, at some point in time)
Ok, some other reusable apps that don't ship with Django:
django-rest-framework
django-registration
South
Those are all truly reusable apps, and nothing less. There are very many more apps like that.
How do they do it?
To me your question looks more like "how do I build reusable apps", then "how to use them". Actually using them is very different from app to app, because they do very different things. There is only one rule: RTFM No way around that either.
Often, they rely on one or more of the following:
additional value(s) in settings.py
addition (usually one include statement) to urls.py
subclassing and/or mixins for Models, Forms, Fields, Views etc.
template tags and/or filters
management commands
...
Those are all powerful ways though which your app can provide functionality to other apps. There is no recipe (AFAIK) to make a reusable app, because there are so many different scenarios to consider. It all depends on what exactly your app should do.
Reusable apps provide functionalities
I'd argue that it's important to not think of reusable apps as "working together" with other app, but instead recognize that that they "provide functionality." The details of the functionality provided should dictate the way the target developer is supposed to use your library.
Not everything should be reusable
Obviously enough, even though many apps can "in principle" be reusable, it often makes little sense to do so, because it is way faster to clump things together (and make them just "work together").
I'm not sure why you think you need a main app for the "frontend" stuff. The point of a reusable app is that it takes care of everything, you just add (usually) a single URL to include the urls.py of the app, plus your own templates and styling as required.
And you certainly don't need to wrap the app's views in your own views, unless you specifically want to override some functionality.
I don't understand at all your question about models. There's no such thing as a "main" models file, and using a reusable app's models is just the same as using models from any of your own apps.
Normally you would not edit a third-party app, that would make it very hard to integrate updates. Just install the app in your virtualenv (you are using virtualenv, of course!) with pip, which will put it in the lib directory, and you can reference it just like any other app. Make sure you add it to INSTALLED_APPS.
Ok here is the problem in brief. I do have a pyramid setup that does start to look like a cms.
I have as base models: [accounts, pages, errors, menus, configs]
It works pretty well but I do have a little problem with something. Currently i'm using git and on some branches I do have different templates and on the master branch I do my change to the core.
I'd like to be able to install themes instead. Themes would be a collection of template files/static file(css/js).
That can be achieved with entry_points and my config view can look them up and display a list of installed themes. That so far can be done.
Being able to switch different themes on the fly would be a very good start so I wouldn't have to fork my projects only for new themes.
The second problem is that theses sites requires different content. For example, one would require "Question" and the other "Products"
So I have this idea in mind
class TemplatePlugin(PyramidPlugin):
template_path = ''
static_path = ''
def register(self, config, app):
'''Inject the plugin in the application... how I'm not sure yet'''
def unregister(self):
'''unregister the plugin if something is needed'''
def (before/after)_(request/newapp...)(self,...):
'''do some stuff for some events most are optional'''
And a different plugin for models
class PyramidPlugin(pyramid_plugin):
def register(self, config, app):
'''add routes,
add view handlers (view_config)
add models acl to the acl list
'''
# other functions similar to the above class to handle events
My biggest problem is how does it find files. I will have to do some test but i'm worried about translations, and file path.
How does it works through entries points is still a mistery to me. Will plugins use babel translations... can I use my babel translation in my template plugins? When an entry point is loaded..current dir is the dir of the project or the dir of the entry point? I believe I can easily get the path with distribution but I'm not sure what is the right way to do all this... I feel like i'm getting in a whole new land filled with mines.
In Pyramid you can pick templates at run-time using render_to_reponse function. But if you want a more cooked solution, you might get inspired by Kotti, a Pyramid CMS that already has support for addons and look and feel customization with 'Babel' for internationalization. In order to use another 'theme' you have to write another package with some templates and static assets following the convention Kotti uses and then you activate the package in the .ini configuration file.
To understand how Kotti achieves this, you should start following the code path from this line
In any case, Kotti makes some assumptions about how the Pyramid application is configured, such as SQLAlchemy for storage, formencode for form generation or traversal to map views to resources, so YMMV. Pyramid itself is unopinionated about the way you do this.
In Django, settings are stored in a file, settings.py. This file is part of the code, and goes into the repository. It is only the developers who deal with this file. The admin deals with the models, the data in the database. This is the data that the non-development staff edits, and the site visitors see rendered in templates.
The thing is, our site, and many others, have lots of settings options that should be edited by non-developer staff. We're talking about stand-alone site-wide constants that really have no place in the database. Putting them in the database will result in numerous pointless queries. Caching could alleviate that, but that seems unnecessarily complex to handle what can be done with a single line in the settings.py file.
I did notice this dbsettings app, but it is old and unmaintained. I also noticed that the django e-commerce app, Satchmo, includes a use-case specific fork of this dbsettings app. We could build something similar into our site, an app that stores some settings as key/value pairs in a single database table, but it just really seems like the wrong approach. Why put something in the DB that doesn't belong there just to make it more easily editable by non-developers?
We have a list of site-wide settings on our Django site that we want to be editable by non-developer administrators. What is the best way of going about this?
Something like dbsettings (as you mentioned) seems like the way to go. From the reasons for existence for that project:
Not all settings belong in
settings.py, as it has some
particular limitations:
Settings are project-wide. This not only requires apps to clutter up
settings.py, but also increases the chances of naming
conflicts.
Settings are constant throughout an instance of Django. They cannot be
changed without restarting the application.
Settings require a programmer in order to be changed. This is true even
if the setting has no functional impact on anything else.
If dbsettings doesn't work for you, then implement your own, or fork it. It doesn't seem like it'd be too arduous.
I'm actually a big fan of dbsettings, and keep meaning to publish my fork that patches it to work with Django 1.1 (not actually a big change). Looks like someone has updated it already.
However, you're probably right that this is overkill for what you need. One thing I've done before is to add a line to the end of settings.py that imports and parses a YAML file. YAML is a simple markup language, which at its most basic is just KEY: VALUE ...
CONSTANT1: MyValue
CONSTANT2: Anothervalue
If you put this somewhere editors can access it, then at the end of settings.py you just do:
import yaml
try:
globals().update(yaml.load(open('/path/to/my/yaml/file.yml')))
except:
pass
You'll need the Python YAML library to parse the YML file.
The downside to this approach is that you'll need to restart Apache to get it to pick up the changes.
Edited to add It wouldn't be particularly difficult to build a front end which could edit this file, and provide a button which runs a script to restart Apache.
If you must avoid server restarts then a logical place for the settings is the database as Dominic and Daniel said, but you'll need to invalidate cached settings object every time it is updated.
Looks like it's possible to re-set values in the cache with Django's low level cache API. All you want should be achievable with these calls:
cache.set('settings', local_settings)
cache.add('settings', local_settings)
local_settings = cache.get('settings')
cache.delete('settings')
How about putting a sitesettings.py (or whatever) somewhere that your admins can access, then in settings.py do
from sitesettings import *
That seems good and simple, but I may have misunderstood or oversimplified your problem :)
models.py
class Setting(models.Model):
"""Global settings for app"""
name = models.CharField(max_length=100, null=False, blank=False)
value = models.CharField(max_length=100, null=False, blank=False)
def __str__(self):
return self.name
admin.py
from YOUR_APP.models import Setting
class SettingAdmin(admin.ModelAdmin):
list_display = (
'name',
'value',
)
admin.site.register(Setting, SettingAdmin)
extras.py
#register.filter
def get_setting(name):
setting = Setting.objects.get(name=name)
return setting.value
template.html
{% if 'setting_name'|get_setting == 'true' %}
Display your Feature
{% endif %}
Django Packages has a page that lists packages that provide such functionality - most query the database and then use caching to minimize hits on the DB.
I found Django Dynamic Preferences to be of particular interest due to the fine-grained control it gives you over the configuration.