<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>blog.elsdoerfer.name &#187; Django</title>
	<atom:link href="http://blog.elsdoerfer.name/category/django/feed/" rel="self" type="application/rss+xml" />
	<link>http://blog.elsdoerfer.name</link>
	<description>Contributing back to the Google Index.</description>
	<lastBuildDate>Wed, 11 Aug 2010 17:14:20 +0000</lastBuildDate>
	<generator>http://wordpress.org/?v=2.8</generator>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
			<item>
		<title>Django Tree Libraries</title>
		<link>http://blog.elsdoerfer.name/2010/02/28/django-tree-libraries/</link>
		<comments>http://blog.elsdoerfer.name/2010/02/28/django-tree-libraries/#comments</comments>
		<pubDate>Sun, 28 Feb 2010 05:58:31 +0000</pubDate>
		<dc:creator>admin</dc:creator>
				<category><![CDATA[Django]]></category>

		<guid isPermaLink="false">http://blog.elsdoerfer.name/?p=177</guid>
		<description><![CDATA[django-mptt

Nested Set trees.
A register() call is used to set things up; it ads the necessary fields to the model.
A tree model still has a foreign key to itself. This is the API you use to manage the tree. Signals are used that the hidden tree fields are updated when the parent ForeignKey changes. No add_child() [...]]]></description>
			<content:encoded><![CDATA[<p><a href="http://code.google.com/p/django-mptt/">django-mptt</a></p>
<ul>
<li>Nested Set trees.</li>
<li>A <em>register()</em> call is used to set things up; it ads the necessary fields to the model.</li>
<li>A tree model still has a foreign key to itself. This is the API you use to manage the tree. Signals are used that the hidden tree fields are updated when the parent ForeignKey changes. No add_child() required.</li>
<li>Using the foreign key to self means that deletion is handled automatically be Django and/or the database. The other libraries need to implement a custom Queryset subclass to handle deletes.</li>
</ul>
<p><a href="http://code.tabo.pe/django-treebeard/">django-treebeard</a></p>
<ul>
<li>Has an awesome name.</li>
<li>In addition to the common <em>Nested Set/MPTT</em> approach, supports two other tree implementations. <em>Materialized Path</em> in particular is interesting.</li>
<li>You inherit your models from abstract base classes, which I like.</li>
<li>The tree has to be managed manually, that is, there are specific APIs like <em>add_child()</em> you have to call.</li>
<li>Unfortunately, those APIs are classmethods on the model rather than the Django-way, putting them into the model manager.</li>
</ul>
<p><a href="http://bitbucket.org/fivethreeo/django-easytree/">django-easy-tree</a></p>
<ul>
<li>Apparently a fork of django-treebeard, but only supports Nested Set trees.</li>
<li>But has a prettier API that fits very well into Django: Nicer class names, properly puts methods into the manager when they belong there, options are specified inside "Meta" rather than on the model itself.</li>
<li>Has an interesting concept of validators. Included is a <em>SingleRootAllowedValidator</em>.</li>
<li>No tests!</li>
</ul>
<p>Clearly, somebody needs to write a django-treebeard that uses the django-easy-tree API design and django-mptt's signal approach.</p>
]]></content:encoded>
			<wfw:commentRss>http://blog.elsdoerfer.name/2010/02/28/django-tree-libraries/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>Django: Flexible date form fields accepting (almost) any input</title>
		<link>http://blog.elsdoerfer.name/2009/12/12/django-flexible-date-form-fields-accepting-almost-any-input/</link>
		<comments>http://blog.elsdoerfer.name/2009/12/12/django-flexible-date-form-fields-accepting-almost-any-input/#comments</comments>
		<pubDate>Sat, 12 Dec 2009 06:25:12 +0000</pubDate>
		<dc:creator>admin</dc:creator>
				<category><![CDATA[Django]]></category>

		<guid isPermaLink="false">http://blog.elsdoerfer.name/?p=138</guid>
		<description><![CDATA[At critify, we do a lot of copy &#038; paste. Sometimes, that means copy &#038; pasting a date from another site into a Django DateTimeField on our site. This can be tedious, because Django only supports a fixed number of strict input formats, while the actual input can at times be something quite freeform. So [...]]]></description>
			<content:encoded><![CDATA[<p>At <a href="http://critify.de">critify</a>, we do a lot of copy &#038; paste. Sometimes, that means copy &#038; pasting a date from another site into a Django <a href="http://docs.djangoproject.com/en/dev/ref/forms/fields/#datetimefield">DateTimeField</a> on our site. This can be tedious, because Django only supports a fixed number of strict input formats, while the actual input can at times be something quite freeform. So I decided that what was needed were date form fields that would make a good attempt at parsing the input.</p>
<p>Here's what you need:</p>
<ul>
<li><a href="http://labix.org/python-dateutil">python-dateutil</a>, which provides the parser.</li>
<li><a href="http://bitbucket.org/miracle2k/djutils/src/468ecaa38255/djutils/forms/fields/dateutil.py">This file</a>, which implements <em>DateTimeField</em> and <em>DateField</em> form field classes which use <em>python-dateutil</em> to process the input.</li>
</ul>
<p>With that available, the actual code is quite simple:</p>
<pre name="code" class="python">
from djutils.forms.fields import formfield_callback

class YourForm(ModelForm):
    formfield_callback = formfield_callback
    class Meta:
        model = YourModel
</pre>
<p>The <em>formfield_callback</em> will ensure that for every <em>DateField</em> or <em>DateTimeField</em> that your model has, the appropriate form field with dateutil-parsing support will be generated.</p>
<p>Of course, you can use these fields manually as well:</p>
<pre name="code" class="python">
from django import forms
from djutils.forms.fields import DateField

class MyForm(forms.Form):
    std_date = forms.DateField() # < - Uses the standard DateField
    parsed_date = DateField()  # <- Uses the custom DateField
</pre>
<p>This should work well enough; we can now put something like <em>8th of January</em> into the form, and it'll be parsed into the correct date.</p>
<p><em>"8th of January"</em>? My site is in German! Fortunately, while not supporting it out of the box, <em>python-dateutil</em> is flexible enough to allow for internationalization as well. You need to get:</p>
<ul>
<li><a href="http://bitbucket.org/miracle2k/pyutils/src/tip/pyutils/date/__init__.py">Yet another file</a>, which adds support for German date strings to <em>python-dateutil</em> (i.e. "Janauar", "Montag", ....). If you need to support a different language, you can use that file as a template.</li>
</ul>
<p>The way internationalization is done with <em>python-dateutil</em> is that you implement a <em>parserinfo</em> class for a given language. We need to tell our custom form fields to use the German parserinfo provided by the file above:</p>
</pre>
<pre name="code" class="python">
from djutils.forms.fields import get_formfield_for
from pyutils.date import GermanParserInfo

class YourForm(ModelForm):
    def formfield_callback(field):
         # If it's a date-related field, get one of our custom form fields
         result = get_formfield_for(field, parserinfo=GermanParserInfo())
         # Otherwise, use the default form field.
         return result or field.formfield()
    class Meta:
        model = YourModel
</pre>
<p>That's basically it. You might want to create a base form class that you can inherit from for DRY purposes.</p>
<p>By the way, my module containing the German parser info also has a <em>MultiParserInfo</em> helper that may be useful to some:</p>
<pre name="code" class="python">
parserinfo=MultiParserInfo(parsers=[GermanParserInfo()])
</pre>
<p>This will give you a parser that supports both German date names, and the original English date names as a fallback. If you need to support even more languages, you could too:</p>
<pre name="code" class="python">
parserinfo=MultiParserInfo(parsers=[GermanParserInfo(), FrenchParserInfo()])
</pre>
]]></content:encoded>
			<wfw:commentRss>http://blog.elsdoerfer.name/2009/12/12/django-flexible-date-form-fields-accepting-almost-any-input/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>Properly sending contact form emails and how to do it in Django</title>
		<link>http://blog.elsdoerfer.name/2009/11/09/properly-sending-contact-form-emails-and-how-to-do-it-in-django/</link>
		<comments>http://blog.elsdoerfer.name/2009/11/09/properly-sending-contact-form-emails-and-how-to-do-it-in-django/#comments</comments>
		<pubDate>Mon, 09 Nov 2009 13:41:18 +0000</pubDate>
		<dc:creator>admin</dc:creator>
				<category><![CDATA[Django]]></category>

		<guid isPermaLink="false">http://blog.elsdoerfer.name/?p=84</guid>
		<description><![CDATA[Ever since I decided to use SpamStopsHere (their excellent, by the way) I noticed that some emails sent to me by one of my site's contact form didn't pass their SPF check.
It turns out that apart from your normal "From" sender, an email message also has an envelope sender specified in the Return-Path header. The [...]]]></description>
			<content:encoded><![CDATA[<p>Ever since I decided to use <a href="http://spamstopshere.com/">SpamStopsHere</a> (their excellent, by the way) I noticed that some emails sent to me by one of my site's contact form didn't pass their <a href="http://en.wikipedia.org/wiki/Sender_Policy_Framework">SPF</a> check.</p>
<p>It turns out that apart from your normal "<em>From</em>" sender, an email message also has an <a href="http://en.wikipedia.org/wiki/Bounce_address">envelope sender</a> specified in the <em>Return-Path</em> header. The first is considered to be the author, the second refers to who is responsible for actually sending the message.</p>
<p>So my site sent those contact form emails to me using as the sender whatever the user specified as his email address in the form - in both the <em>From</em> and <em>Return-Path</em> path fields. Whenever the user's email domain had SPF records installed, the validation would run the user's email against my mail servers and thus obviously fail.</p>
<p>The solution then is to use as the <em>Return-Path</em> an address of your own. How to do this in Django? It's really simple, but totally non-obvious. This is per <a href="http://code.djangoproject.com/ticket/9214">Ticket 9214</a> and <a href="http://code.djangoproject.com/changeset/9842">Changeset 9842</a> (so you need at least 1.1).</p>
<pre name="code" class="python">
connection = SMTPConnection(fail_silently=fail_silently)
headers = {'From': 'users@email.address'}  # From-header
from_email = 'bounce@mysite.com'           # Return-Path header
EmailMessage(subject, message, from_email, recipient_list,
                   connection=connection, headers=headers).send()
</pre>
<p>Note that we need to work with ``EmailMessage`` directly - <code>django.core.mail.send_mail</code> doesn't provide an option for custom headers.</p>
<p>If you are using <a href="http://bitbucket.org/ubernostrum/django-contact-form/">django-contact-form</a>, it unfortunately doesn't support custom headers out of the box either, so you need to apply <a href="http://bitbucket.org/miracle2k/django-contact-form/changeset/97e82ad7e8d3/">a patch</a>. Then, the following should work:</p>
<pre name="code" class="python">
class MyContactForm(AkismetContactForm):
    def __init__(self, *args, **kwargs):
        super(self.__class__, self).__init__(*args, **kwargs)
            self.subject = "Contact Form"
            self.template_name = "site/pages/contact_email.txt"
            # Return-Path header, e.g. bounce@mysite.com
            self.from_email = settings.DEFAULT_FROM_EMAIL
            # From-header
            self.headers = \
                lambda: {'From': "%s < %s>" %
                    (self.cleaned_data['name'], self.cleaned_data['email'])}
</pre>
]]></content:encoded>
			<wfw:commentRss>http://blog.elsdoerfer.name/2009/11/09/properly-sending-contact-form-emails-and-how-to-do-it-in-django/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>quick update: django-assets now supporting Jinja 2</title>
		<link>http://blog.elsdoerfer.name/2008/10/28/quick-update-django-assets-now-supporting-jinja-2/</link>
		<comments>http://blog.elsdoerfer.name/2008/10/28/quick-update-django-assets-now-supporting-jinja-2/#comments</comments>
		<pubDate>Tue, 28 Oct 2008 18:46:55 +0000</pubDate>
		<dc:creator>admin</dc:creator>
				<category><![CDATA[Django]]></category>

		<guid isPermaLink="false">http://blog.elsdoerfer.name/2008/10/28/quick-update-django-assets-now-supporting-jinja-2/</guid>
		<description><![CDATA[Since I've been playing a round with Jinja a bit the last few days, I needed django-assets to support it as well. So it can now be used with both Django and Jinja templates, even simultaneously. So far, the code is only in bzr, not packaged up. Details in the Readme, though it's all pretty [...]]]></description>
			<content:encoded><![CDATA[<p>Since I've been playing a round with Jinja a bit the last few days, I needed <a href="https://launchpad.net/django-assets">django-assets</a> to support it as well. So it can now be used with both Django and Jinja templates, even simultaneously. So far, the <a href="https://code.launchpad.net/django-assets">code is only in bzr</a>, not packaged up. Details in the Readme, though it's all pretty straightforward.</p>
<p>I initially had some trouble porting the Django template tag to a Jinja extension, partly due a seemingly limited number of examples out there - so if you're in the same boat, maybe this will help.</p>
]]></content:encoded>
			<wfw:commentRss>http://blog.elsdoerfer.name/2008/10/28/quick-update-django-assets-now-supporting-jinja-2/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Django: Testing with twill</title>
		<link>http://blog.elsdoerfer.name/2008/09/24/django-testing-with-twill/</link>
		<comments>http://blog.elsdoerfer.name/2008/09/24/django-testing-with-twill/#comments</comments>
		<pubDate>Wed, 24 Sep 2008 08:53:03 +0000</pubDate>
		<dc:creator>admin</dc:creator>
				<category><![CDATA[Django]]></category>

		<guid isPermaLink="false">http://blog.elsdoerfer.name/2008/09/24/django-testing-with-twill/</guid>
		<description><![CDATA[After putting it off again and again, I decided that it would be finally time to make an effort and start writing some actual tests for my views (rather than just the code behind them). Beyond Django's neat, but somewhat limited test client, the tool to do this seems to be twill.
Twill supports a WSGI intercept [...]]]></description>
			<content:encoded><![CDATA[<p>After putting it off again and again, I decided that it would be finally time to make an effort and start writing some actual tests for my views (rather than just the code behind them). Beyond Django's neat, but somewhat limited <a href="http://docs.djangoproject.com/en/dev/topics/testing/#module-django.test.client">test client</a>, the tool to do this seems to be <a href="http://twill.idyll.org/">twill</a>.</p>
<p>Twill supports a WSGI intercept that can be hooked up to Django, bypassing the need to go through the network. There's an entry on <a href="http://www.djangosnippets.org/snippets/665/">django snippets</a> that shows how to use this in context of unit tests.</p>
<p>I've slightly improved upon it to remove the need to deal with the local dummy host in urls. I also added a login/logout feature, as known from the Django's own test client. The result can be found on <a href="http://www.bitbucket.org/miracle2k/djutils/src/tip/djutils/test/twill.py">BitBucket</a>.</p>
<p>Quick example:</p>
<pre name="code" class="python">from djutils.test import twill

# install the wsgi hook
twill.setup()

try:
    # those will go to Django
    twill.go('/')
    twill.follow('login')
    twill.code(200)

    # once we're browsing away...
    twill.go('http://google.com')
    # ...urls will be relative to that
    twill.go('/services')
    # now at http://google.com/services

    # default=True brings us back to Django
    twill.go('/list', default=True)

    # you can also pass along reverse args
    twill.go('proj.app.views.func', args=[1,2,3])

    # login as some user
    twill.login(username="foo", passwort="bar")
    twill.go('/django_admin')
    twill.logout()

    # alternative: login without credentials
    any_admin = User.objects.filter(is_superuser=True)[0]
    twill.login(user=any_admin)
finally:
    twill.teardown()</pre>
<p>For the benefit of people searching for this, I should also mention that when calling <em>twill.setup()</em>, a workaround is applied to make twill function with documents documents that identify themselves as XHTML. Per default, twill explicitly fails on those with a <em>"Not viewing html"</em> error. Looking at the source, this is apparently because support for XHTML is considered incomplete and/or broken. However, at least for two XTHML sites of mine everything seems to work just fine.</p>
<p>Finally, I recommend you set <em>DEBUG_PROPAGATE_EXCEPTIONS = True</em> while testing with twill, as <a href="http://groups.google.com/group/django-developers/browse_thread/thread/89590ae35abcaf8a?fwc=1">explained here</a>. Otherwise, not only will debugging tests be more difficult, in some instances tests failures may easily go unnoticed (imagine you're testing for string containment, but inadvertently dealing with your 404 or 500 error page).</p>
]]></content:encoded>
			<wfw:commentRss>http://blog.elsdoerfer.name/2008/09/24/django-testing-with-twill/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Making a copy of a model instance</title>
		<link>http://blog.elsdoerfer.name/2008/09/09/making-a-copy-of-a-model-instance/</link>
		<comments>http://blog.elsdoerfer.name/2008/09/09/making-a-copy-of-a-model-instance/#comments</comments>
		<pubDate>Tue, 09 Sep 2008 13:52:04 +0000</pubDate>
		<dc:creator>admin</dc:creator>
				<category><![CDATA[Django]]></category>

		<guid isPermaLink="false">http://blog.elsdoerfer.name/2008/09/09/making-a-copy-of-a-model-instance/</guid>
		<description><![CDATA[Copying a model instance, i.e. creating a new database row based on an existing one (copying all the data except the primary key), doesn't seem to be a very common need - it's not directly supported by the Django ORM, and Google doesn't turn much up, either.
But maybe that's because, in most cases, it really [...]]]></description>
			<content:encoded><![CDATA[<p>Copying a model instance, i.e. creating a new database row based on an existing one (copying all the data except the primary key), doesn't seem to be a very common need - it's not directly supported by the Django ORM, and Google doesn't turn much up, either.</p>
<p>But maybe that's because, in most cases, it really is pretty simple:</p>
<pre name="code" class="python">&gt;&gt;&gt; obj = Model.objects.get(pk=1)
&gt;&gt;&gt; obj.pk = None    # (or: obj.id=None)
&gt;&gt;&gt; obj.save()
&gt;&gt;&gt; obj.pk
2</pre>
<p>That's how I've done it myself in the past. However, it turns out that this doesn't work when model inheritance is used. When copying a subclass model, <em>obj.id</em> refers to the parent model object's primary key, and <em>obj.pk</em> points to the parent_link OneToOne relationship. Both need to be nulled for a copy to be created, otherwise the <em>save()</em> logic will cause the missing one to be reset to the original value (I haven't gone through all of the code, but that seems to be the effect).</p>
<pre name="code" class="python">&gt;&gt;&gt; obj = SubclassModel.objects.get(pk=1)
&gt;&gt;&gt; obj.pk = None
&gt;&gt;&gt; obj.id = None
&gt;&gt;&gt; obj.save()
&gt;&gt;&gt; obj.pk
2</pre>
<p>While that works, I felt like it would be relying on implementation details a bit too much, so currently I am using this function:</p>
<pre name="code" class="python">from django.db.models import AutoField
def copy_model_instance(obj):
    """Create a copy of a model instance.

    M2M relationships are currently not handled, i.e. they are not
    copied.

    See also Django #4027.
    """
    initial = dict([(f.name, getattr(obj, f.name))
                    for f in obj._meta.fields
                    if not isinstance(f, AutoField) and\
                       not f in obj._meta.parents.values()])
    return obj.__class__(**initial)</pre>
<p>Which basically initializes a new model instance with the data from the old, while leaving out all id and parent link fields. For example:</p>
<pre name="code" class="python">&gt;&gt;&gt; obj = SubclassModel.objects.get(pk=1)
&gt;&gt;&gt; obj = copy_model_instance(obj)
&gt;&gt;&gt; obj.save()
&gt;&gt;&gt; obj.pk
&gt;&gt;&gt; 2</pre>
<p>So far it works great, and I'm pretty happy with it - I'd love to hear other ideas, though.</p>
]]></content:encoded>
			<wfw:commentRss>http://blog.elsdoerfer.name/2008/09/09/making-a-copy-of-a-model-instance/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>django-xappy: Searching with Xapian</title>
		<link>http://blog.elsdoerfer.name/2008/08/13/django-xappy-searching-with-xapian/</link>
		<comments>http://blog.elsdoerfer.name/2008/08/13/django-xappy-searching-with-xapian/#comments</comments>
		<pubDate>Wed, 13 Aug 2008 21:39:36 +0000</pubDate>
		<dc:creator>admin</dc:creator>
				<category><![CDATA[Django]]></category>

		<guid isPermaLink="false">http://blog.elsdoerfer.name/2008/08/13/django-xappy-searching-with-xapian/</guid>
		<description><![CDATA[Yes, yet another search app.  However, unlike other projects, say this year's GSoC project, it doesn't try to be generic. Rather, it is specific to Xapian, making it possible to make full use of all the advanced features the excellent Xappy library offers. Xappy is a high-level interface to Xapian (as opposed to the [...]]]></description>
			<content:encoded><![CDATA[<p>Yes, yet another search app.  However, unlike other projects, say this year's <a href="http://code.google.com/p/djangosearch/">GSoC project</a>, it doesn't try to be generic. Rather, it is specific to <a href="http://www.xapian.org/">Xapian</a>, making it possible to make full use of all the advanced features the excellent <a href="http://code.google.com/p/xappy">Xappy library</a> offers. Xappy is a high-level interface to Xapian (as opposed to the tedious-to-use lowlevel Python bindings), and supports some pretty nice stuff like facets, tags or ranges.</p>
<p>Yes, I also know about <a href="src/djapian/backend/text.py">djapian</a>, but... I really wanted to use Xappy!</p>
<p>So, here's how it works. First, define your index (note that since I really built this for my own use where indexes usually span multiple models, it might not be as simple as it could be if you want to search through only one - at least, right now).</p>
<pre name="code" class="python">
from django_xappy import Index, action, FieldActions

class MyIndex(Index):
    location = '/var/www/mysite/search-index'

    class Data:
        @action(FieldActions.INDEX_FREETEXT, spell=True, language="en")
        @action(FieldActions.STORE_CONTENT)
        def name(self):
            if self == auth.models.User:
                return self.content_object.username  

        @action(FieldActions.SORTABLE, type="date")
        def date(self):
            if self == app.models.Book:
                return self.content_object.released_at
            elif self == user:
                return self.content_object.date_joined

MyIndex.register(Book)
MyIndex.register(auth.models.User)</pre>
<p>This says where the index lives, what fields it has, what Xappy actions to use for each, and from where to get the data for those fields (note that not all models have to provide data for each field).</p>
<p>Now, the way django-xappy works is, it logs all changes in a database table instead of updating the index directly. This means that your index won't always be up-to-date, but also, that the rest of your site's functionality will never be affected by troubles with your search engine. Instead, you regularly apply the changes to your index (e.g. using a cronjob). The easiest way to do that is using the management command.</p>
<p>Let's create the index for the first time:</p>
<pre name="code">PS G:\...\trunk\examples\simple&gt; .\manage.py index --full-rebuild
Creating a new index in "index-1218575904"...
Indexing 11 objects of type "Book"...
Indexing 2 objects of type "User"...
Switching "index-1218575904" to live index...
Done.</pre>
<p>Then, after doing some changes, say in the admin:</p>
<pre name="code">PS G:\...\trunk\examples\simple&gt; .\manage.py index --update
Updating 1 index with 18 changes...
Done.</pre>
<p>Good. Now that we have an up to date index, let's search:</p>
<pre name="code" class="python">results = search("searchterm", page=1, num_per_page=10)</pre>
<p>Pass <em>results</em> to your template:</p>
<pre name="code" class="html">    {% if results %}
        {% for result in results %}
            {{ result.content_object }}
        {% endif %}
    {% endif %}</pre>
<p>Done! For more information, see the <a href="http://bazaar.launchpad.net/~miracle2k/django-xappy/trunk/annotate/head:?file_id=readme-20080812193821-sdqgd4zomyaoif88-1">readme</a> - and don't forget to check out the <a href="http://code.google.com/p/xappy/source/browse/trunk/docs/">Xappy docs</a> as well.</p>
<p>As usual, the code is available on <a href="https://launchpad.net/django-xappy">Launchpad</a> - and now also <a href="http://pypi.python.org/pypi/django-xappy/">PyPi</a>. Via <em>bzr</em>:</p>
<pre>bzr branch lp:django-xappy</pre>
<p>For questions and support, use the <a href="http://groups.google.com/group/django-apps">django-apps Google Group</a> and prefix your message with <em>(xappy)</em>.</p>
]]></content:encoded>
			<wfw:commentRss>http://blog.elsdoerfer.name/2008/08/13/django-xappy-searching-with-xapian/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>django-tables: A QuerySet renderer</title>
		<link>http://blog.elsdoerfer.name/2008/07/09/django-tables-a-queryset-renderer/</link>
		<comments>http://blog.elsdoerfer.name/2008/07/09/django-tables-a-queryset-renderer/#comments</comments>
		<pubDate>Wed, 09 Jul 2008 13:53:10 +0000</pubDate>
		<dc:creator>admin</dc:creator>
				<category><![CDATA[Django]]></category>

		<guid isPermaLink="false">http://blog.elsdoerfer.name/2008/07/09/django-tables-a-queryset-renderer/</guid>
		<description><![CDATA[While trying to add a simple sorting feature to the critify game listing, I went off on a strange train of thought involving a bunch of future functionality I only have a very vague picture of, and decided that it would be best to choose the most complex approach possible and create a separate, overarchitected [...]]]></description>
			<content:encoded><![CDATA[<p>While trying to add a simple sorting feature to the <a href="http://critify.de/games/">critify game listing</a>, I went off on a strange train of thought involving a bunch of future functionality I only have a very vague picture of, and decided that it would be best to choose the most complex approach possible and create a separate, overarchitected abstraction layer for that very purpose.</p>
<p>Well, something like that, though hopefully not quite as bad. Basically, the idea is:</p>
<ul>
<li>to making rendering tabular data a little easier by encapsulating some repetitive parts.</li>
<li>make working with tabular data a lot easier when it comes to the user interacting with the table.</li>
</ul>
<p>You would define a table, which is sort of a cross between a model and a form, define it's columns (i.e. fields), and then tell it how you want to sort, filter and group the data.</p>
<p>Some snippets of actual code should probably explain it best.</p>
<p>First, let's define a table:</p>
<pre name="code" class="python">import django_tables as tables

class BookTable(tables.ModelTable):
    id = tables.Column(sortable=False, visible=False)
    book_name = tables.Column(name='title')
    author = tables.Column(data='author__name')
    class Meta:
        model = Book</pre>
<p>The table is based on the <em>Book</em> model; thus, it will have a column for each model field, and in addition the locally defined columns will override the default ones, or add to them, very much like newforms works (you'll find that even the internals are at times very similar to the newforms code).</p>
<p>So, now that we have defined the table, let's create an instance:</p>
<pre name="code" class="python">initial_queryset = Book.objects.all()
books = BookTable(
         initial_queryset,
         order_by=request.GET.get('sort', 'title'))</pre>
<p>We tell the table to operate on the full book data set, and to order it by whatever the user sends along via the query string, or fall back to the default sort order based on the <em>title</em> (<em>book_name</em>) column.</p>
<p>Finally, you would send the table to the template:</p>
<pre name="code" class="python">return render_to_response('table.html', {'table': books})</pre>
<p>Where it is easy to print it out:</p>
<pre name="code" class="html">&lt;table&gt;

&lt;tr&gt;
  {% for column in table.columns %}
  &lt;th&gt;
    {% if column.sortable %}
      &lt;a href="?sort={{ column.name_toggled }}"&gt;
        {{ column }}
      &lt;/a&gt;
      {% if column.is_ordered_reverse %}
        &lt;img src="up.png" /&gt;
      {% else %}
        &lt;img src="down.png" /&gt;
      {% endif %}
    {% else %}
      {{ column }}
    {% endif %}
  &lt;/th&gt;
  {% endfor %}
&lt;/tr&gt;

{% for row in table.rows %}
  &lt;tr&gt;
  {% for value in row %}
    &lt;td&gt;{{ value }}&lt;td&gt;
  {% endfor %}
  &lt;/tr&gt;
{% endfor %}

&lt;/table&gt;</pre>
<p>The above template code generically renders any table you give it, restricted to it's visible columns, and allows each column to be sorted in ascending or descending order (so long sorting is not disabled for a column). It gives you those nice arrow icons too.</p>
<p>At this point you will probably wonder if it's not <strong>a lot</strong> simpler to just say:</p>
<pre name="code" class="python">Books.objects.all().order_by(request.GET.get('sort'))</pre>
<p>And you'd be right, it is, and I indicated as much at the beginning of the post. There are however a couple of nice things about the table abstraction:</p>
<ul>
<li>While Django's ORM already protects you against SQL injections, you still might like to play it safe and limit the possible values of the <em>sort</em> parameter (which will also ensure users won't be able to guess your database schema by trying different values). Using django-tables, this is built in.</li>
<li>It easily allows you to expose your fields under a different name, e.g. <em>date</em> instead of<em> published_at</em>. True, it's just cosmetics, but personally I am (probably unhealthily) particular about stuff like that.</li>
<li>Both previous points are especially relevant when you want to order via a relationship, e.g. <em>author__birthdate</em>. The double underscore doesn't look all that nice, gives a rather clear insight into your database layout and also exposes that you are using Django, which may be undesirable.</li>
<li>It easily allows you to move control over what fields to expose from your templates into python. Your templates will need to deal to a lesser extend with what to render, but rather on how to render it.</li>
<li>Boilerplate code required to let the user sort the table, particularly when it comes to allowing toggling between descending/ascending, or even multiple sort fields, is reduced.</li>
</ul>
<p>Additionally, it might be worth noting that there is a non-model implementation as well (use <em>Table</em> instead of <em>ModelTable</em>), that bascially does the same thing with static python data, e.g. a list of dicts.</p>
<p>To be perfectly honest, at this point I have no idea myself if much of this makes any sense or how useful it actually is. The fact that I haven't really thought that much beyond the (already implemented) sorting functionality is not helping either (i.e. grouping, filtering...). I am going to toy with it for a bit though, and you are invited to do so too.</p>
<p>The project is maintained in bazaar and can be retrieved via <a href="https://launchpad.net/django-tables">Launchpad</a>:</p>
<blockquote>
<pre>bzr branch lp:django-tables</pre>
</blockquote>
<p>There is also a <a href="http://bazaar.launchpad.net/~miracle2k/django-tables/trunk/files">source code browser</a>, where you'll also find the readme with a lot more information.</p>
<p>For questions/discussions/support use the <a href="http://groups.google.com/group/django-apps">django-apps</a> Google Group and prefix your message with <em>(tables)</em>.</p>
]]></content:encoded>
			<wfw:commentRss>http://blog.elsdoerfer.name/2008/07/09/django-tables-a-queryset-renderer/feed/</wfw:commentRss>
		<slash:comments>15</slash:comments>
		</item>
		<item>
		<title>django-assets</title>
		<link>http://blog.elsdoerfer.name/2008/06/13/django-assets/</link>
		<comments>http://blog.elsdoerfer.name/2008/06/13/django-assets/#comments</comments>
		<pubDate>Thu, 12 Jun 2008 23:37:40 +0000</pubDate>
		<dc:creator>admin</dc:creator>
				<category><![CDATA[Django]]></category>

		<guid isPermaLink="false">http://blog.elsdoerfer.name/2008/06/13/django-assets/</guid>
		<description><![CDATA[There are already a couple asset management addons for Django out there, and so I feel somewhat bad for coming up with another one.
In my defense, non of the other approaches appealed to me: django-yslow apparently simply searches recursively through the project directory, finding media files and merging them into one single package. django-assetpacker has [...]]]></description>
			<content:encoded><![CDATA[<p>There are already a couple asset management addons for Django out there, and so I feel somewhat bad for coming up with another one.</p>
<p>In my defense, non of the other approaches appealed to me: <a href="http://github.com/mallipeddi/django-yslow/">django-yslow</a> apparently simply searches recursively through the project directory, finding media files and merging them into one single package. <a href="http://code.google.com/p/django-assetpackager/">django-assetpacker</a> has you define your assets in the database, which is a definite no-go for me. The database is installation-specific data, my media file configuration I consider to be application/project data (although I realize that that could be argued). Finally, <a href="http://code.google.com/p/django-compress/">django-compress</a> uses the settings file for setup, which, while better, I'm still not all that happy with either.</p>
<p>So what then, you ask, do I want? See, right now, the only thing that references my JS and CSS files are my templates (only a limited number of base templates in fact). I'd like it to stay this way, i.e. assets should be defined and created solely through templates. So for example:</p>
<pre name="code" class="html">{% load assets %}
{% assets filter="jsmin" output="packed.js" "jquery.js" "common/file1.js" %}
    &lt;script type="text/javascript" src="{{ ASSET_URL }}"&gt;&lt;/script&gt;
{% endassets %}</pre>
<p>Which would merge <em>jquery.js</em> and <em>file1.js,</em> apply jsmin and store the result as <em>packed.js</em>. Since the tag simply renders it's contents using the right ASSET_URL, you are free to reference your media files any way you want to, e.g. specify the correct media-type for CSS files.</p>
<p>Changes to the source files can automatically be detected (only by timestamp, right now), and the assets recreated. As an alternative, there is a management command that can be used to update manually:</p>
<pre name="code">./manage.py assets rebuild --parse-templates</pre>
<p>As you can see from the command line, and this is the approach's downside, since there is now no central repository of available assets, the command needs to parse your templates and look for usage of the assets tag. I find that a bearable compromise, however.</p>
<p>I've implemented a couple of the more popular minifiers and compressors, including YUI, jsmin, jspacker and <a href="http://cthedot.de/cssutils/">cssutils</a>. GZip is supported as well, and you can apply multiple filters:</p>
<pre name="code" class="html">{% assets filter="jsmin,gzip" ... %}</pre>
<p>Another notworthy feature might be the ability to rewrite relative urls in CSS files. If your output file is in a different location than your CSS source files, relative url() references will break. The cssrewrite filter will fix this:</p>
<pre name="code" class="html">{% assets filter="cssrewrite,yui_css" output="cache/default.css" common/base.css extjs/css/extjs-all.css %}</pre>
<p>I've put the whole thing up as a <a href="http://code.google.com/p/django-assets/">Google Code project</a>. I've also created a Google Group and since I'm planning on releasing a couple other things in the future, generically called it <a href="http://groups.google.com/group/django-apps">django-apps</a> - I don't see the point of having a dozen empty groups, not to mention the inconvenience of jumping between them all. Feel free to use the group for your own projects - I suggest messages should be prefixed with <em>(appname),</em> e.g. <em>(assets).</em></p>
]]></content:encoded>
			<wfw:commentRss>http://blog.elsdoerfer.name/2008/06/13/django-assets/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>Django: Finding the current project&#039;s path</title>
		<link>http://blog.elsdoerfer.name/2008/06/06/django-finding-the-current-projects-path/</link>
		<comments>http://blog.elsdoerfer.name/2008/06/06/django-finding-the-current-projects-path/#comments</comments>
		<pubDate>Fri, 06 Jun 2008 12:30:13 +0000</pubDate>
		<dc:creator>admin</dc:creator>
				<category><![CDATA[Django]]></category>

		<guid isPermaLink="false">http://blog.elsdoerfer.name/2008/06/06/django-finding-the-current-projects-path/</guid>
		<description><![CDATA[Problem: You need the filesystem location of the current project, but your code doesn't know which project is is used by (think 3rd party app).
Answer:  Define "project location" as "location of settings file", and you can do:

from django.conf import settings
os.path.dirname(os.path.normpath(os.sys.modules[settings.SETTINGS_MODULE].__file__))
]]></description>
			<content:encoded><![CDATA[<p>Problem: You need the filesystem location of the current project, but your code doesn't know which project is is used by (think 3rd party app).</p>
<p>Answer:  Define "project location" as "location of settings file", and you can do:</p>
<pre class="python" name="code">
from django.conf import settings
os.path.dirname(os.path.normpath(os.sys.modules[settings.SETTINGS_MODULE].__file__))</pre>
]]></content:encoded>
			<wfw:commentRss>http://blog.elsdoerfer.name/2008/06/06/django-finding-the-current-projects-path/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
	</channel>
</rss>
