views:

338

answers:

3

I am in a team developing a web-based university portal, which will be based on Django. We are still in the exploratory stages, and I am trying to find the best way to lay the project/development environment out.

My initial idea is to develop the system as a Django "app", which contains sub-applications to separate out the different parts of the system. The reason I intended to make these "sub" applications is that they would not have any use outside the parent application whatsoever, so there would be little point in distributing them separately. We envisage that the portal will be installed in multiple locations (at different universities, for example) so the main app can be dropped into a number of Django projects to install it. We therefore have a different repository for each location's project, which is really just a settings.py file defining the installed portal applications, and a urls.py routing the urls to it.

I have started to write some initial code, though, and I've come up against a problem. Some of the code that handles user authentication and profiles seems to be without a home. It doesn't conceptually belong in the portal application as it doesn't relate to the portal's functionality. It also, however, can't go in the project repository - as I would then be duplicating the code over each location's repository. If I then discovered a bug in this code, for example, I would have to manually replicate the fix over all of the location's project files.

My idea for a fix is to make all the project repos a fork of a "master" location project, so that I can pull any changes from that master. I think this is messy though, and it means that I have one more repository to look after.

I'm looking for a better way to achieve this project. Can anyone recommend a solution or a similar example I can take a look at? The problem seems to be that I am developing a Django project rather than just a Django application.

+1  A: 

Hi

You should take a look at :

  • Django generic relations
  • Django reusable apps best practices if you want to re-use
  • GIT or any other CVS (git is great for maintaining + deployment)
  • Fabric if you need automated deployments/updates

I usually use this project structure :

  • /djangoproject
    • /apps
      • /main # the main code
      • /static # each sub app can serve statics
      • /app1
      • /static # each sub app can serve statics
      • /app2...
    • /scripts # manage.py, wsgi, apache.conf, fabfile.py...
    • /core # your libraries ...
    • settings.py
    • local_settings.py

Each app in /apps have an urls.py thats autoincluded in the main urls.py. And each app can be a git submodule (or svn external)

Also, using git, you can work on different parallels branches (master/dev/customerA/customerB...) and merge updates.

Creating real reusable is not so easy with django.

jujule
I'm using Mercurial for version control, and I use the local_settings trick also. My question was more about how to keep the projects separate, but still keep a central version controlled copy of the core code.
Rob Golding
+7  A: 

The best way that I have found to go about this is to create applications and then a project to glue them together. Most of my projects have similar apps which are included in each. Emails, notes, action reminders, user auth, etc. My preferred layout is like so:

  • project/
    • settings.py
    • urls.py
    • views.py
    • ...
  • apps/
    • emails/
      • urls.py
      • views.py
      • ...
    • notes/
      • urls.py
      • views.py
      • ...
    • ...

apps:

Each of the "apps" stands on its own, and other than a settings.py, does not rely on the project itself (though it can rely on other apps). One of the apps, is the user authentication and management. It has all of the URLs for accomplishing its tasks in apps/auth/urls.py. All of its templates are in apps/auth/templates/auth/. All of its functionality is self-contained, so that when I need to tweak something, I know where to go.

project:

The project/ contains all of the glue required to put these individual apps together into the final project. In my case, I made use heavy of settings.INSTALLED_APPS in project/ to discern which views from the apps were available to me. This way, if I take apps.notes out of my INSTALLED_APPS, everything still works wonderfully, just with no notes.

Maintenance:

This layout/methodology/plan also has long-term positive ramifications. You can re-use any of the apps later on, with almost no work. You can test the system from the bottom up, ensuring that each of the apps works as intended before being integrated into the whole, helping you find/fix bugs quicker. You can implement a new feature without rolling it out to existing instances of the application (if it isn't in INSTALLED_APPS, they can't see it).

I'm sure there are better documented ways of laying out a project, and more widely used ways, but this is the one which has worked best for me so far.

Jack M.
Upvoted with the caveat that apps can still have dependencies. That said, they should make sense. If you have comments, this has a dependencies on django's auth app. If you have a notification app, it might have a dependency on your emailing app. All of these dependencies should be well documented.
Justin Lilly
I understand how re-usable apps work in Django, but my problem is that my apps have absolutely no use whatsoever outside of this project - so how do I keep separate version controlled instances of similar code for the different locations?
Rob Golding
@Justin, you are correct. I wrote that poorly, thanks for pointing it out.@Rob, it depends on what functionality you are changing between the instances. If you are not changing the core functionality of a piece (such as authorization) then you can have auth be a stand-alone app, and how it is implemented would vary based on which project it is pulled into. This way auth doesn't need to fork, just the project itself.
Jack M.
@rob Sounds like you're looking for git submodules or svn externals?
Justin Lilly
I'm marking this as the accepted answer, as I have realised that what I am making is essentially a Django *project*, and not just a Django *application*. Therefore your project structure is a nice fit, and is very similar to that of the djangoproject.com website. Thanks!
Rob Golding
+2  A: 

You can extract the common functionality into a separate module and make your apps depend on it:

  • my_portal
  • auth_module
  • profiles_module
  • application1 (depends on auth_module)
  • application2 (depends on auth_module and profiles_module)

I think the fact that a 'classical' Django project appear to 'contain' the apps it's using prevent you from seeing the picture - in fact, it's not necessary. For a project where you're going to have some sort of pluggable modules I'd suggest organizing the apps as eggs and using zc.buildout+djangorecipe to manage everything.

This way you'll be able to keep your modules in a flat one-level structure. Eggs have the ability to specify dependencies, so if you install application1 (see above), auth_module will be installed automatically.

Also it'll be easy to have different configurations deployed to different servers. Suppose, you have server1 which has application1 installed and server2 which has both application1 and application2 installed - you can just have two configs:

server1.cfg:

[buildout]
extends = base_deployment.cfg
eggs += application1

server2.cfg:

[buildout]
extends = base_seployment.cfg
eggs += application1
        application2

djangorecipe also allows you to specify different settings files for each buildout config so you'll be able to add the necessary bits to the main project's urls and installed apps settings.

Not to mention, you can also have a separate config for development configuration (with debug=True and Django Debug Toolbar installed, for example).

Sergey
I didn't know about buildout, so thanks for mentioning that. I'm still not sure I've found the best way to do this though - I'm not particularly interested in different "permutations" of my project, it will generally be the same everywhere. I just need to be able to change the title, for example, and override templates where necessary.
Rob Golding
It's not only about "permutations":- djangorecipe allows you to specify which settings file to use, so you can override stuff on a per-installation basis in a nice, clean and version-controlled way (i.e. settings_production.py says "from settings import *; DEBUG=False" and settings_dev.py says "from settings import *; DEBUG=True"- buildout allows you to control which versions of third-party (and your own) modules are getting installed so you can create installations repeatably- it installs everything locally without polluting system python directories (similar to virtualenv but nicer)
Sergey