Dev360.com - Web Development and Beyond

In a split-second, customers will determine if your site is worthy of their time. Can you afford to lose them?

Blog

Categories

Posts Tagged ‘Django’

ManyToManyField and Ordered fields in Django ModelForms

Monday, June 15th, 2009

I was working on some code and realized that ManyToManyFields always show up last in a ModelForm, regardless if you specify the order in the Meta fields property. Apparently this is due to be fixed in Django 1.1 which is right around the corner.. unfortunately I’m on 1.0 and feel anxious about moving 10+ sites to 1.1 beta right at this moment. I also felt it was a bit inappropriate to diff my Django source.

Please be aware that this is a hack. It is not an optimal solution. Stuff like form.as_* will NOT work with the solution below. All this does is add a property called ordered_fields to your ModelForm which implements the correct behavior.

# models.py
class Bar(models.Model):
	pass

class Foo(models.Model):
        # ordinarily, Django 1.0 would list the regular_field first and all M2Ms last
	many_to_many = models.ManyToManyField('Bar', related_name='foos')
	regular_field = models.CharField(max_length=10)
# forms.py
class FooForm(forms.ModelForm):
	def ordered_fields(self):
		list = []
		for field_name in self._meta.fields:
			list.append(self[field_name])
		return list

	class Meta:
		model = Foo
		fields = ('many_to_many',
			     'regular_field',)
#Template:

<form action="{{ app_path }}" method="post" id="foo-form">
	<fieldset class="module aligned ()">
	{% for field in form.ordered_fields %}
		<div class="form-row thin wide ()">

			{{ field.label_tag }}
			{{ field }}
			{{ field.errors }}
			{% if field.help_text %}
			<p class="help">{{ field.help_text }}</p>
			{% endif %}
		</div>
	{% endfor %}
	</fieldset>
	<div class="submit-row aligned ()">
		<input class="default" type="submit" value="Send" />
	</div>
</form>

ImageField not validating in Django ModelForm

Friday, June 5th, 2009

The other day I was working on a Django ModelForm that had an ImageField in it and to my great surprise the ImageField would not validate in the ModelForm, even when I had selected an image. The solution was simple enough: add request.FILES to the instantiation parameters of the ModelForm.. DUH!

    #ProfileForm is a ModelForm
    form = ProfileForm(request.POST, request.FILES, instance=profile)

Rendering a RSS feed in Django

Sunday, May 24th, 2009

I have been working to get the new version of DEV360.com out the door and found myself in need of displaying RSS items from my Wordpress-powered blog on the DEV360 site which is developed in Django.

There were two libraries that I found for parsing RSS; RSS.py by Mark Nottingham which unfortunately didn’t support RSS 2.0, and Mark Pilgrim’s feedparser.py. I settled on the latter since it contains more features, has easier syntax and has better unit-test coverage.

For what I’m doing, a template tag works out best for rendering the RSS items; let’s fast-forward to the code:

foo.html:

{% load rss_feed %}
{% rss_feed %}

[application]/templatetags.py:

import feedparser
from datetime import datetime
from django.template import Library, Node
register = Library()

@register.simple_tag
def rss_feed(itemCount=5):
	channel = feedparser.parse('http://blog.dev360.com/feed/')

	html = []
	html.append('<div id="rss-feed">')
	html.append('	<h1>Latest blog posts</h1>')
	html.append('	<ul>')
	for entry in channel.entries[:itemCount]:
		url = entry.id
		title = entry.title
		date = datetime.strptime(entry.date, "%a, %d %b %Y %H:%M:%S +0000");
		html.append('<li><p><strong><a href="%s">%s</a></strong>' % (url, title));
		html.append('%s</p></li>' % (date.strftime("%B %d, %Y")))

	html.append('	</ul>')
	html.append('</div>')
	return "\n".join(html)

Amazon S3 file uploads in Django

Monday, December 8th, 2008

Last time I had to use S3 uploads in Django was in 0.96 and I am happy to report that it is simpler than ever to upload files to S3 in Django. The recent storage-engine refactoring in Django 1.0 makes it a breeze to implement - no need for custom field types or anything like that.

David Larlet has put together a very good collection of Django storage-engines that looks very well-written compared to some naive implementations that I happened to stumble across elsewhere on the web. In addition, it includes a library for MogileFS - looks very exciting indeed and I hope I’ll have an opportunity (or reason rather) to play around with it one day!

To use, simply download Amazons S3 api, along with Larlet’s storage-engines (I just placed them in site-packages), and then your model would look something like the following:

import S3Storage

class UserProfile(models.Model):
    storage = S3Storage()
    profile_image = models.ImageField(upload_to='some-dir', storage=storage)

JSON serialization in Django

Thursday, November 27th, 2008

I’ve been quite busy lately, but I decided I’d share a few lines of code on how to do JSON (as well as XML) serialization in Django - its very simple.

I like the REST-based approach that Rails takes, so I kind of incorporated that in my code. It allows you to do something like this:

Regular view:
http://foo.com/banners/list/
JSON serialized data:
http://foo.com/banners/list/?format=json
XML serialized data:
http://foo.com/banners/list/?format=xml

On to the code:

# models.py
class Banner(models.Model):
	title = models.CharField(max_length=64)
	url = models.URLField()
	image = models.ImageField(upload_to='img/banners/')

# views.py
from django.core import serializers
from django.http import HttpResponse, QueryDict
from django.shortcuts import render_to_response

def request_format(request):
	default_format = 'http'
	q = QueryDict(request.META['QUERY_STRING'])
	format = q.get('format', default_format)
	if(format not in ['http','json','xml']):
		format = default_format
	return format

def list_banners(request):
	banners = Banner.objects.filter()
	format = request_format(request)
	if format == 'http':
		return render_to_response('list_banners.html', {'banners':banners})
	else:
		serialized_data = serializers.serialize(format, banners, fields = ('title', 'url', 'image'))
		return HttpResponse(serialized_data, mimetype='application/'+format)