Archive for Django

Adding additional links to Django’s Admin

If you’re like me, you’d like to add some new links to one of the Django admin lists (perhaps to delete right from the list or to direct a user to a custom made view).

Here’s the relevant code:

To your model, add:

def some_name(self):
return '<a href="/some/admin/url/here/%s/">Link Name</a>' % self.id
some_name.allow_tags = True #this is to allow HTML tags.
some_name.short_description = 'Table Header Name here'

And then just add “some_name” to your “class Admin” in the “list_display” list. Nice and neat.

Comments off

Safari and Django Redirects

I was working on a Django Project (http://naturalareas.saleient.com/) and I was having trouble with people visiting the site with Mac’s Safari. As it turns out, a shortcut I was using was causing the problem. I was using HttpResponseRedirect(“/page-name/”) and apparently Safari doesn’t like this. It’s actually looking for the entire URL. So I had to change my code to HttpResponseRedirect(“http://naturalareas.saleient.com/page-name/”) and it worked.

Comments off

TeamRemind.com Beta Launch

Yup, we’re finally ready to show this guy off a little bit. The look and feel of it is not set yet and we’re still finalizing a few features but it’s good enough to show a few people and have some people test it out.

We’re already getting some good feedback.

FYI – If anyone out there is building a website, I have a few suggestions. First, design your code to be as simple and clean as you can get. TeamRemind.com flies off the server because of it’s slim HTML code and external CSS and Javascript (which are cached on most browsers). Also, it will be easier to maintain down the road.

Check it out at www.teamremind.com

Comments off

Django Newforms

Binding a form to a model instanceDjango’s newforms module provides the helper method ‘form_for_instance’. The method will return a Form similar to the one returned by form_for_model but the initial data will be populated by the instance’s data. The form will have a ‘save’ method which will save changes to the instance to the database (unless it is passed the commit=False argument) and will return the instance itself.

Sometimes, however, it is desirable to use fields different from the default. In order to bind a form to an instance one will have to provide __init__ and save methods.

The __init__ method should be defined as follows:


def __init__(self, data=None, auto_id='id_%s', prefix=None,
initial=None, instance=None):
  if instance is not None:
    self.instance = instance
    new_data = {}
    # Populate new_data using 'instance'
    # ...
    data = new_data
  else:
    self.instance = None
super(MyForm, self).__init__(data, auto_id, prefix, initial)

The __init__ method will save the original instance in self.instance and pass the data it contains to the superclass (most likely forms.Form). The bound form will be created with MyForm(instance=MyInstance). To use the form for creating new instances it can be created with MyForm(request.POST).

The save method will look similar to the following:
def save(self, commit=True):
  if self.instance is not None:
    instance = self.instance
  else:
    instance = InstanceModel()

# Construct the instance below using self.clean_data
# Using self.clean_data ensures everything is validated.
# ...

if commit:
  instance.save()
return instance

It should be noted that one will not be able to save ManyToMany data without saving the instance first. If the model contains M2M fields then commit=False will not make any sense.

Views

Your add+edit view should look something like the following:

def add_edit_model(request, id=None):
if id is not None:
instance = MyModel.objects.get(id=id)
InstanceForm = MyForm(instance=instance)
else:
InstanceForm = MyForm()

if request.POST:
form = InstanceForm(request.POST)
if form.is_valid():
form.save()
return HttpResponseRedirect(‘/whatever/url/’)

return render_to_response(‘template.html’, {‘form’: InstanceForm})

Comments off

Django Quickies

Debugging in templates

<pre>{% debug %}</pre>

<pre>errors
{{ form.error_dict|pprint }}</pre>

<pre>data
{{ form.data|pprint }}</pre>

Example of Edit Inline

models.py

class Poll(models.Model):
    question = models.CharField(maxlength = 200)

class Choice(models.Model):
    poll = models.ForeignKey(Poll, edit_inline=models.STACKED, num_in_admin=3)
    choice = models.CharField(maxlength = 200, core = True)
    votes = models.IntegerField(core = True)

urls.py

urlpatterns = patterns('',
    [...]
    (r'^poll_update/(?P<object_id>d+)/$', 'django.views.generic.create_update.update_object', {'model': Poll})
)

templates/myapp/pollform.html

{% extends "base.html" %}
{% block content %}

<pre>errors
{{ form.error_dict|pprint }}</pre>
<pre>data
{{ form.data|pprint }}</pre>

<p>Today's question is: <em>{{ object.question }}</em></p>

<form method="POST" action="./">

     <label for="id_question">Question:</label>{{ form.question }}

       {% for the_choice in form.choice %}
        {{ the_choice.id }}

        <TABLE>
        <TH><label for="id_choice.{{ forloop.counter0 }}.choice">Choice
        <TD>{{ the_choice.choice }}
        <TH><label for="id_votes.{{ forloop.counter0 }}.votes">Votes
        <TD>{{ the_choice.votes }}
        </TABLE>
   {% endfor %}

    <input type="submit" />
</form>

{% endblock %}

Send Emails

views.py

from django.core.mail import send_mail

send_mail('Subject here', 'Here is the message.', 'from@domain.com',
    ['to@domain.com'], fail_silently=False)

settings.py

EMAIL_HOST = 'domain.com'
EMAIL_PORT = '25'
EMAIL_HOST_USER = 'username'
EMAIL_HOST_PASSWORD = 'xxxxxxxx'

Generate RSS

from django.conf import settings
from django.utils import feedgenerator
from nm.models import Newsitem
import os

def generate_rss(self):

    file_name = "latest_news.rss"
    file_path = os.sep.join([settings.MEDIA_ROOT, file_name])
    file_url = os.sep.join([settings.MEDIA_URL, "site_media", file_name])

    feed = feedgenerator.Rss201rev2Feed(
        title=u"Newsmemory",
        link=file_url,
        description=u"Dernières nouvelles",
        language=u"fr",
    )

    qs = Newsitem.objects.select_related().filter(...)[:50]

    for r in qs:
        text = "<br />".join([r.source.name, "%s" % r.time, r.text])
        feed.add_item(title=r.title, link=r.get_absolute_url(), description="")

    fp = open(file_path, 'w')
    feed.write(fp, 'utf-8')
    fp.close()

Reuse Login / Logout

settings.py

INSTALLED_APPS = (
    'django.contrib.auth',
    [...]
)

urls.py

 (r'^accounts/login/$', 'django.contrib.auth.views.login'),
 (r'^accounts/logout/$', 'django.contrib.auth.views.logout'),

app_name/urls.py

(r'^accounts/profile/$', 'projectname.invoice.views.index'), # default page after login

templates/appname/registration/loggedout.html

templates/app_name/registration/loggin.html

{% block content %}

<div id="box"><h4>Login</h4></div>

{% if form.has_errors %}
<div id="alert">
    <p>Your username and password didn't match. Please try again.</p>
</div>
{% endif %}

{% if user.is_authenticated %}
<div id="alert">
    <p>You are already logged in as "{{ user }}".</p>
</div>
{% endif %}

<form method="post" action=".">
<P>
<table>
<tr><td><label for="id_username">Username:</label></td><td>{{ form.username }}</td></tr>
<tr><td><label for="id_password">Password:</label></td><td>{{ form.password }}</td></tr>
</table>
</P>
<p>
<input type="submit" value="Login" />
<input type="hidden" name="next" value="{{ next }}" />
</p>
</form>

{% endblock %}

Creating and Using Custom Filters

projectname/invoice/templatetags/

__init__.py
custom_filters.py

projectname/invoice/templatetags/custom_filters.py

from django import template
from django.conf import settings

def nop(value):
    return value[3:-4]

register = template.Library()
register.filter('nop', nop)

projectname/settings.py

INSTALLED_APPS = (
    'projectname.invoice'
)

projectname/templates/invoice/customer_detail.html

{% load custom_filters %}
{{ object.address|linebreaks|nop }}

Reuse Django Admin Widgets and Graphics

urls.py

urlpatterns = patterns('',
    [...]
     (r'^jsi18n/$', 'django.views.i18n.javascript_catalog', {'packages': 'django.conf'}),
)

settings.py

ADMIN_MEDIA_PREFIX = '/media/'

template file

<script type="text/javascript" src="/jsi18n/"></script>
<script type="text/javascript" src="/media/js/core.js"></script>
<script type="text/javascript" src="/media/js/admin/RelatedObjectLookups.js"></script>
<script type="text/javascript" src="/media/js/calendar.js"></script>
<script type="text/javascript" src="/media/js/admin/DateTimeShortcuts.js"></script>

<img src="/media/img/admin/icon_changelink.gif">

Comments off