Best django questions in June 2012

django==1.4 support for html5

6 votes

I have a small blog app I have built using Django 1.4 and recently, I have been learning "bits and pieces" of html5 and css3. I am about the start transitioning my site to html5/css3 and I was wondering if Django widgets support html5(?)

My blog is nothing special - a few forms, a few tables etc.. For example when I do,

{{form_as_p}}

I was wondering if django would generate the required html5 markup(?) I read the docs, and it says the admin pages support html5, but I could not find any docs for regular apps.

If html5 is not supported by Django, what is the best way going about achieving this?

Thanks for your time.

Django's form output is XHTML. Django does not snip with support for the new HTML5 input types such as number, email, url, etc but it is not difficult to add them. See https://code.djangoproject.com/ticket/16630 or https://github.com/rhec/django-html5 That being said I don't know any place where Django generates markup that is invalid for HTML5.

What to do with pyc files when Django or python is used with Mercurial?

5 votes

Just started to use Mercurial. Wow, nice application. I moved my database file out of the code directory, but I was wondering about the .pyc files. I didn't include them on the initial commit. The documentation about the .hgignore file includes an example to exclude *.pyc, so I think I'm on the right track.

I am wondering about what happens when I decide to roll back to an older fileset. Will I need to delete all the .pyc files then? I saw some questions on Stack Overflow about the issue, including one gentleman that found old .pyc files were being used. What is the standard way around this?

As mentioned in ms4py's answer, *.pyc are compiled files that will be regenerated on the fly. You wouldn't want to include these when distributing a project.

However, if it happens you have modules that existed before when you roll back changes and *.pyc files are left lying around, strange bugs can appear as pyc files can be execute even if the original python file doesn't exist anymore. This has bitten me a few times in Django when adding and removing apps in a project and switching branches with git.

To clean things up, you can delete every compiled files in your project's directory by running the following shell command in you project's directory:

find . -name '*.pyc' -exec rm {} \;

python Socket.IO client for sending broadcast messages to TornadIO2 server

5 votes

I am building a realtime web application. I want to be able to send broadcast messages from the server-side implementation of my python application.

Here is the setup:

I can succesfully send socket.io messages from the client to the server. The server handles these and can send a response. In the following i will describe how i did that.

Current Setup and Code

First, we need to define a Connection which handles socket.io events:

class BaseConnection(tornadio2.SocketConnection):
    def on_message(self, message):
        pass

    # will be run if client uses socket.emit('connect', username)
    @event
    def connect(self, username):
        # send answer to client which will be handled by socket.on('log', function)
        self.emit('log', 'hello ' + username)

Starting the server is done by a Django management custom method:

class Command(BaseCommand):
    args = ''
    help = 'Starts the TornadIO2 server for handling socket.io connections'

    def handle(self, *args, **kwargs):
        autoreload.main(self.run, args, kwargs)

    def run(self, *args, **kwargs):
        port = settings.SOCKETIO_PORT

        router = tornadio2.TornadioRouter(BaseConnection)

        application = tornado.web.Application(
            router.urls,
            socket_io_port = port
        )

        print 'Starting socket.io server on port %s' % port
        server = SocketServer(application)

Very well, the server runs now. Let's add the client code:

<script type="text/javascript">    
    var sio = io.connect('localhost:9000');

    sio.on('connect', function(data) {
        console.log('connected');
        sio.emit('connect', '{{ user.username }}');
    });

    sio.on('log', function(data) {
        console.log("log: " + data);
    });
</script>

Obviously, {{ user.username }} will be replaced by the username of the currently logged in user, in this example the username is "alp".

Now, every time the page gets refreshed, the console output is:

connected
log: hello alp

Therefore, invoking messages and sending responses works. But now comes the tricky part.

Problems

The response "hello alp" is sent only to the invoker of the socket.io message. I want to broadcast a message to all connected clients, so that they can be informed in realtime if a new user joins the party (for example in a chat application).

So, here are my questions:

  1. How can i send a broadcast message to all connected clients?

  2. How can i send a broadcast message to multiple connected clients that are subscribed on a specific channel?

  3. How can i send a broadcast message anywhere in my python code (outside of the BaseConnection class)? Would this require some sort of Socket.IO client for python or is this builtin with TornadIO2?

All these broadcasts should be done in a reliable way, so i guess websockets are the best choice. But i am open to all good solutions.

I've recently written a very similar application on a similar setup, so I do have several insights.

