<?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>Terminus a Quo &#187; Django</title>
	<atom:link href="http://abing.gotdns.com/posts/category/code-and-consequences/python/django/feed/" rel="self" type="application/rss+xml" />
	<link>http://abing.gotdns.com</link>
	<description>Because you can never have too many blogs on the Internet...</description>
	<lastBuildDate>Tue, 19 May 2009 00:23:13 +0000</lastBuildDate>
	<generator>http://wordpress.org/?v=2.8.5</generator>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
			<item>
		<title>Django File Upload Handling Examples</title>
		<link>http://abing.gotdns.com/posts/2009/django-file-upload-handling-examples/</link>
		<comments>http://abing.gotdns.com/posts/2009/django-file-upload-handling-examples/#comments</comments>
		<pubDate>Wed, 18 Feb 2009 05:10:24 +0000</pubDate>
		<dc:creator>nimrod.abing</dc:creator>
				<category><![CDATA[Code and Consequences]]></category>
		<category><![CDATA[Django]]></category>
		<category><![CDATA[Python]]></category>

		<guid isPermaLink="false">http://abing.gotdns.com/?p=257</guid>
		<description><![CDATA[I have been working on a multi-user blogging and publishing platform using Django 1.0 lately. Naturally this requires the backend to be able to handle file uploads. A lot of things have changed from Django 0.96 which I am still using on some legacy code. One of those changes is the way Django 1.0 handles [...]
<p>a</p>
]]></description>
			<content:encoded><![CDATA[<p>I have been working on a multi-user blogging and publishing platform using <a href="http://www.djangoproject.com/">Django 1.0</a> lately. Naturally this requires the backend to be able to handle file uploads. A lot of things have changed from Django 0.96 which I am still using on some legacy code. One of those changes is the way Django 1.0 handles file uploads. Most of the changes done were made to allow Django apps to handle large files without soaking up too much memory.</p>

<p>So what has changed? The most visible change is that there are now at least two separate API&#8217;s that you have to work with. You have the <a href="http://docs.djangoproject.com/en/dev/ref/files/file/#ref-files-file">File API</a> and the <a href="http://docs.djangoproject.com/en/dev/ref/files/storage/#ref-files-storage">Storage API</a>. The File API which exposes the <code>File</code> class provides a thin wrapper around <a href="http://www.python.org/">Python</a> <code>file</code> objects. The Storage API, on the other hand, exposes a base class <code>Storage</code> that you can use to implement custom storage facilities. There is another API that provides <a href="http://docs.djangoproject.com/en/dev/topics/http/file-uploads/#writing-custom-upload-handlers">FileUploadHandler</a>. This will allow you to customize the way Django handles the uploaded files in their &#8220;raw&#8221; form. For most purposes, the <code>File</code> and <code>Storage</code> API will suffice.</p>

<p>This post is meant to supplement the information found in the <a href="http://docs.djangoproject.com/en/dev/topics/http/file-uploads/#topics-http-file-uploads">&#8220;Handling Uploaded Files&#8221;</a> section of the Django File Uploads documentation. You will still need to refer to documentation.</p>

<p><span id="more-257"></span></p>

<p>The examples I will be using here implement basic file uploads handling in Django 1.0. The examples provided in the official Django documentation, as of 18 Feb 2009, do not give you an idea of how the <code>File</code> and <code>Storage</code> can be used together. Please note that these examples <strong>will not work with Django versions before 1.0</strong>.</p>

<h3>The Model</h3>

<p>Here is the model that we will be using for this example:</p>

<pre class="brush: python">

from django.db import models

class Attachment(models.Model):
    attached_file = models.FileField(upload_to=&#039;attachments&#039;)
    mimetype = models.CharField(max_length=64, editable=False)
    created = models.DateTimeField(auto_now_add=True, editable=False)
    updated = models.DateTimeField(auto_now=True, auto_now_add=True, editable=False)

</pre>

<p>We have marked the 3 fields that are not editable so that the corresponding form fields will not be created for them by Django&#8217;s automatic admin and <code>django.forms.ModelForm</code>.</p>

<h3>The Form</h3>

<p>Normally you would just use <code>django.forms.ModelForm</code> to create the form. Like so:</p>

<pre class="brush: python">

from django.forms import ModelForm

class AttachmentForm(ModelForm):
    class Meta:
        model = Attachment

</pre>

<p>This will take care of most use-cases where you have a simple app with one form per model. Taking it a bit further, you could just make use of Django 1.0&#8217;s excellent <a href="http://docs.djangoproject.com/en/dev/ref/contrib/admin/#ref-contrib-admin">&#8220;automatic admin interface&#8221;</a>. This is what you <strong>should</strong> normally do when you are just starting out with Django. However, there are times when you just want a bit more control over the way things are done. In this context, we will create a form class manually to illustrate how you would use Django&#8217;s <code>File</code> and <code>Storage</code> API.</p>

<pre class="brush: python">

from django import forms

class AttachmentForm(forms.Form):
    attached_file = forms.FileField()

    def __init__(self, bound_object=None, *args, **kwargs):
        super(AttachmentForm, self).__init__(*args, **kwargs)
        self.bound_object = bound_object
        self.is_updating = False
        if self.bound_object:
            self.is_updating = True

    def save(self):
        if not self.is_updating:
            self.bound_object = Attachment()
        # Retrieve the UploadedFile object for the attached_file field.
        uploaded_file = self.cleaned_data[&#039;attached_file&#039;]
        # Clean up the filename before storing it.
        import re
        stored_name = re.sub(r&#039;[^a-zA-Z0-9._]+&#039;, &#039;-&#039;, uploaded_file.name)
        # Save the file and its metadata.
        self.bound_object.attached_file.save(stored_name, uploaded_file)
        self.bound_object.mimetype = uploaded_file.content_type

</pre>

<p>In the example above, we used the <code>save()</code> method of the <code>Attachment</code> object&#8217;s <code>attached_file</code> field. The <code>save()</code> method&#8217;s second argument takes any object that implements the <code>File</code> class&#8217; methods. All file uploads handled by Django&#8217;s default upload handlers are <code>UploadedFile</code> objects. Since <code>UploadedFile</code> is a subclass of <code>File</code> we can use it directly in the <code>save()</code> method of our file field.</p>

<p>By default the uploaded file will be saved on the file system under the directory structure specified by <code>settings.MEDIA_ROOT</code> plus the <code>upload_to</code>. So if you have <code>settings.MEDIA_ROOT</code> set to <code>/webapp/media_root</code> adding our <code>upload_to</code> setting for the model above, the file for <code>attached_file</code> will be saved under the directory <code>/webapp/media_root/attached_file</code>. Normally this directory will also be mapped to the appropriate public URL on your webserver&#8217;s configuration.</p>

<p>There are times however when you want to change the default storage behavior. This is where the <code>Storage</code> API comes in. For example we want to be able to save files in a different root directory. The problem is that you can only specify one <code>settings.MEDIA_ROOT</code> for your entire app. To do this, we need to pass the parameter <code>storage</code> to our <code>attached_file</code> field.</p>

<p>Here is our model again, this time we specify a custom storage location other than MEDIA_ROOT.</p>

<pre class="brush: python">

from django.core.files.storage import FileSystemStorage
from django.db import models

attachment_file_storage = FileSystemStorage(location=&#039;/webapp/attachments_root&#039;, base_url=&#039;/attachments&#039;)

class Attachment(models.Model):
    attached_file = models.FileField(upload_to=&#039;attachments&#039;, storage=attached_file_storage)
    mimetype = models.CharField(max_length=64, editable=False)
    created = models.DateTimeField(auto_now_add=True, editable=False)
    updated = models.DateTimeField(auto_now=True, auto_now_add=True, editable=False)

</pre>

<p>With our modified model, calling the <code>save()</code> method of the <code>attached_file</code> field will save the file under <code>/webapp/attachments_root/attachments</code>.</p>

<p>It does not end with customizing storage locations on the filesystem however. With the <code>Storage</code> API you can customize how files are actually saved by creating a subclass of <code>Storage</code> that overrides the appropriate API methods as documented <a title="Django Storage API" href="http://docs.djangoproject.com/en/dev/ref/files/storage/#ref-files-storage">here</a> and <a title="Django Custom File Storage" href="http://docs.djangoproject.com/en/dev/howto/custom-file-storage/#howto-custom-file-storage">here</a>.</p>

<h3>Django FileUploadHandler API</h3>

<p>By default Django 1.0 handles file uploads using either <code>django.core.files.uploadhandler.TemporaryFileUploadHandler</code> or <code>django.core.files.uploadhandler.MemoryFileUploadHandler</code>. <code>TemporaryFileUploadHandler</code> is the default for files larger than <code>settings.FILE_UPLOAD_MAX_MEMORY_SIZE</code>. This handler streams the uploaded file to a temporary file saved under <code>settings.FILE_UPLOAD_TEMP_DIR</code>. It then wraps this file with a <code>TemporaryUploadFile</code> object. For smaller files, Django uses the <code>MemoryUploadFileHandler</code>. This handler wraps the uploaded file with a <code>StringIO</code> object. Either way, you get an object with a <code>file</code>-like interface. The only difference is where the file&#8217;s data is actually stored.</p>

<p>The <code>FileUploadHandler</code> allows you to customize the default behavior by using subclasses of <code>FileUploadHandler</code> and inserting them into the <code>settings.FILE_UPLOAD_HANDLERS</code> list. This is documented in the <a href="http://docs.djangoproject.com/en/dev/topics/http/file-uploads/#upload-handlers">&#8220;Upload Handlers&#8221;</a> section of the Django manual.</p>

<h3>Performing Additional Processing</h3>

<p>There are cases when you need to do more than just save an uploaded file. For instance, in a photo album application, you might want to use <a title="Python Imaging Library" href="http://www.pythonware.com/products/pil/">PIL</a> to resize uploaded images or create thumbnails before you save them. In the examples above, we did not do any post-processing of the uploaded files and just saved them right away. It really depends on what you intend to do with the uploaded file. The most common way is to just read the file into a variable using the <code>read()</code> method. You must be careful when you do this however since you will overload your server if the uploaded file is too large. Use the <code>size</code> propery of the <code>File</code> object to test if a file is too large for your system to handle. You would normally do this in your form&#8217;s <code>clean()</code> method.</p>

<p>A more efficient way of applying post-processing is to stream the file and do it lazily. PIL&#8217;s <code>Image.open()</code> is a good example. Using PIL as an example, here is how you would apply post-processing to uploaded images. This example also shows how to use <code>ContentFile</code>.</p>

<pre class="brush: python">

from PIL import Image

def postprocess_image(uploaded_file):
    img = Image.open(uploaded_file)
    # ... do image post-processing and manipulation ...
    return img

</pre>

<p>Elsewhere, in one of your form&#8217;s methods (implemented with <code>self.bound_object</code> as the example above)&#8230;</p>

<pre class="brush: python">

def save_uploaded_photo(self):
    uploaded_image = self.cleaned_data[&#039;uploaded_image&#039;]
    # We assume that uploaded_image.size has been checked in
    # the form&#039;s clean() method and that we are good to go.
    img = postprocess_image(uploaded_image)
    if (img.format == &#039;JPEG&#039;):
        processed_image = ContentFile(img.tostring(&#039;jpeg&#039;, img.mode))
    elif (img.format == &#039;PNG&#039;):
        # PIL Image.tostring() does not support PNG encoding for some reason.
        imgstr = StringIO()
        img.save(imgstr, &#039;PNG&#039;)
        imgstr.reset()
        processed_image = ContentFile(imgstr.read())
    elif (img.format == &#039;GIF&#039;):
        processed_image = ContentFile(img.tostring(&#039;gif&#039;, img.mode))

    # Clean up the filename before storing it.
    import re
    stored_name = re.sub(r&#039;[^a-zA-Z0-9._]+&#039;, &#039;-&#039;, uploaded_image.name)
    self.bound_object.image.save(stored_name, processed_image)

</pre>

<p>The above code is overly simplified and does not perform any additional checking of the file data or any exception handling. Do note that in the versions of PIL I am using, <code>Image.tostring()</code> does not support PNG encoding. This is why some additional code was needed.</p>

<p>At first glance, it may be a bit overwhelming. But the new API allows for greater flexibility in handling file uploads. It allows you to implement anything from custom storage to a <abbr title="Content Delivery Network">CDN</abbr> to upload progress meters. So learning how to use the new API is well worth the effort.</p>

<p><em>Please post any corrections in the comments below. Thanks.</em></p>

<p>a</p>
]]></content:encoded>
			<wfw:commentRss>http://abing.gotdns.com/posts/2009/django-file-upload-handling-examples/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Writing a Facebook App using Django</title>
		<link>http://abing.gotdns.com/posts/2008/writing-a-facebook-app-using-django/</link>
		<comments>http://abing.gotdns.com/posts/2008/writing-a-facebook-app-using-django/#comments</comments>
		<pubDate>Wed, 31 Dec 2008 05:31:59 +0000</pubDate>
		<dc:creator>nimrod.abing</dc:creator>
				<category><![CDATA[Code and Consequences]]></category>
		<category><![CDATA[Django]]></category>
		<category><![CDATA[Python]]></category>

		<guid isPermaLink="false">http://abing.gotdns.com/?p=235</guid>
		<description><![CDATA[I recently found myself writing my first Facebook app using Python with the Django web framework. I have to admit that it was not a very pleasant experience. The usual Django development cycle of programming and testing locally does not work. I have a very simple workflow nailed down when writing Django apps: write, test [...]
<p>a</p>
]]></description>
			<content:encoded><![CDATA[<p>I recently found myself writing my first Facebook app using Python with the Django web framework. I have to admit that it was not a very pleasant experience. The usual Django development cycle of programming and testing locally does not work. I have a very simple workflow nailed down when writing Django apps: write, test locally, commit to VCS, and upload to server. When writing a Facebook app, I had to change the current workflow a bit: write, commit to VCS, upload to server, test <strong>on production</strong>.</p>

<p>Facebook, being a PHP-powered site, likes to make the assumption that you will also be writing your app using PHP. They don&#8217;t even make any efforts to hide their bias towards PHP. The &#8220;official&#8221; client library is for PHP. The example program they give to you the first time you sign up is written in PHP. All the relevant starting points all lead towards PHP-centric development.</p>

<p>Thankfully, there are those who realize that PHP is not the be-all and end-all to programming web applications. You can find <a href="http://wiki.developers.facebook.com/index.php/Client_Libraries">unofficial client libraries</a> for other programming languages. Download and install the client library for your programming language of choice and follow the documentation and hopefully you get to have everything working on your first try.</p>

<p><span id="more-235"></span></p>

<p>If you are programming a web-based Facebook app in Python, you will have two choices:</p>

<ol>
<li><p><a href="http://code.google.com/p/pyfacebook/">PyFacebook</a> &#8211; a little bit on the heavy side since it comes with a framework-neutral core plus Django integration and Google App Engine support. It seems to be more actively maintained. The latest revision was on December 2, 2008 at the time of writing.</p></li>
<li><p><a href="http://code.google.com/p/minifb/">minifb</a> &#8211; small. However it seems that activity has stopped since February 2008.</p></li>
</ol>

<p>The choice of client library was a no-brainer for me since the site I am working on was written using Django. After downloading and installing PyFacebook I was able to get a minimal Facebook app up and running. By &#8220;up and running&#8221; I mean I can view the app&#8217;s canvas page on Facebook. However updates to my profile via profile.setFBML() do not seem to be working. After a bit of digging, I was able to find the culprit in a <a href="http://code.google.com/p/pyfacebook/issues/detail?id=82">bug report</a>. The modifications suggested by the issue reporter fixed the problem.</p>

<p>The app I was making was supposed to post updates to a Facebook Page. Facebook Pages are a relatively new feature and as a result <a href="http://wiki.developers.facebook.com/index.php/Facebook_Pages">documentation for it is a bit lacking</a>. The IRC transcript in the Wiki page for Facebook Pages provided some useful clues. There are two things you need to ensure if you need to write a Django view that has to update a Facebook Page:</p>

<ol>
<li><p><strong>Do not</strong> use <code>@facebook.require_login()</code> decorator.</p></li>
<li><p>The <code>uid</code> parameter for the <code>profile.setFBML()</code> call must be taken from the <code>fb_page_id</code> query parameter.</p></li>
</ol>

<p>For example:</p>

<pre>from django.template import loader, RequestContext

def update_page_profile(request):
    # facebook attribute in request is added by FacebookMiddleware
    uid = request.GET.get('fb_page_id')
    if uid:
        ctx = RequestContext(request, {'page_id': uid})
        # Do whatever you need to do here...
        t = loader.get_template('facebook/page_fbml.xml')
        # Render the template into the profile parameter for setFBML.
        # We do not use the deprecated markup parameter.
        request.facebook.profile.setFBML(profile=t.render(ctx), uid=uid)
        # Return a redirect to the profile URL for the page.
        # Note that we do not use Django HttpResponseRedirect here.
        return request.facebook.redirect(request.facebook.get_url('profile', id=uid))
    else:
        # Do something else here if the view did not get called
        # with the fb_page_id parameter. One possibility is to check if we got
        # called with a valid user ID and do something completely different.
        pass
</pre>

<p>One other thing to note about &#8220;profile boxes&#8221; in Facebook Pages is that they do not automatically update every time you view the Facebook Page. That is, you will need to provide a way of calling the update view manually. What I did was set the update view URL as the &#8220;Page Edit URL&#8221; for the app when embedded in a Facebook Page. Ideally you should set &#8220;Page Edit URL&#8221; to output a canvas page where the page admin can update settings for the app. Because the Facebook app I was making was mainly intended for internal use, I opted out of having a dedicated &#8220;Page Edit&#8221; canvas page and instead linked it directly to the profile update view URL.</p>

<p>a</p>
]]></content:encoded>
			<wfw:commentRss>http://abing.gotdns.com/posts/2008/writing-a-facebook-app-using-django/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>OMG!!! Ponies!!!</title>
		<link>http://abing.gotdns.com/posts/2008/omg-ponies/</link>
		<comments>http://abing.gotdns.com/posts/2008/omg-ponies/#comments</comments>
		<pubDate>Tue, 04 Nov 2008 03:54:33 +0000</pubDate>
		<dc:creator>nimrod.abing</dc:creator>
				<category><![CDATA[Code and Consequences]]></category>
		<category><![CDATA[Django]]></category>
		<category><![CDATA[Python]]></category>

		<guid isPermaLink="false">http://abing.gotdns.com/?p=218</guid>
		<description><![CDATA[Now see this is why I love Django. It&#8217;s an awesome framework with a great community behind it.

a
<p>a</p>
]]></description>
			<content:encoded><![CDATA[<p>Now see <a href="http://avalonstar.com/blog/2008/sep/9/web-framework-ponies/">this is why I love Django</a>. It&#8217;s an awesome framework with a great community behind it.</p>

<p>a</p>
]]></content:encoded>
			<wfw:commentRss>http://abing.gotdns.com/posts/2008/omg-ponies/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Undocumented Django: Overriding _get_FIELD_url and friends</title>
		<link>http://abing.gotdns.com/posts/2008/undocumented-django-overriding-get_field_url-and-friends/</link>
		<comments>http://abing.gotdns.com/posts/2008/undocumented-django-overriding-get_field_url-and-friends/#comments</comments>
		<pubDate>Mon, 21 Apr 2008 05:00:29 +0000</pubDate>
		<dc:creator>nimrod.abing</dc:creator>
				<category><![CDATA[Code and Consequences]]></category>
		<category><![CDATA[Django]]></category>
		<category><![CDATA[Python]]></category>

		<guid isPermaLink="false">http://abing.gotdns.com/?p=139</guid>
		<description><![CDATA[Recently I found the need to override the <em>get_FIELD_url() for a particular set of models in my Django app. The _get_FIELD</em>*() methods provide your FileField and ImageField with &#8220;magic&#8221; convenience methods. For example:

from django.db import models

class MyModel(models.Model):
    file = models.FileField(upload_to=&#38;#8217;some/path&#38;#8217;)

If you want to to retrieve the URL for the file you would [...]
<p>a</p>
]]></description>
			<content:encoded><![CDATA[<p>Recently I found the need to override the <a href="http://www.djangoproject.com/documentation/0.96/db-api/#get-foo-url"><code>_get_FIELD_url()</code></a> for a particular set of models in my Django app. The <code>_get_FIELD_*()</code> methods provide your FileField and ImageField with &#8220;magic&#8221; convenience methods. For example:</p>

<pre><code>from django.db import models

class MyModel(models.Model):
    file = models.FileField(upload_to=&amp;#8217;some/path&amp;#8217;)
</code></pre>

<p>If you want to to retrieve the URL for the file you would use:</p>

<pre><code>m = MyModel().objects.get(id=1)
m.get_file_url()
</code></pre>

<p>Notice that your class automagically gets a method called &#8220;get_file_url()&#8221;. This is the &#8220;magic&#8221; part and all of this is done behind the scenes for you. While this is really convenient for getting things done most of the time, there are some times where you need to have more control over what&#8217;s returned by these magic methods.</p>

<p><span id="more-139"></span></p>

<h3>You&#8217;re not in OOP Kansas anymore&#8230;</h3>

<p>All of the <code>_get_FIELD_<em></code> methods are defined in the <code>Model</code> class. Normally when you want to replace logic for a method in a subclass, you would override the method in the subclass. So the most straightforward approach would be to create a subclass of <code>Model</code> and override the <code>_get_FIELD_</em></code> methods you need. Then you would use the subclass for your own models where you need <code>_get_FIELD_*</code> overridden. This approach does not work (try it if you don&#8217;t take my word for it). It will take too long to explain why this won&#8217;t work but suffice to say, the current implementation does not allow for subclassing a subclass of Model. The Django team is working on getting around this limitation.</p>

<p>Why would you want to replace them in the first place? In my app, I had the need for &#8220;protected&#8221; and &#8220;unprotected&#8221; downloads. I needed the URL&#8217;s for &#8220;protected&#8221; files to be rooted to <code>/protected</code> and &#8220;unprotected&#8221; files to <code>/media</code> This meant that I had to use a different MEDIA_ROOT and MEDIA_URL for the &#8220;protected&#8221; files and a different one for &#8220;unprotected&#8221; files. Because of the way things are set up by default in Django, you can only have one MEDIA_ROOT and MEDIA_URL for all your models. Plus having to embed the URL root in your templates would be tedious to maintain.</p>

<p>So what do you do when you want to replace the logic for <code>_get_FIELD_<em></code>? Since subclassing won&#8217;t work, what other options do you have? One solution, and the one I used for my app, is to use <a href="http://www.linuxjournal.com/node/4540/print">mix-ins</a>. We still won&#8217;t be able to override the existing <code>_get_FIELD_</em></code> methods in the <code>Model</code> class but using a <code>ProtectedDownloadModelMixIn</code> we will be able to provide alternate implementations under different names. For instance, we only need to override the <code>_get_FIELD_url()</code> method or provide a suitable replacement for it in the mix-in. Let&#8217;s call the new method, <code>_get_PROTECTED_FIELD_url()</code>. This is straight out of the <code>django/db/models/base.py</code> module with a few modifications.</p>

<pre><code>class ProtectedDownloadModelMixIn(object):
    def _get_PROTECTED_FIELD_url(self, field):
        if getattr(self, field.attname): # value is not blank
            import urlparse
            return urlparse.urljoin(settings.PROTECTED_MEDIA_URL, getattr(self, field.attname)).replace(&amp;#8217;\\&amp;#8217;, &amp;#8216;/&amp;#8217;)
        return &amp;#8221;
</code></pre>

<p>The <code>_get_FIELD_*</code> methods are automatically added to the fields through the <code>contribute_to_class()</code> method of the field. To make our model use our custom <code>_get_PROTECTED_FIELD_url()</code> we need to create a subclass of either a <code>FileField</code> or <code>ImageField</code> and override the <code>contribute_to_class</code> method. In my app, I needed to subclass the <code>FileField</code> class.</p>

<pre><code>from django.utils.functional import curry
from django.db import get_creation_module

class ProtectedFileField(models.FileField):
    def contribute_to_class(self, cls, name):
        super(ProtectedFileField, self).contribute_to_class(cls, name)
        setattr(cls, &amp;#8216;get_%s_url&amp;#8217; % self.name, curry(cls._get_PROTECTED_FIELD_url, field=self))

# Register our new field.
data_types = get_creation_module().DATA_TYPES
data_types['ProtectedFileField'] = data_types['FileField']
</code></pre>

<p>The last bit will register our new field with Django so that the database backend will know what SQL to use when the field is created. Now to use our custom classes:</p>

<pre><code>from django.db import models

class ProtectedFile(models.Model, ProtectedDownloadModelMixIn):
    file = ProtectedFileField(upload_to=&amp;#8217;protected/&amp;#8217;
    mime = models.CharField(max_length=64)
</code></pre>

<p>That&#8217;s pretty much it! Now if you need to override the other <code>_get_FIELD_*</code>, for instance you might want to override <code>_save_FIELD_file()</code> you need to define that method in the mix-in and add the method to the class in <code>contribute_to_class</code>. There are a lot of things that I have left unexplained here. This is because most of this is &#8220;magic&#8221; and Django is going through &#8220;magic removal&#8221; so all of this will become irrelevant eventually. If you really need to understand what&#8217;s going on, try looking at the code in <code>django/db/models/base.py</code> and in <code>django/db/fields/<strong>init</strong>.py</code>.</p>

<p>a</p>
]]></content:encoded>
			<wfw:commentRss>http://abing.gotdns.com/posts/2008/undocumented-django-overriding-get_field_url-and-friends/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Running a Budget Web Hosting Company (or Not)</title>
		<link>http://abing.gotdns.com/posts/2008/running-a-budget-web-hosting-company-or-not/</link>
		<comments>http://abing.gotdns.com/posts/2008/running-a-budget-web-hosting-company-or-not/#comments</comments>
		<pubDate>Wed, 16 Apr 2008 07:19:46 +0000</pubDate>
		<dc:creator>nimrod.abing</dc:creator>
				<category><![CDATA[Code and Consequences]]></category>
		<category><![CDATA[Django]]></category>
		<category><![CDATA[Python]]></category>
		<category><![CDATA[System Administration]]></category>
		<category><![CDATA[You are doing it WRONG!!!]]></category>
		<category><![CDATA[bullshit]]></category>
		<category><![CDATA[damn lies]]></category>
		<category><![CDATA[numbers game]]></category>
		<category><![CDATA[Shenanigans]]></category>

		<guid isPermaLink="false">http://abing.gotdns.com/?p=137</guid>
		<description><![CDATA[I will be buying a new server to host my site and possibly use it for web hosting. I have been scoping out the competition. There are a lot of them out there and it&#8217;s scary what some of these web hosting companies appear to be offering. On the surface they certainly look very attractive, [...]
<p>a</p>
]]></description>
			<content:encoded><![CDATA[<p>I will be buying a new server to host my site and possibly use it for web hosting. I have been scoping out the competition. There are a lot of them out there and it&#8217;s scary what some of these web hosting companies appear to be offering. On the surface they certainly look very attractive, not so much for their glossy landing pages and slick designs, but because of the numbers they put out on their packages.</p>

<p>A colleague brought up one web hosting company the other day. Ultra-cheap packages and impressive numbers make it very attractive to those who are looking to host their site for the first time. I don&#8217;t know what bothers me more. Is it the fact that people buy into these bullshit packages? Or the fact that some unscrupulous web hosting companies take advantage of numbers to market their crappy service. To be fair to them (and so you don&#8217;t fall prey to them as well), I won&#8217;t mention that company here. However, I will take a look at the packages they offer.</p>

<p><span id="more-137"></span></p>

<h3>Marketing</h3>

<p>Here are some of the interesting bits on their hosting packages page:</p>

<blockquote>
  <ul>
  <li>99.9% Uptime Guarantee</li>
  <li>27/7 Support</li>
  <li>Lowest Latency</li>
  <li>Highest Reliability</li>
  <li>Powerful Servers</li>
  </ul>
  
  <p>Our servers are packed with powerful Dual Quad Core Clovertown Xeon (8 logical CPU&#8217;s) machines with 4GB of memory, SCSI drives, and being monitored by sytem administrator 24/7.</p>
  
  <p>Our network having the best network equipment will give you the hightest reliability, lowest latency and 99.9% uptime guarantee.</p>
  
  <p><strong>Cisco Routers &#038; Switches</strong> &#8211; 6500, 3750, 2900 Series routers and switches with gigabit speeds available from the individual server to the Internet.</p>
  
  <p><strong>Redundant GigE Backbone</strong> &#8211; Multi-router gigabit connections to the Internap, SAVVIS, VERIO/NTT, Abovenet, and Global Crossing core backbone exchanges located in the INFOMART in Dallas, Texas</p>
  
  <p><strong>Traffic Management &#038; Analysis</strong> &#8211; Utilizing Peakflow from Arbor Networks coupled with Netflow data from Cisco routers and switches, network engineers continuously monitor the health, reliability, and performance of the network. Historical analysis is critical for demand and capacity planning.</p>
  
  <p><strong>Network IDS, IPS &#038; DDOS</strong> &#8211; Industry best solutions from Tipping Point are utilized to guard against denial of service, malicious traffic, viruses, malware, phishing, spyware and other types of Internet threats via wire speed detection and remediation coupled with automatic and zero day response.</p>
  
  <p>The datacenter which our servers are housed in is a tier one datacenter facility located inside the well-known INFOMART telecom hotel near downtown Dallas. Specializing in datacenter and hosting facilities, INFOMART is home to multiple datacenters including MCI, Level 3, Equinix, Verio, Switch &#038; Data, Verizon, DataSides, and more. The building sits atop three redundant electrical grids from TXU delivering diverse power to each quadrant of the building. HVAC needs are supplied via five one hundred ton onsite water chillers to deliver N+1 cooling requirements. Home to over twelve switch sites and thirty-five different carriers, INFOMART houses technology and telecom related businesses in a complex communications ecosystem.</p>
  
  <ul>
  <li>2000AMPS 480V Input Power</li>
  <li>Parallel 500Kva UPS Battery Backup Units</li>
  <li>2000Kw Diesel Generator with Onsite Fuel Storage</li>
  <li>Redundant Liebert 20 Ton HVAC Units</li>
  <li>Pre-Action Dry Pipe Fire Suppression</li>
  <li>Digital Security Video Surveillance</li>
  </ul>
</blockquote>

<p>At first glance it&#8217;s all pretty impressive huh? If you&#8217;re impressed then they almost have you at their mercy at this point. Don&#8217;t fall for it though. It&#8217;s all smoke and mirrors. A company putting up an infrastructure such as this will have spent millions of dollars to set it up. Every web hosting company I have reviewed has drivel like this in one form or another. Surely if they all had &#8220;data centers&#8221; as they claim on their marketing page, Dallas would be full of these concrete bunkers by now.</p>

<p>The truth of the matter is that these web hosting companies are just copy/pasting specs from the company doing the actual web hosting. More likely these web hosting companies are co-located or have managed servers under companies like RackSpace, Serverbeach, or Softlayer.</p>

<p>It&#8217;s not that they&#8217;re lying or anything. Since they are co-located or managed by another company, then the drivel also applies to them as well.</p>

<h3>The Numbers! They Lie!</h3>

<p>Web hosting companies will usually offer several packages with varying price points and features. Usually it all boils down to the following:</p>

<ul>
<li>Disk quota</li>
<li>Bandwidth</li>
<li>Number of email accounts</li>
<li>Number of FTP accounts</li>
<li>Number of subdomains</li>
<li>Number of databases</li>
<li>Occasionally, number of support tickets</li>
</ul>

<p>Here&#8217;s a very interesting set of packages from one web hosting company:</p>

<h4>Package 1</h4>

<ul>
<li><strong>Monthly rate</strong> &#8211; $3.95</li>
<li><strong>Disk Quota</strong> &#8211; 1GB</li>
<li><strong>Bandwidth</strong> &#8211; 10GB/Month</li>
<li><strong>Email Accounts</strong> &#8211; Unlimited</li>
<li><strong>FTP Accounts</strong> &#8211; Unlimited</li>
<li><strong>Subdomains</strong> &#8211; 10</li>
<li><strong>Databases</strong> &#8211; 10 MySQL</li>
</ul>

<h4>Package 2</h4>

<ul>
<li><strong>Monthly rate</strong> &#8211; $7.95</li>
<li><strong>Disk Quota</strong> &#8211; 5GB</li>
<li><strong>Bandwidth</strong> &#8211; 50GB/Month</li>
<li><strong>Email Accounts</strong> &#8211; Unlimited</li>
<li><strong>FTP Accounts</strong> &#8211; Unlimited</li>
<li><strong>Subdomains</strong> &#8211; 20</li>
<li><strong>Databases</strong> &#8211; 20 MySQL</li>
</ul>

<h4>Package 3</h4>

<ul>
<li><strong>Monthly rate</strong> &#8211; $14.95</li>
<li><strong>Disk Quota</strong> &#8211; 10GB</li>
<li><strong>Bandwidth</strong> &#8211; 100GB/Month</li>
<li><strong>Email Accounts</strong> &#8211; Unlimited</li>
<li><strong>FTP Accounts</strong> &#8211; Unlimited</li>
<li><strong>Subdomains</strong> &#8211; 40</li>
<li><strong>Databases</strong> &#8211; 40 MySQL</li>
</ul>

<p>Pretty impressive huh? But let&#8217;s take a closer look and put ourselves in the shoes of someone who wants to run a web hosting business. First let&#8217;s deal with the claim of &#8220;Our servers are packed with powerful Dual Quad Core Clovertown Xeon (8 logical CPU&#8217;s) machines with 4GB of memory, SCSI drives&#8221;. So far I&#8217;ve found that the cheapest Dual Quad Core Xeon servers cost around $259 (not including taxes) for a managed server at Softlayer (Rackspace and Serverbeach have them but at $300+). The cheap setup I&#8217;m going with does not have any add-ons for storage, CPanel with WHM at additional $25. The Linux distribution is not a factor as all of the offerings are the free distros anyway. Total cost each month to keep the server running is $284.</p>

<p>The server setup is like this:</p>

<ul>
<li><strong>Processor</strong> &#8211; Dual Processor Quad Core Xeon 5310</li>
<li><strong>Memory</strong> &#8211; 2 GB FB-DIMM Registered 533/667</li>
<li><strong>Uplink Port Speed</strong> &#8211; 10 Mbps Public &#038; Private Networks</li>
<li><strong>Public Bandwidth</strong> &#8211; 2000 GB Bandwidth</li>
<li><strong>Disk</strong> &#8211; 250GB SATA II</li>
</ul>

<p>OK. So it takes $284 to run the server each month. Let&#8217;s take the most expensive package offering, Package 3. To break even, you need 284 / 14.55 = 18.99 hosting clients. Let&#8217;s round it off to 19. That gives you $284.05 per month, with a profit of $0.05. Not enough profit if you ask me. What&#8217;s the point of running a business if you don&#8217;t turn any profits?!? Let&#8217;s up our clients to 25! We get $373.75 a month. That&#8217;s $89.75 in monthly profits.</p>

<p>Now let&#8217;s turn our attention to resource usage. First off, disk space usage. Remember we have a 250GB disk. The OS will use around 10GB of that for a typical server installation. For 25 clients each requiring 10GB disk quota, we would need 25 * 10GB = 250GB. That would not leave us enough room for our operating system! Let&#8217;s say we adjust our purchase and instead of the 250GB disk, we get the 500GB disk. This will cost us an additional $30 each month. So we are left with $59.75 in monthly profits. But now we have a bigger disk, we can accommodate more clients. So let&#8217;s assume we have 40 clients. That&#8217;s 40 * $14.95 = $598 per month. We have a monthly profit of $284 now and we have 100GB disk space to spare as well.</p>

<p>Now let&#8217;s look at bandwidth usage. Let&#8217;s say all 40 clients soak up their 100GB per month. That&#8217;s already 4000GB, twice as much bandwidth that was allocated for our server. Say we purchase more bandwidth 4000GB is $200 extra. But that would be cutting it really close. So now our profits are cut down to $84 per month putting us back where we started!</p>

<p>I&#8217;ve been in the web hosting business once and quite frankly tech support is a nightmare. Especially if you make the mistake of enabling phone-in tech support. Phone in tech support is something that you would outsource and call centers don&#8217;t come cheap. So for a budget outfit like the one I&#8217;m describing here, it really makes you wonder if it&#8217;s not just some fly-by-night company.</p>

<h3>Afterthoughts</h3>

<p>I have been contemplating on running a small &#8220;custom web hosting&#8221; shop for 2 years now. I planned to focus on catering to Django-powered sites. But with the recent release of Google App Engine I think it really hit the nail on the coffin for that idea. It&#8217;s really not worth the expense and the tech support nightmare.</p>

<p>So far SoftLayer is the cheapest managed hosting I&#8217;ve found. I&#8217;ve looked at DimeHost but I hear a lot of their IP&#8217;s are black listed because spammers used them in the past.</p>

<p>a</p>
]]></content:encoded>
			<wfw:commentRss>http://abing.gotdns.com/posts/2008/running-a-budget-web-hosting-company-or-not/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Undocumented Django: urlresolvers.reverse() gotchas</title>
		<link>http://abing.gotdns.com/posts/2008/undocumented-django-urlresolversreverse-gotcha/</link>
		<comments>http://abing.gotdns.com/posts/2008/undocumented-django-urlresolversreverse-gotcha/#comments</comments>
		<pubDate>Thu, 03 Apr 2008 03:40:25 +0000</pubDate>
		<dc:creator>nimrod.abing</dc:creator>
				<category><![CDATA[Code and Consequences]]></category>
		<category><![CDATA[Django]]></category>
		<category><![CDATA[Python]]></category>

		<guid isPermaLink="false">http://abing.gotdns.com/?p=136</guid>
		<description><![CDATA[When you have several projects that share the same app, it is particularly important not to hard-code URL&#8217;s. Say you have a Blog app that you want to use with a couple of projects, you need to ensure that any URL&#8217;s used in the views as well as the templates are &#8220;portable&#8221;. That is, if [...]
<p>a</p>
]]></description>
			<content:encoded><![CDATA[<p>When you have several projects that share the same app, it is particularly important not to hard-code URL&#8217;s. Say you have a Blog app that you want to use with a couple of projects, you need to ensure that any URL&#8217;s used in the views as well as the templates are &#8220;portable&#8221;. That is, if you have one site with the Blog app rooted under /blog/ and the other site puts it under /diary/ you need to make sure that URL&#8217;s mapping to the views in the Blog app will work under these different roots.</p>

<p>For instance, viewing a post on one site would require a URL like /blog/posts/1/view/ and the other site it would be /diary/posts/1/view/. For blog archives you would have URLs like /blog/archives/ and /diary/archives/. You would use a URLconf pattern like this:</p>

<pre><code>(r&amp;#8217;^posts/(?P&lt;post_id&gt;\d+)/view/$&amp;#8217;, &amp;#8216;post_view&amp;#8217;),
(r&amp;#8217;^archives/$&amp;#8217;, &amp;#8216;post_archive&amp;#8217;),
</code></pre>

<p>You can hard-code the URLs in your views and templates, but that would be less than ideal since you now have to maintain two slightly different versions of what is essentially the same code base. What you need to do is somehow obtain the URL properly rooted to either /blogs/ or /diary/.</p>

<p><span id="more-136"></span></p>

<p>Django provides an API for doing just that, <code>django.core.urlresolvers.reverse()</code> will give you the URL for the view you specify. To retrieve the URL for archives, you do the following:</p>

<pre><code>from django.core import urlresolvers

archives_url = urlresolvers.reverse(&amp;#8217;Blog.views.post_archive&amp;#8217;)
</code></pre>

<p>Retrieving the URL for posts is a bit different and this is where I found a gotcha:</p>

<pre><code>from django.core import urlresolvers

posts_url = urlresolvers.reverse(&amp;#8217;Blog.views.post_view&amp;#8217;)
</code></pre>

<p>Will give you NoReverseMatch exception. The problem here is that the URLconf for posts requires a post_id parameter and the resolver will not be able to return the reverse resolution to a URL without it. So you need to do:</p>

<pre><code>from django.core import urlresolvers

posts_url = urlresolvers.reverse(&amp;#8217;Blog.views.post_view&amp;#8217;, None, (&amp;#8217;0&amp;#8242;))
</code></pre>

<p>Note that the <code>'0'</code> is just a dummy value that we use so that <code>reverse()</code> will work properly. It&#8217;s easy overlook this important detail especially when you have been using <code>reverse()</code> with views that don&#8217;t take arguments for a while.</p>

<p>There&#8217;s another gotcha with <code>urlresolvers.reverse()</code> and this time it involves its use in decorator functions. Put simply, you cannot use <code>urlresolvers.reverse()</code> from within a decorator function such as <code>user_passes_test</code>. This is because decorators are parsed and evaluated <strong>before</strong> the URLconfs are processed. Because the decorator creates a closure, it ends up with an invalid URLconf.<sup><a href="#note1">1</a></sup> There is a way to use <code>urlresolvers.reverse()</code> inside a decorator but you need to ensure that the lookup is triggered later, rather than upon evaluation in the decorator (lazy evaluation).</p>

<p>There are two solutions. One found <a href="http://blog.micampe.it/articles/2007/01/06/a-little-django-feature-nobody-tells-you-about">here</a> uses a wrapper method around the <code>reverse()</code> call. The other one found <a href="http://code.djangoproject.com/ticket/5925">here</a> wraps the call with a &#8220;lazy string&#8221; class. Both solutions seem to work rather well, but I particularly like the second implementation.</p>

<p><small><a name="note1"></a><sup>1</sup> As far as I understand it, this is what happens. Please correct me if I&#8217;m wrong. Thanks.</small></p>

<p>a</p>

<p></post_id></p>
]]></content:encoded>
			<wfw:commentRss>http://abing.gotdns.com/posts/2008/undocumented-django-urlresolversreverse-gotcha/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Undocumented Django: newforms and the case of the disappearing fields</title>
		<link>http://abing.gotdns.com/posts/2008/undocumented-django-newforms-and-the-case-of-the-disappearing-fields/</link>
		<comments>http://abing.gotdns.com/posts/2008/undocumented-django-newforms-and-the-case-of-the-disappearing-fields/#comments</comments>
		<pubDate>Wed, 02 Apr 2008 03:58:07 +0000</pubDate>
		<dc:creator>nimrod.abing</dc:creator>
				<category><![CDATA[Code and Consequences]]></category>
		<category><![CDATA[Django]]></category>
		<category><![CDATA[Python]]></category>
		<category><![CDATA[newforms cannot access fields in form methods]]></category>
		<category><![CDATA[newforms disappearing fields]]></category>

		<guid isPermaLink="false">http://abing.gotdns.com/?p=135</guid>
		<description><![CDATA[This is the first in a series of articles that I will be writing about Django, a Python-based web development framework that I have been using for two years now. While documentation for the framework is available, there are still vast amounts of &#8220;uncharted&#8221; regions in the code base. Articles in this series are my [...]
<p>a</p>
]]></description>
			<content:encoded><![CDATA[<p>This is the first in a series of articles that I will be writing about Django, a Python-based web development framework that I have been using for two years now. While documentation for the framework is available, there are still vast amounts of &#8220;uncharted&#8221; regions in the code base. Articles in this series are my attempts to document undocumented behavior and code. I only use the latest stable version (0.96) at this point, so it is possible that it is already documented in the latest SVN version. In which case, you should also check the SVN version docs first.</p>

<p>First up are newforms. Older code based on 0.95 and earlier use the older &#8220;Manipulators&#8221; system. The replacement system is &#8220;newforms&#8221; which, until 0.96.1, had only been available from the SVN versions. Newer code should make use of the &#8220;newforms&#8221; system as Django team has already announced that they will remove the old Manipulators system eventually.</p>

<p><span id="more-135"></span></p>

<h3>newforms, New Code</h3>

<p>Like the rest of Django, newforms is a fairly young codebase. Continuous development efforts add and remove features all the time. So it should come as no surprise that one feature/quirk that you relied upon in your old code will no longer work with new versions of the framework. At least the Django team has the good sense to let everyone know <a href="http://code.djangoproject.com/wiki/BackwardsIncompatibleChanges">what will break in new releases</a> (unlike some other web framework people out there). Documentation is almost complete for newforms, so you should refer to the <a href="http://www.djangoproject.com/documentation/newforms/">latest development snapshot of the docs</a> when working with newforms.</p>

<p>Although they are an improvement over the old Manipulators system, newforms are not without their quirks though. They have a few undocumented quirks that can take one by surprise and leave one tearing bits of their hair out in frustration. For example:</p>

<pre><code># myform.py

from django import newforms as forms

class MyForm(forms.Form):
    name = forms.CharField(label=&amp;#8221;Your Name&amp;#8221;, max_length=64)
    age = forms.IntegerField(label=&amp;#8221;Age&amp;#8221;, min_value=0)
</code></pre>

<p>Suppose you wanted to access the fields in your code:</p>

<pre><code>&gt;&gt;&gt; import myform
&gt;&gt;&gt; f = myform.MyForm()
&gt;&gt;&gt; print f.name
</code></pre>

<p>You will get a surprise error message like the one below:</p>

<pre><code>Traceback (most recent call last):
  File &amp;#8220;&lt;console&gt;&amp;#8220;, line 1, in &lt;module&gt;
AttributeError: &amp;#8216;MyForm&amp;#8217; object has no attribute &amp;#8216;name&amp;#8217;
</code></pre>

<p>What the heck just happened?!? Clearly the class definition has an attribute with the name &#8216;name&#8217;.</p>

<pre><code>&gt;&gt;&gt; dir(f)
['_BaseForm__errors', '__class__', '__delattr__', '__dict__', '__doc__', '__geta
ttribute__', '__getitem__', '__hash__', '__init__', '__iter__', '__metaclass__',
 '__module__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr_
_', '__str__', '__unicode__', '__weakref__', '_errors', '_html_output', 'add_pre
fix', 'as_p', 'as_table', 'as_ul', 'auto_id', 'base_fields', 'clean', 'data', 'e
rrors', 'fields', 'full_clean', 'initial', 'is_bound', 'is_valid', 'non_field_er
rors', 'prefix']
</code></pre>

<p>As you can see, the fields you declared in the class are no longer there. What happened to them? Where did they go? What if you need to access field objects directly in your code? Using <code>self.clean_data</code><sup><a href="#footnote1">1</a></sup> is no good since all that would give you is the cleaned value of the field.</p>

<p>If you poke around the Django source code for newforms, you will see that the Form class is declared as follows:</p>

<pre><code>class Form(BaseForm):
    &amp;#8220;A collection of Fields, plus their associated data.&amp;#8221;
    # This is a separate class from BaseForm in order to abstract the way
    # self.fields is specified. This class (Form) is the one that does the
    # fancy metaclass stuff purely for the semantic sugar &amp;#8212; it allows one
    # to define a form using declarative syntax.
    # BaseForm itself has no way of designating self.fields.
    __metaclass__ = DeclarativeFieldsMetaclass
</code></pre>

<p>What this means is that class creation is customized using the <code>DeclarativeFieldsMetaclass</code>. This is one demonstration of Python&#8217;s metaclass programming. Read more about metaclass programming in Python <a href="http://www.ibm.com/developerworks/library/l-pymeta.html">here</a>. For those in a hurry, in simple terms Django customizes the way Form objects are instantiated. The <code>DeclarativeFieldsMetaclass.<strong>new</strong>()</code> method scans the incoming class&#8217;s attributes for any instances of Field and its subclasses. These are then stuffed into a <code>SortedDictFromList</code> object which is then attached to the outgoing class&#8217;s <code>fields</code> attribute. The result is that, the outgoing class is &#8220;stripped&#8221; of the attributes that are instances of <code>Field</code> and its subclasses. The other fields that were declared in the incoming class are not touched and remain accessible in the outgoing class.</p>

<pre><code># myform2.py

from django import newforms as forms

class MyForm2(forms.Form):
    name = forms.CharField(label=&amp;#8221;Your Name&amp;#8221;, max_length=64)
    age = forms.IntegerField(label=&amp;#8221;Age&amp;#8221;, min_value=0)
    regular_attr = &amp;#8220;This is a regular attribute, one that is not an instance of Field or its subclasses.&amp;#8221;
</code></pre>

<p>And then&#8230;</p>

<pre><code>&gt;&gt;&gt; import myform2
&gt;&gt;&gt; f2 = myform2.MyForm2()
&gt;&gt;&gt; print f2.regular_attr
This is a regular attribute, one that is not an instance of Field or its subclasses.
</code></pre>

<p>But,</p>

<pre><code>&gt;&gt;&gt; print f2.name

Traceback (most recent call last):
  File &amp;#8220;&lt;console&gt;&amp;#8220;, line 1, in &lt;module&gt;
AttributeError: &amp;#8216;MyForm2&amp;#8242; object has no attribute &amp;#8216;name&amp;#8217;
</code></pre>

<p>So how does one get to the original fields? For instance, you would like to modify one of the field&#8217;s properties based on arguments given through a constructor. In one app, I needed to modify some field&#8217;s <code>required</code> attribute based on whether or not the form is used for editing or adding a new object. You will need to do:</p>

<pre><code>def __init__(self, editing=False, *args, **kwargs):
    super(MyForm, self).__init__(*args, **kwargs)
    if editing:
        self.fields['field_name'].required = True
</code></pre>

<p>At one point I needed a Forms class that would automatically apply the CSS class &#8220;required&#8221; for all required fields in the form.</p>

<pre><code>class StyledForm(forms.Form):
    def __init__(self, *args, **kwargs):
        super(StyledForm, self).__init__(*args, **kwargs)
        for field_name, obj in self.fields:
            if obj.required:
                css_classes = obj.widget.attrs.get(&amp;#8217;class&amp;#8217;)
                if not css_classes: obj.widget.attrs['class'] = &amp;#8216;required&amp;#8217;
                elif not &amp;#8216;required&amp;#8217; in css_classes: obj.widget.attrs['class'] += &amp;#8216; required&amp;#8217;
</code></pre>

<p>These are just a couple of things that I needed to do where I required access to the form object&#8217;s fields. I certainly hope that eventually it will be possible to get to the fields in a newforms form without the need to jump through hoops like this.</p>

<p><small><a name="footnote1"></a>
<sup>1</sup> <code>clean_data</code> is also known as <code>cleaned_data</code> in the latest SVN versions.</small></p>

<p>a</p>

<p></module></console></module></console></p>
]]></content:encoded>
			<wfw:commentRss>http://abing.gotdns.com/posts/2008/undocumented-django-newforms-and-the-case-of-the-disappearing-fields/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>New PHP5-based Framework Project, PHP5 and Lack of Namespace Support, Among Other Things&#8230;</title>
		<link>http://abing.gotdns.com/posts/2007/new-php5-based-framework-project-php5-and-lack-of-namespace-support-among-other-things/</link>
		<comments>http://abing.gotdns.com/posts/2007/new-php5-based-framework-project-php5-and-lack-of-namespace-support-among-other-things/#comments</comments>
		<pubDate>Mon, 13 Aug 2007 08:21:56 +0000</pubDate>
		<dc:creator>nimrod.abing</dc:creator>
				<category><![CDATA[Code and Consequences]]></category>
		<category><![CDATA[Django]]></category>
		<category><![CDATA[PHP]]></category>
		<category><![CDATA[Python]]></category>

		<guid isPermaLink="false">http://abing.gotdns.com/posts/2007/new-php5-based-framework-project-php5-and-lack-of-namespace-support-among-other-things/</guid>
		<description><![CDATA[I have been spending way too much time programming with Python and Django. I was looking for something like Django but written for PHP5. I needed a way to go forward with my PHP-based projects since PHP4 will no longer receive updates next year.

Not satisfied with the PHP5 frameworks I found I decided to write [...]
<p>a</p>
]]></description>
			<content:encoded><![CDATA[<p>I have been spending way too much time programming with Python and Django. I was looking for something like Django but written for PHP5. I needed a way to go forward with my PHP-based projects since PHP4 will no longer receive updates next year.</p>

<p><span id="more-102"></span></p>

<p>Not satisfied with the PHP5 frameworks I found I decided to write my own (again). I looked at one particular candidate &#8212; [Picora &trade;: PHP Micro Framework][picora]. It&#8217;s small and focused on doing one thing: provide an MVC framework for PHP. While it has both qualities that I was looking for in an MVC framework there are a couple of issues that I found:</p>

<ul>
<li>it currently lacks an ActiveRecord implementation.</li>
</ul>

<blockquote>Note that the model() calls use a PHP ActiveRecord implementation which is not part of Picora, substitute with your own database logic for the time being.</blockquote>

<ul>
<li>it makes the same (IMHO) mistake as CakePHP and Rails in that actions are mapped directly into methods in your Controller class without giving you the option of delegating it to a separate class. While there&#8217;s nothing wrong with this, I found that having all your actions in one big file becomes unwieldy when your project grows. Which was why I came up with [a modified action mapper for CakePHP][cakephp-sucks01].</li>
</ul>

<p>So, for now Picora &trade; doesn&#8217;t quite cut it for me yet. I began writing a new framework, based on some ideas I had from a year ago as well as taking a lot of inspiration from Django. I am writing the model class hierarchy based on Django&#8217;s excellent ORM. This will also be my first large project written using PHP5. Needless to say it has been pretty frustrating to find that PHP5 lacks namespace support. I was left wondering, &#8220;With PHP5, they practically went out and copied Java and yet they forgot to implement namespaces?!?&#8221;.</p>

<p>I did a search on Google for &#8220;php namespace support&#8221; and what I got was a depressing state of affairs for this important feature. It turns out that at the time, PHP5 namespace support is not a simple thing to implement and one of the major issues is the namespace separator. Maybe this is a testament to the fact that the PHP language is horribly broken an a multitude of places? Or maybe it&#8217;s because &#8220;design by committee&#8221; does not work? I found [one particularly entertaining post about the issue][shalosh] from 2005 and [a more recent posting][phpnamespaces] citing a [patch that implements namespaces for PHP6][phpnamespace-patch]. It looks like [namespace support will be in <strong>PHP6</strong>][zend-weekly]. I can only hope that this will be backported into a point release for PHP5.</p>

<p>Among other things I would like to see in PHP6:</p>

<ul>
<li>Closures or <strong>real</strong> anonymous functions at the very least. No, <code>create_function()</code> does not count!</li>
<li>Inner classes.</li>
<li>Inner functions.</li>
<li>Make built-ins like <code>include()</code>, <code>include_once()</code>, <code>require()</code>, and <code>require_once()</code> throw exceptions in addition to their original behavior. But it would really help to do away with the old <code>*_error_handler()</code> way of doing things.</li>
</ul>

<p>These are just some of the features that I <em>wish</em> was in PHP, ever since PHP4.</p>

<p>[picora]: http://livepipe.net/projects/picora/ &#8220;Picora &trade;: PHP Micro Framework&#8221;
[cakephp-sucks01]: http://abing.gotdns.com/posts/2006/cakephp-delegating-actions-to-separate-classes/ &#8220;CakePHP: Delegating Actions to Separate Classes&#8221;
[shalosh]: http://blog.phpdoc.info/archives/27-+1-for-Shalosh-Nekudotayim.html &#8220;Shalosh Nekudotayim&#8221;
[phpnamespaces]: http://www.gravitonic.com/blog/archives/000418.html &#8220;PHP Namespace Support&#8221;
[phpnamespace-patch]: http://news.php.net/php.zend-engine.cvs/5894 &#8220;PHP6 Namespace Support Patch&#8221;
[zend-weekly]: http://devzone.zend.com/article/2336-Zend-Weekly-Summaries-Issue-348 &#8220;Zend Weekly Summaries&#8221;</p>

<p>a</p>
]]></content:encoded>
			<wfw:commentRss>http://abing.gotdns.com/posts/2007/new-php5-based-framework-project-php5-and-lack-of-namespace-support-among-other-things/feed/</wfw:commentRss>
		<slash:comments>4</slash:comments>
		</item>
		<item>
		<title>I Am No Longer Tracking CakePHP</title>
		<link>http://abing.gotdns.com/posts/2007/i-am-no-longer-tracking-cakephp-and-new-projects/</link>
		<comments>http://abing.gotdns.com/posts/2007/i-am-no-longer-tracking-cakephp-and-new-projects/#comments</comments>
		<pubDate>Wed, 11 Jul 2007 07:25:09 +0000</pubDate>
		<dc:creator>nimrod.abing</dc:creator>
				<category><![CDATA[CakePHP]]></category>
		<category><![CDATA[Code and Consequences]]></category>
		<category><![CDATA[Django]]></category>
		<category><![CDATA[PHP]]></category>
		<category><![CDATA[Python]]></category>
		<category><![CDATA[Yes, I do have a Life.]]></category>

		<guid isPermaLink="false">http://abing.gotdns.com/posts/2007/i-am-no-longer-tracking-cakephp-and-new-projects/</guid>
		<description><![CDATA[Title says it all. I am no longer tracking the CakePHP project and therefore my CakePHP modifications project is now officially dead. This is mostly due to time constraints but there are other reasons as well. I will not go into the details for the other reasons but those who know me already know what [...]
<p>a</p>
]]></description>
			<content:encoded><![CDATA[<p>Title says it all. I am no longer tracking the CakePHP project and therefore my CakePHP modifications project is now <strong>officially dead</strong>. This is mostly due to time constraints but there are other reasons as well. I will not go into the details for the other reasons but those who know me already know what those reasons are.</p>

<p>Of course, hosting for these patches continues as well as my ThemeableView class which some CakePHP users out there found useful. If anyone else is interested in taking the reins for this class, please feel free to do so. No need to contact me or anything, but a trackback to this post would be nice so that I will know who is currently maintaining this class. This will allow me to direct them to you for any updates that you may post.</p>

<p>On another note, the project that has been taking much of my time lately is a new website for posting <a href="http://www.preownedcar.com/" title="Free online classified ads for cars, trucks, and bikes">free online classified ads for cars, trucks, and bikes</a>. This website is currently US-centric. We have plans to extend worldwide if all goes well with the current setup. So, if you&#8217;re in the US and you wish to sell your vehicle, or if you&#8217;re looking to buy a preowned car, truck, or bike check out <a href="" title="Free online classified ads for cars, trucks, and bikes">PreOwnedCar.com</a>. If you know someone with the same needs, please tell them about this site.</p>

<p>We are also currently in the final design phases for PhilWeavers Version 4. I am currently divided between doing this new version using Django as a base or simply going back to the drawing board and creating a new PHP5-based framework. We&#8217;ll see how this pans out in the later stages of development.</p>

<p>a</p>
]]></content:encoded>
			<wfw:commentRss>http://abing.gotdns.com/posts/2007/i-am-no-longer-tracking-cakephp-and-new-projects/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>Two Months Working With Django&#8230; Wishing CakePHP had a Better ORM</title>
		<link>http://abing.gotdns.com/posts/2007/two-months-working-with-django-wishing-cakephp-had-a-better-orm/</link>
		<comments>http://abing.gotdns.com/posts/2007/two-months-working-with-django-wishing-cakephp-had-a-better-orm/#comments</comments>
		<pubDate>Thu, 08 Mar 2007 04:03:13 +0000</pubDate>
		<dc:creator>nimrod.abing</dc:creator>
				<category><![CDATA[CakePHP]]></category>
		<category><![CDATA[Code and Consequences]]></category>
		<category><![CDATA[Django]]></category>
		<category><![CDATA[PHP]]></category>
		<category><![CDATA[Python]]></category>

		<guid isPermaLink="false">http://abing.gotdns.com/posts/2007/two-months-working-with-django-wishing-cakephp-had-a-better-orm/</guid>
		<description><![CDATA[I have been working with the Django Web framework for close to two months now and I&#8217;m loving it. Not so much for the free admin interface, but for the sheer ease of development that it provides. For the first time, I cared more about how my models are designed and not how they are [...]
<p>a</p>
]]></description>
			<content:encoded><![CDATA[<p>I have been working with the <a href="http://www.djangoproject.com/" title="Django Web framework">Django Web framework</a> for close to two months now and I&#8217;m loving it. Not so much for the <a href="http://www.djangoproject.com/documentation/overview/#a-dynamic-admin-interface-it-s-not-just-scaffolding-it-s-the-whole-house" title="A dynamic admin interface: It's not just scaffolding -- it's the whole house">free admin interface</a>, but for the sheer ease of development that it provides. For the first time, I cared more about how my models are designed and not how they are laid out and implemented in the database. For the two projects that I am working on, I have yet to write a custom SQL statement under Django.</p>

<p>It makes me wish CakePHP offered more when it comes to object-relational mapping. How I wish it was as simple as defining your models and running <code>php cake/scripts/bake.php syncdb</code>. CakePHP does it the other way around: you create the database first and then use <code>cake/scripts/bake.php</code> to create your models and views.</p>

<p><span id="more-81"></span></p>

<p>I found that Django&#8217;s way of doing ORM is significantly faster. You specify your models as Python classes using Django&#8217;s modeling API. You run <code>python manage.py syncdb</code> and Django takes care of generating the correct SQL for your database backend. It takes model relationships into account and also generates the correct foreign key constraints. Beautiful!</p>

<p>A similar system should also be possible to implement in CakePHP. I&#8217;ve been having a few ideas of how to go about it and hopefully, I can find the time to do them as an add-on to CakePHP 1.2.x (and hopefully, someone else is already working on the same thing).</p>

<p>Here is what I imagine it would look like:</p>

<pre><code>class User extends MetaModel {
    var $username;
    var $password;
    var $lastname;
    var $firstname;
    var $is_active;
    var $is_staff;
    var $is_admin;
    var $created;
    var $updated;

    function __construct() {
        $this-&gt;username = FieldFactory::CharField(&amp;#8217;Username&amp;#8217;, 32, IS_PK, IS_REQUIRED, NOT_NULL);
        $this-&gt;password = FieldFactory::CharField(&amp;#8217;Password&amp;#8217;, 64, NO_INDEX, IS_REQUIRED, NOT_NULL);
        $this-&gt;lastname = FieldFactory::CharField(&amp;#8217;Last Name&amp;#8217;, 64, INDEX, IS_OPTIONAL, NOT_NULL);
        $this-&gt;firstname = FieldFactory::CharField(&amp;#8217;First Name&amp;#8217;, 64, INDEX, IS_OPTIONAL, NOT_NULL);
        $this-&gt;is_active = FieldFactory::BooleanField(&amp;#8217;Active&amp;#8217;, IS_REQUIRED, NOT_NULL, false);
        $this-&gt;is_staff = FieldFactory::BooleanField(&amp;#8217;Staff&amp;#8217;, IS_REQUIRED, NOT_NULL, false);
        $this-&gt;is_admin = FieldFactory::BooleanField(&amp;#8217;Admin&amp;#8217;, IS_REQUIRED, NOT_NULL, false);
        $this-&gt;created = FieldFactory::DateTimeField(&amp;#8217;Created&amp;#8217;, NO_INDEX, IS_REQUIRED, NOT_NULL);
        $this-&gt;updated = FieldFactory::DateTimeField(&amp;#8217;Updated&amp;#8217;, NO_INDEX, IS_REQUIRED, NOT_NULL);
    }
}
</code></pre>

<p><code>FieldFactory</code> would have static methods for instantiating the correct field objects for each type. It would also have methods for generating constraints for implementing many-to-one and many-to-many relationships. I think a new model class is required to be able to do the additional magic without changing the current API.</p>

<p>I haven&#8217;t thought about how to implement the analogs of Admin and Meta inner-classes yet. I think those can be done as fields in the model, maybe <code>$this->__meta</code> and <code>$this->__admin</code>. As for QuerySets, Q objects and other classes in the Django DB API those are pretty much doable under PHP.</p>

<p>For SQL generation using the models, I imagine the backend will first load all the model classes found. Then models extending the MetaModel base class are instantiated and introspected to generate the correct DDL statements in database-specific SQL.</p>

<p>This is not a trivial undertaking and will take a lot of planning and thought. Model introspection and ORM should use as much of the existing CakePHP API as possible.</p>

<p>One last thing, if you are working on a similar system for CakePHP leave comments below. Remember: DRY.</p>

<p>a</p>
]]></content:encoded>
			<wfw:commentRss>http://abing.gotdns.com/posts/2007/two-months-working-with-django-wishing-cakephp-had-a-better-orm/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
	</channel>
</rss>
