GeoDjango « Linfiniti Geo Blog

By: Linfiniti  11-11-2011

We do a lot of django work here at Linfiniti and always use a python virtual environment with each project so that the runtime requirements are isolated to that project. Our typical project looks like this:

projectfolder
+-- django_project
   +-- django_app
+-- python
   +-- bin
   +-- include
   +-- lib
   +-- local

..with an outer folder containing a python virtual environment and a django project with one or more django apps in it.

This works out great..until you need to change the name of your project. You can simply rename everything like this:

newfolder
+-- new_django_project
   +-- django_app
+-- python
   +-- bin
   +-- include
   +-- lib
   +-- local

Using mv and git mv. But the problem is that virtualenvs are not portable - they have the filesytem paths hard coded into them. Usually I just destroy the virtualenv and then recreate it, but in our low bandwidth office that takes quite a while. So today I came up with a formula to rename everything without rebuilding. There are four steps:

1) rename the outer project folder e.g.

 
mv projectfolder newfolder

2) rename the django project e.g.

git mv django_project new_django_project

3) use the linux 'rpl' command to replace all references to the old folder names (run from the root of the newfolder directory:

 rpl -R "projectfolder" "newfolder" *
 rpl -R "django_project" "new_django_project" *

4) remove all old pyc files:

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

This last step is the important one - if you don't do it python binary files will contain stale references to the old directory structure and you will see something like this if you try to do a runserver:

ValueError: bad marshal data (unknown type code)

Needless to say you should create a backup before attempting the above.

I've been working on a web site for a client that uses django flatpages. Flatpages is a built in component that allows users to create static content within the admin interface and publish it to the web front end. Think of it as a basic content management system component for django. Out of the box django's flatpages have some limitations though - you cannot easily dictate a sort order or heirachy for the pages. Let me demonstrate..

The old way:

Typically one might show a list of your flatpages on your website you would do something like this

{% load flatpages %} {# Custom tag defined in lib/templatetags/ #}
{% get_flatpages as flatpages %}
<ul>
{% for page in flatpages %}
 <li><a href="{{ page.url }}">{{ page.title }}</a></li>
{% endfor %}
</ul>

Which might generate some html rendered out like this:

Basic flat page listing

Extending the FlatPages model:

from django.db import models
from django.contrib.flatpages.models import FlatPage
class ExtendedFlatPage(FlatPage):
 show_after = models.ForeignKey('ExtendedFlatPage', \
  null=True, blank=True, default=None, \
  related_name="flatpage_predecessor", \
  help_text="Page that this one should appear after (if any)")
 child_of = models.ForeignKey('ExtendedFlatPage', \
  null=True, blank=True, default=None, \
  related_name="flatpage_parent", \
  help_text="Page that shis one should appear under (if any)")

So my new model adds two fields to the flatpages model that will allow me to define ordering and heirachy. The show_after field means that when I create a new flatpage, I can specify which other page the new page should be shown after. The child_of field can be used to state that the new page being added is a child of another page. A quick run of

python manage.py syncdb

Will go ahead and create the new table for your extended flat pages model. If we want to migrate existing flatpages into the new model, you can run a little query from the postgres command prompt like this:

insert into localsite_extendedflatpage (flatpage_ptr_id)
 select (id) from django_flatpage;

Where localsite_extendedflatpage is the table that was generated for your model (its name will vary depending on the name of your django app).

Registering the model in the admin interface:

To allow the user to administer the extended flat pages, you need to register your custom flatpages model with the admin interface and deregister the existing one (in admin.py):

from django.contrib import admin
from django.contrib.flatpages.admin import FlatpageForm, FlatPageAdmin
from django.contrib.flatpages.models import FlatPage

from models import ExtendedFlatPage

class ExtendedFlatPageForm(FlatpageForm):
 class Meta:
  model = ExtendedFlatPage
class ExtendedFlatPageAdmin(FlatPageAdmin):
 form = ExtendedFlatPageForm
 fieldsets = (
 (None, {'fields': ('url', 'title', 'content', \
     'sites', 'show_after', 'child_of' )}),
 )
admin.site.unregister(FlatPage)
admin.site.register(ExtendedFlatPage, ExtendedFlatPageAdmin)

After restarting your web server, you should now see the ExtendedFlatPages model listed in your admin interface, and it should show you our two custom fields which we use to define order and heirachy.

Admin interface for our customised flatpages model

Creating a custom template tag:

The next step in our journey is to create a custom templatetag that will render our listing of flatpages according to their heirachy and order. I added this to <myapp>/templatetags/local_tags.py :

So the template tag uses a simple recursive function to generate a heirachical nested collection of unordered lists (ul). The last thing I need to do is update my template that shows a listing of available flatpages to look something like this:

{% load local_tags %}

<div class = "flat-page-list">
  {% show_ordered_flatpages %}
</div>

The result:

After making the above changes, my contrived list of flatpages now looks like this when rendered:

Flatpages rendered using user defined order and nesting

A couple of gotchas:

My examples above do not check to see where the logged in user has the rights to view a page. Also my ExtendedFlatPages model needs to have some checks added to ensure that show_after and child_of fields can not be populated with a reference back to themselves (which would probably cause infinite recursion in my templatetag code).


Other products and services from Linfiniti

11-11-2011

Uncategorized « Linfiniti Geo Blog

I was lucky enough to be an intern earlier in the year, and am happy to be part of the team again, and helping in bringing Open Source GIS to Africa and other parts of the world. At one of my clients we manage a petabyte heirachical storage system and several high capacity SAN enclosures. I am also looking at doing a masters degree in the environmental field. Just an update to let you know that I have recently joined Linfiniti.


11-11-2011

QGIS « Linfiniti Geo Blog

Lately I have been delving deeper into the world of Microsoft Windows - specifically looking to be able to better support Windows users trying to get to grips with running FOSSGIS on that platform. Build all the dependencies yourself from scratch and then download GDAL from SVN and build against those dependencies. What happens here is that Openlayers uses the z-index CSS property for its own internal layer arrangements.