The proper way of doing what you need is to have a pub-sub backend. There's only so much you can do with simple ConnectionHandlers. Eventually, handling class-level sets of connections starts to get ugly (not to mention buggy).

Ideally, you'd want to use something like Redis, with async bindings to tornado (check out brukva). That way you don't have to mess with registering clients to specific channels - Redis has all that out of the box.

Essentially, you have something like this:

class ConnectionHandler(SockJSConnection):
    def __init__(self, *args, **kwargs):
        super(ConnectionHandler, self).__init__(*args, **kwargs)
        self.client = brukva.Client()
        self.client.connect()
        self.client.subscribe('some_channel')

    def on_open(self, info):
        self.client.listen(self.on_chan_message)

    def on_message(self, msg):
        # this is a message broadcast from the client
        # handle it as necessary (this implementation ignores them)
        pass

    def on_chan_message(self, msg):
        # this is a message received from redis
        # send it to the client
        self.send(msg.body)

    def on_close(self):
        self.client.unsubscribe('text_stream')
        self.client.disconnect()

Note that I used sockjs-tornado which I found to be much more stable than socket.io.

Anyway, once you have this sort of setup, sending messages from any other client (such as Django, in your case) is as easy as opening a Redis connection (redis-py is a safe bet) and publishing a message:

import redis
r = redis.Redis()
r.publish('text_channel', 'oh hai!')

This answer turned out pretty long, so I went the extra mile and made a blog post out of it: http://blog.y3xz.com/post/24691592929/a-modern-python-stack-for-a-real-time-web-application

Find the required permissions of Django URLs without calling them?

5 votes

My Django app currently has URLs which are protected by 'permission_required()' functions.

This function is called in three different ways.

  1. As a decorator in views.py, with hardcoded parameters.
  2. As a plain function, with autogenerated parameter, in custom Class Based Generic Views.
  3. As a function invoking views in urls.py, with hardcoded parameters.

I'm now adding a menu system to the app, and I need to make menu entries reflect whether the user has permission to request the URL of each menu entry. (Either by greying-out or hiding said entries.)

Is there a way of query the permissions required to a URL without requesting the URL?

The only solution I've thought of so far is to replace the decorator with a parameterless 'menu_permssion_required()' decorator and hardcode all of the permissions into a Python structure. This seems like a step backwards, as my custom Class Based Generic Views already autogenerate their required permissions.

Any suggestions on how to make a menu system which reflects URL permissions for the current user?

Here is an example of how to solve your problem:

First, Create a decorator wrapper to use instead of permission_required:

from django.contrib.auth.decorators import login_required, permission_required, user_passes_test
from django.core.exceptions import PermissionDenied
from functools import wraps
from  django.utils.decorators import available_attrs

def require_perms(*perms):
    def decorator(view_func):
        view_func.permissions = perms
        @wraps(view_func, assigned=available_attrs(view_func))
        def _wrapped_view(request, *args, **kwargs):
            for perm in perms:
                return view_func(request, *args, **kwargs)
            raise PermissionDenied()
        return _wrapped_view
    return decorator

Then, use it to decorate your views:

@require_perms('my_perm',)
def home(request):
.....

Then, add a tag to use for your menu items:

from django.core.urlresolvers import resolve

def check_menu_permissions(menu_path, user):
    view = resolve(menu_path)
    if hasattr(view.func, "permissions"):
        permissions = view.func.permissions
        for perm in permissions:
            if user.has_perm(perm):
                return True # Yep, the user can access this url
            else:
                return False # Nope, the user cannot access this url
    return True #  or False - depending on what is the default behavior

And finally, in your templates, when building the menu tree:

<button href="{{ some_path }} {% if not check_menu_permissions some_path request.user %}disabled="disabled"{% endif %} />

N.B. I've not tested the last part with the tag, but I hope you got the idea. The magic thing here is to add the permissions to the view_func in the decorator, and then you can access this using resolve(path). I'm not sure how this will behave in terms of performance, but after all that's just an idea.

EDIT: Just fixed a bug in the example..

Caching MongoDB connections in Django

5 votes

I'm using the standard (as opposed to NonRel) version of Django connected to PostgreSQL on top of Apache + mod_wsgi. This setup also connects to MongoDB (some data is saved externally). Right now I have to create a new MongoDB connection for each Django request, and pass it along throughout the call stack to all functions that require access to MongoDB. Is there a way to cache connections between requests?

Edit

At the risk of blasphemy, would a global variable work in this case?

There are several ways explaining how pymongo can work (or fail) with mod_wsgi, suggested here: http://api.mongodb.org/python/current/faq.html?highlight=wsgi#does-pymongo-work-with-mod-wsgi

In addition you can use some kind of pooling solution, like described here: http://www.mongodb.org/display/DOCS/Notes+on+Pooling+for+Mongo+Drivers

One project that I know already to have pooling is MongoEngine, its a very simple ORM that uses pymongo behind the scenes. You might want to look into it together with the pymongo faq solutions above.

Heroku Database Settings Injection - How do I setup my dev django database?

5 votes

I'm trying to get my local dev django app to work after following these instructions on adding env database settings.

https://devcenter.heroku.com/articles/django-injection

I followed the instructions but get the following error when my app tries to access the local database

Request Method: GET
Request URL:    http://localhost:8000
Django Version: 1.4
Exception Type: ImproperlyConfigured
Exception Value:    
You need to specify NAME in your Django settings file.

My database settings originally,

DATABASES = {
    'default': {
        'ENGINE': 'django.db.backends.postgresql_psycopg2',
        'NAME': 'db',                      # Or path to database file if using sqlite3.
        'USER': 'foo',                      # Not used with sqlite3.
        'PASSWORD': 'bar',                  # Not used with sqlite3.
        'HOST': 'localhost',                
        'PORT': '5432',
    }
}

the heroku article says to add the following to the settings file

import dj_database_url
DATABASES = {'default': dj_database_url.config(default='postgres://localhost')}

how do I get dj_database_url.config to use my my dev settings when the DATABASE_URL is not available in dev?

You can just add your dev settings to the default values like this...

import dj_database_url
DATABASES = {'default': dj_database_url.config(default='postgres://foo:bar@localhost:5432/db')}

Git: Exclude a file with git clean

5 votes

i'm working on a big python project, and i'm really sick if .pyc and *~ files. I'd like to remove them. I've seen that the -X flag of git clean would remove untracked files. As you can imagine, i'm not tracking .pyc nor *~ files. And that would make the trick. The problem is that i've a local_settings.py file that I'd like to keep after the git clean.

So, this is what I've got.

.gitignore:

*.pyc
*~
local_settings.py

When I execute this command:

git clean -X -n -e local_settings.py

I get this list of results:

Would remove local_settings.py
Would remove requirements.txt~
Would remove (other bunch of) ~ files
Would remove (other bunch of) pyc files

I don't want to remove the local_settings.py file. I've tryed lots of ways to do it, but i can't figure out how to acomplish it.

git clean -X -n -e local_settings.py
git clean -X -n -e "local_settings.py"
git clean -X -n --exclude=local_settings.py
git clean -X -n --exclude="local_settings.py"

And nothing seems to work.

EDIT:

For posterity, the right way to do it is (Thanks @Rifat):

git clean -x -n -e local_settings.py # Shows what would remove (-n flag)
git clean -x -f -e local_settings.py # Removes it (note the -f flag)

Will you please try that with small x instead of the capital one. Like - git clean -x

   -x
       Don't use the standard ignore rules read from .gitignore (per
       directory) and $GIT_DIR/info/exclude, but do still use the ignore
       rules given with -e options. This allows removing all untracked
       files, including build products. This can be used (possibly in
       conjunction with git reset) to create a pristine working directory
       to test a clean build.

   -X
       Remove only files ignored by git. This may be useful to rebuild
       everything from scratch, but keep manually created files.

Django: Pass variable to logging in settings file

5 votes

I am trying to add a variable to my log line through my settings.py file.

This is the code in settings (the logging part):

LOGGING = {
    'version': 1,
    'disable_existing_loggers': False,
    'handlers': {
        'mail_admins': {
                        'level': 'CRITICAL',
                         'class': 'django.utils.log.AdminEmailHandler'
                        },

        'customhandler':{
                        'level':'DEBUG',
                        'class':'logging.RotatingFileHandler',
                        'formatter':'custom_format',
                        'filename':LOG_LOCATION
                        },
                 },

     'loggers': {
         'django.request': {
                        'handlers': ['mail_admins'],
                         'level': 'CRITICAL',
                        'propagate': True,
                            },
         'Logger_Custom1': {
                        'handlers':['customhandler'],
                        'level':'DEBUG',
                        'propagate':True
                           },
                 },

    'formatters': {
        'verbose': {
            'format': '%(levelname)s %(asctime)s %(module)s %(process)d %(thread)d %(message)s'
                     },
         'simple': {
            'format': '%(levelname)s %(message)s'
                     },
         'custom_format':{
            'format':'[%(asctime)s %(levelname)s T:%(threadName)s F:%(funcName)s ] %(message)s '
                         },
                 }
}

The above code is working fine, but now I would like each log message to have a variable at the end. Something like:

MyVariable = "Somelines" 
[%(asctime)s %(levelname)s T:%(threadName)s F:%(funcName)s ] %(message)s 'MyVariable

So my log would have that variable's contents at the end of each logging line. I know we can do that inside the view function like this: logging.warning('% before you %','Look','Leap') But that will require us to include that line everywhere separately. Also, when we need to add or change that variable name, we will need to change that line everywhere in every file.

So I was wondering if there is any way to do that directly from settings.py, so that we can make one change and it will apply to all logging messages.

I found out the solution by myself. I don't know if this is a good practice, but it works.

All I did was assign a variable:

testvar = "MyVariable"

And then append this variable, like this:

'format': '%(levelname)s %(asctime)s %(module)s %(process)d %(thread)d %(message)s ' + testvar

The output will have the variable in your log entry merged with the log format. Thank you. Please let me know if there are more ways to do it.

Python : How do you find the CPU consumption for a piece of code?

4 votes

Background:

I have a django application, it works and responds pretty well on low load, but on high load like 100 users/sec, it consumes 100% CPU and then due to lack of CPU slows down.

Problem :

  • Profiling the application gives me time taken by functions.
  • This time increases on high load.
  • Time consumed may be due to complex calculation or for waiting for CPU.

so, how to find the CPU cycles consumed by a piece of code ?

Since, reducing the CPU consumption will increase the response time.

  • I might have written extremely efficient code and need to add more CPU power

OR

  • I might have some stupid code taking the CPU and causing the slow down ?

Any help is appreciated !

Update:

  • I am using Jmeter to profile my webapp, it gives me a throughput of 2 requests/sec. [ 100 users]
  • I get a average time of 36 seconds on 100 request vs 1.25 sec time on 1 request.

More Info

  • Configuration Nginx + Uwsgi with 4 workers
  • No database used, using a responses from a REST API
  • On 1st hit the response of REST API gets cached, therefore doesn't makes a difference.
  • Using ujson for json parsing.

Curious to Know:

  • Python-Django is used by so many orgs for so many big sites, then there must be some high end Debug / Memory-CPU analysis tools.
  • All those I found were casual snippets of code that perform profiling.

You could try configuring your test to ramp up slowly, slow enough so that you can see the CPU gradually increase and then run the profiler before you hit high CPU. There's no point trying to profile code when the CPU is maxed out because at this point everything will be slow. In fact, you really only need a relatively light load to get useful data from a profiler.

Also, by gradually increasing the load you will be better able to see if there is a gradual increase in CPU (suggesting a CPU bottleneck) or if there is a sudden jump in CPU (suggesting perhaps another type of problem, one that would not necessarily be addressed by more CPU).

Try using something like a Cosntant Throughput Timer to pace the requests, this will prevent JMeter getting carried away and over-loading the system.

django one-to-many relation

4 votes

In my app,I need to associate the User with a user-selected-filename

A user can only select one filename.But the same filename may be selected by many users

So,database table may be like this

auth_user(created by django.contrib.auth)

-----------------------------------------
id | username | first_name | last_name | ...
------------------------------------------
1  |  bert     |  bert     | russel    |...
------------------------------------------
2  |  jon      |  jon      | snow      | ...
-------------------------------------------
3  |  alice    | alice     | tanner    | ...

userfile table

-----------------------------------------------
id  | filename              
------------------------------------------------
1   |  '/clips/summary.mp4'  
------------------------------------------------
2   | '/clips/intro.mp4'    
------------------------------------------------

user_userfile table

-----------------------------------
 user_id   |    userfile_id
-----------------------------------
   1       |    1
-----------------------------------
   2       |    1
-----------------------------------
   3       |    2
-----------------------------------

It seems that userfile--user is a 1 - n relation . 1 userfile can be associated with many users.

So,what should I use to represent this relationship? In class UserFile given below ,if I use

user = db.models.ForeignKey(django.contrib.auth.User)

That will only make the reverse relationship (ie n-1 for userfile--user)

class UserFile(db.models.Model):
    filename = db.models.CharField()
    user     = ??

I would really like a OneToMany field too. But the reason there is no such field in Django i believe is that this would create an FK on the table of the related model:

  1. That's sort of confusing

  2. Syncdb wouldn't be able to add the column to the existing table

The solution to add the FK on a related model is to use an "unsupported" feature:

from django.contrib.auth.models import User
models.ForeignKey(Badge, null=True, blank=True).contribute_to_class(User, 'badge')

Then you should add migrate auth_user to add the FK.

django-object-permissions Vs django-guardian Vs django-authority

4 votes

I've found 3 row-level permission solutions for Django 1.2+

Could someone tell if there is any recommended more than the others, what are their main differences, etc.?

I'll start this by saying we use none of these for object level permission - we use our own custom method and I really wish we hadn't. If you can avoid object level permissions at all, do so, they are a pain to organise.

This is how I evaluate the 3 apps you've mentioned.

Active Development:

  1. django-guardian (1 week ago)
  2. django-object-permissions (1 year ago)
  3. django-authority (nearly 2 years ago)

API

  1. django-guardian (save an instance of a defined model)
  2. django-object-permissions (register permissions)
  3. django-authority (define classes)

The above are in order by the way.

I'd recommend guardian purely on API alone, but the fact that it is still being developed where the others aren't usually means a big win.

Formatting Time Django Template

4 votes

I am extracting a time stamp from JSON which I want to convert to EST and format in human readable form.

When I extract it from JSON, I get the following text: "2012-06-30T10:36:06-07:00"

How do I convert it to east coast time (+3 hours) and in proper format ("6-30-2012 1:36pm")?

you could use the pyiso8601 package that does this exactly. It accepts tzinfo which you can use pytz library to get predefined timezones. [they have plenty of e.g.]

De-encode URL parameters

3 votes

I am talking to a server that used to send me HTTP strings like this:

/path/to/my/handler/?action-query&id=112&type=vca&info=ch=0&type=event&ev16[sts=begin (...)

So the "info" GET parameter included "=" and "&" characters. It was rather unorthodox but nevertheless we wrote a parser for it. However, recently they have decided to encode part of it, so now the string looks like this..

/path/to/my/handler/?action=query&id=112&type=vca&info=ch%3D0%26type%3Devent%26ev46[sts%3Dbegin (...)

This breaks our parser, which expects a string like the first one.

Can I somehow "de-encode" the string, so that I can use the old code (so that it's not broken as we re-write the parser)?

As per answer below, we can use urllib.unquote() to clean the string up. However, we are relying on request.GET, which gets set up based on the first string. Is it possible to reconstruct the GET object based on the new converted string, or somehow force it to re-evaluate?

I suspect what you want is the unquote function from the urllib module.

>>> s = '/path/to/my/handler/?action=query&id=112&type=vca&info=ch%3D0%26type%3Devent%26ev46[sts%3Dbegin'
>>> import urllib
>>> urllib.unquote(s)
'/path/to/my/handler/?action=query&id=112&type=vca&info=ch=0&type=event&ev46[sts=begin'

Edit: I'm not very familiar with Django, but the Request and response object section of their docs states the following:

QueryDict instances are immutable, unless you create a copy() of them. That means you can't change attributes of request.POST and request.GET directly.

Based on my limited reading of those docs, you might be able to apply the unquote() function to the HttpRequest.body attribute and build a new QueryDict out of the results (and possibly use it to update your current one if necessary).

what is reverse() in Django

3 votes

When I read django code sometimes, I see in some templates reverse(). I am not quite sure what this is but it is used together with HttpResponseRedirect. How and when is this reverse() supposed to be used?

It would nice if someone gave an answer with some examples...

https://docs.djangoproject.com/en/dev/topics/http/urls/#reverse

in your urls.py define this:

url(r'^foo$', some_view, name='url_name'),

in a template you can then refer to this url as:

<!-- django <= 1.4 -->
<a href="{% url url_name %}">link which calls some_view</a>

<!-- django >= 1.5 or with {% load url from future %} in your template -->
<a href="{% url 'url_name' %}">link which calls some_view</a>

this will be rendered as

<a href="/foo/">link which calls some_view</a>

now say you want to do something similar in your views.py - e.g. you are handling some other url (not /foo/) in some other view (not some_view) and you want to redirect the user to /foo/ (often the case on successful form submission)

you could just do

return HttpResponseRedirect('/foo/')

but what if you want to change the url in future - you'd have to update your urls.py and all references to it in your code. This violates DRY (google it).

instead you can say

return HttpResponseRedirect(reverse('url_name'))

This looks through all urls defined in your project for the url defined with the name url_name and returns the actual url /foo/.

this means that you refer to the url only by its name attribute - if you want to change the url itself or the view it refers to you can do this by editing one place only - urls.py. This whole idea of editing one place only is refered to as "Don't Repeat Yourself" and is something to strive for.

package that works inside and outside django. Is this a good design?

3 votes

I'm relative new to django and in generall to the python world. But I have experience with ruby (been working with rails for 2 years) so many concepts of python/django are not that new to me.

Anyway, I am writing an small package in python that will have a database connection and I want to use this package inside django but also in the feature outside django. So I decided take advantage of django.db and not worry about writing any database connection and managment stuff.

So I started writing my first models and wanted to make a first test outside of a django environment and I'm finding myself with some difficulties.

I thought about having the same configuration mechanism for my package as for any django application (I mean the settings.py file). I wrote a file (called nodjango_settings.py as a template) that only contains the DATABASES dictionary and added two custom variables to it:

MYAPP_DB_ID   = "myappdb"
MYAPP_DB_PREFIX = "myapp_"
DATABASES = {
  MYAPP_DB_ID: {
    'ENGINE': 'django.db.backends.postgresql_psycopg2',
    'NAME':   'myappdb',
  }
}

The directory structure of my package is:

.
|-- README.txt
|-- doc
|   `-- db.txt
|-- setup.py
|-- src
|   |-- __init__.py
|   `-- myapp
|       |-- __init__.py
|       |-- exceptions.py
|       |-- models.py
|       |-- nodjango_settings.py
|       `-- nodjango_settings.pyc
`-- test
    `-- test.py

I was reading a little bit of djangos own code to see how to handle the DJANGO_SETTINGS_MODULE environment variable and read the configuration file, so added the following code to myapp/__init__py.

import os

# try to look after the DJANGO_SETTINGS_MODULE environment variable
# if not present raise an import error

# code abstract from python2.6/site-packages/django/conf/__init__.py
try:
    settings_module = os.environ["DJANGO_SETTINGS_MODULE"]
    if not settings_module: # If it's set but is an empty string.
        raise KeyError
except KeyError:
    raise ImportError("The DJANGO_SETTINGS_MODULE environment variable is not present.")


# TODO: look at python2.6/site-packages/django/conf/__init__.py +93
# if you print sys.path then the project directory gets added
# in django/core/management/__init__.py with sys.path.append
from django.utils import importlib

p = importlib.import_module(settings_module)

print p.MYAPP_DB_ID

I wanted to test that __init__.py works as intended so on the root directory of my package I ran:

$ DJANGO_SETTINGS_MODULE="src.myapp.nodjango_settings" python src/myapp/__init__.py


Traceback (most recent call last):
  File "src/myapp/__init__.py", line 22, in <module>
    p = importlib.import_module(settings_module)
  File "/home/yanez/devpython/lib/python2.6/site-packages/django/utils/importlib.py",   line 35, in import_module
    __import__(name)
ImportError: No module named src.myapp.nodjango_settings

I didn't expect that. When you create a new django application a manage.py file is created. And this file sets DJANGO_SETTINGS_MODULE the variable to the settings.py file from the perspective of the root directory of the application.

I read more code of django and realized that in django/core/management/__init__.py the root directory of the application is added to sys.path. This could also be the solution to my problem but I'm not quite sure whether it's a good idea to mess with sys.path or not.

I'm not quite sure whether my idea is a good one or a bad one. I'd like to know what you think about it and where/how I can improve it. Beside, if I stick to my idea, how can I read my custom varaibles in settings.py without having to reimport the settings module over and over?

Thanks

When deploying a django project with mod_wsgi, one have to write a wsgi (python) script, that does the "sys.path" dance and sets the DJANGO_SETTINGS_MODULE environment variable, then create the wsgi application object etc.

Why do I mention this ? Because, IMHO, you should not try to handle this part of the problem within "myapp", but from a distinct python script that would be the application entry point when using your app outside a django project context, and keep "myapp" as a pure library package. This launcher script would then take care of setting up the correct environement (sys.path, settings, whatever). For the record, the settings module is just a Python module, which at runtime is an ordinary python object (instance of class "module"), and there are quite a few ways (other than the default import mechanism) to create a module instance and add it to sys.modules (which is the important point here).

As a side note, having the settings in the packages doesn't make sense IMHO, it's a configuration file.

Edit : well, I knew there was something about using part of django standalone, and here it is: https://docs.djangoproject.com/en/dev/topics/settings/#using-settings-without-setting-django-settings-module