Best django questions in January 2011

Django: remove a filter condition from a queryset

6 votes

I have a third-part funtion which gives me a filtered queryset (e.g. records with 'valid'=True) but I want to remove a particular condition (e.g. to have all records, both valid and invalid).

Is there a way to remove a filter condition to an already-filtered queryset?

E.g.

only_valid = MyModel.objects.filter(valid=True)
all_records = only_valid.**remove_filter**('valid')

(I know that it would be better to define 'all_records' before 'only_valid', but this is just an example...)

From the docs:

Each time you refine a QuerySet, you get a brand-new QuerySet that is in no way bound to the previous QuerySet. Each refinement creates a separate and distinct QuerySet that can be stored, used and reused.

I doubt therefore, that there is a standard way to do it. You could dig into the code, see, what filter() does and try a bit. If that doesn't help, my assumption is, you're out of luck and need to re-build the query yourself.

Workflow using virtualenv and pip

6 votes

I have python2.6 and django1.2.3 already installed on my system(Ubuntu 10.x). This is the setup i use for most of my projects. But for some projects I need sandboxed environments, different django version, some extra python modules and sometimes even different python version.

So, I am trying to use pip and virtualenv now,but I am unable to change python and django version. Will I have to remove default setup and move all existing projects into 1 virtualenv. Can I avoid this? Even if I do that, how can I specify a different version of python?

If I have to remove the old settings. How do i do that? I have currently most of the things installed in /usr/local/lib/python2.6/dist-packages but I am not sure if there is anything installed anywhere else also.

Q.3 If I have a completely blank setup with just Ubuntu,What is the ideal workflow? Is it? Install python $ sudo apt-get install python-setuptools $ sudo apt-get install python-virtualenv $ sudo easy_install pip $ sudo pip install virtualenvwrapper

You want to do:

virtualenv --python=/path/to/python/version --no-site-packages ENV_NAME

For example:

virtualenv --python=/usr/bin/python2.6 --no-site-packages my_project_env

If you follow this for your projects you should be able to have a separate configuration for each one.

Django template can't loop defaultdict

6 votes
import collections

data = [
  {'firstname': 'John', 'lastname': 'Smith'}, 
  {'firstname': 'Samantha', 'lastname': 'Smith'}, 
  {'firstname': 'shawn', 'lastname': 'Spencer'}, 
]

new_data = collections.defaultdict(list)

for d in data:
    new_data[d['lastname']].append(d['firstname'])

print new_data

Here's the output:

defaultdict(<type 'list'>, {'Smith': ['John', 'Samantha'], 'Spencer': ['shawn']})

and here's the template:

{% for lastname, firstname in data.items %}
  <h1> {{ lastname }} </h1>
  <p> {{ firstname|join:", " }} </p>
{% endfor %}

But the loop in my template doesn't work. Nothing shows up. It doesn't even give me an error. How can i fix this? It's supposed to show the lastname along with the firstname, something like this:

<h1> Smith </h1>
<p> John, Samantha </p>

<h1> Spencer </h1>
<p> shawn </p>

try:

dict(new_data)

and is better to use iteritems instead of items:)

Tools and tips for switching CMS

5 votes

I work for a university, and in the past year we finally broke away from our static HTML site of several thousand pages and moved to a Drupal site. This obviously entails massive amounts of data entry.

What if you're already using a CMS and are switching to another one that better suits your needs? How do you minimize the mountain of data entry during such a huge change? Are there tools built for this, or some best practices one should follow?

  • Expect to have to both pre-process and post-process your data manually, whatever happens. Accept early on that your data is likely to be in a worse state than you think it is: fields will be misused; record-to-record references (foreign keys) might not be implemented properly, or at all; content is likely to need weeding and occasionally to be just bad or incorrect.

  • Check your database encoding. Older databases won't be in Unicode encodings, and get grumpy if you have to export data dumps and import them elsewhere. Even then, assume that there'll be some wacky nonprintable characters in your data: programs like Word seem to somehow inject them everywhere, and I've seen... codepoints... you people wouldn't believe. Consider sweeping your data before you even start (or even sweeping a database dump) for these characters. Decide whether or not to junk them or try to convert them in the case of e.g. Word "smart" punctuation characters.

  • It's very difficult to create explicit data structures from implied one. If your incoming data has a separate date field, you can map that to a date field; if it has a date as part of a big lump of HTML, even if that date is in a tag with an id attribute, simple scripting won't work. You could use offline scripting with BeautifulSoup or (if your HTML's a bit nicer) the faster lxml to pre-process your data set, extract those implicit fields, and save them into an implicit format. Consider creating an intermediate database where these revisions are going to go.

  • The Migrate module is excellent, but to get really good data fidelity and play more clever tricks you might need to learn about its hook system (Drupal's terminology for functions following a particular naming scheme) and the basics of writing a module to put these hooks in (a module is broadly just a PHP file where all the functions begin with the same text, the name of the module file.)

  • All imported content should be flagged for at least a cursory check. You can do this by importing it with status=0 i.e. unpublished, and then create a view with the Views module to go through the content and open it in other tabs for checking. Views Bulk Operations lets you have a set of checkboxes alongside your view items, so you could approve many nodes at once.

  • Expect to run and re-run and re-run the import, fixing new things every time. Check ten, or twenty items, as early as possible. If there are any problems, check ten or twenty more. Fix and repeat the import.

  • Gauge how long a single import run is likely to take. Be pessimistic: we had an import we expected to take ten hours encounter exponential slowdown when we introduced the full data set; until we finally fixed some slow queries, it was projected to take two weeks.

  • If in doubt, or if you think the technical aspects of the above are just going to take more time than the work itself, then just hire temps to do the data. But you still need decent quality controls, as early as possible during their work. Drupal developers are also for hire: try your country's relevant IRC channel, or post a note in a relevant groups.drupal.org group. They're more expensive than temps but they usually write better PHP...! Consider hiring an agency too: that's a shameless plug, as I work for one, but sometimes it's best to get experts in for these specific jobs.

  • Really good imports are always hard, harder than you expect. Don't let it get you down!

Distributing Django projects with unique SECRET_KEYs

5 votes

I have a Django project that I'd like to distribute on a public repository like bitbucket or github. I'd like it to be as easy to install as possible, so I'm including the full project, not just the pluggable apps. This means that the settings.py file will be included as well.

How can I avoid the problem of settings.SECRET_KEY being the same for every installation?

Is the only simple solution to have the user manually modify settings.py?

Should I store the key in the default database and have settings.py initialize it if it doesn't exist? That would solve the problem, but I'm wondering if there is already a standard way of doing this.

Thanks!

I'd go about it this way:

Have the secret key in a separate file "secret_key.py". This file does not exist for a pristine installation. In your settings.py include something like:

try:
    from secret_key import *
except ImportError:
    SETTINGS_DIR=os.path.abspath(os.path.dirname(__file__))
    generate_secret_key(os.path.join(SETTINGS_DIR, 'secret_key.py'))
    from secret_key import *

The function generate_secret_key(filename) generates a file called filename (which, as we call it, will be secret_key.py in the same dir as settings.py) with the contents:

SECRET_KEY = '....random string....'

Where random string is the generated key based on a random number. Probably I don't need to write that key generation function for you, but can do it on demand.


EDIT: Bonus content - My personal random key generation

As an afterthought, this is the generic key generation method I use in my apps for a number of purposes:

from hashlib import md5, sha1
from base64 import urlsafe_b64encode as b64encode

import random
random.seed()


def random_string():
    """
    Generate a random string (currently a random number as a string)
    """
    return str(random.randint(0,100000))

def generate_key(max_length, data, encoder=b64encode, digester=md5):
    """
    Generate a Base64-encoded 'random' key by hashing the data.
    data is a tuple of seeding values. Pass arbitrary encoder and
    digester for specific hashing and formatting of keys
    """
    base = ''
    for arg in data:
        base += str(arg)
    key = encoder(digester(base).digest())
    return key[:max_length]

You can pass any encoder and digester methods, and key length, as in:

from hashlib import sha1
generate_key(40, (random_string(),), digester=sha1)

How to keep imports neat in Django?

5 votes

This might seem like a subjective question, but I'm sure there are good techniques that some of you employ to ensure the imports in Django projects stay maintainable. I'm used to having a list of about 30 different imports in every file, and that clearly violates the DRY principle. So it's not just about aesthetics, it's also about not duplicating code.

I'm looking for a method that keeps the import sections in Django files manageable. What seems to me like a good idea is to have a generic import file for every file type (views, models, etc.), which is then imported at the top, with further application-specific imports after that. But would that cause a lot of unnecessary overhead? How should those files look, and what are the important classes for every file-type?

Update

On request, here is an example from one of my views.py files.

from django.shortcuts import render_to_response, get_object_or_404
from shortcuts import render_to_context, render_template
from django.http import HttpResponseRedirect
from django.contrib.comments.models import Comment
from django.template import RequestContext
from django.contrib.auth.decorators import login_required
from django.views.decorators.http import require_POST

from django.core.urlresolvers import reverse

from models import Listing, LocationData

from django.template import RequestContext

import sys
import urllib
if sys.version_info <= (2, 5):
    import simplejson as json
else:
    import json

import forms
import sanitize

from models import RentListing, VacationListing, SaleListing

from django.forms.models import model_to_dict
from django.forms.formsets import formset_factory

from django.core.urlresolvers import reverse

which, as you can see, is just really messy, since I just add to the bottom of the list every time I need something in the file. Keeping it in alphabetical order would obviously help, but there has to be a better way to generalize than what I'm doing now.

Is it worth breaking the style guideline of not using the * import for the sake of shorter, more maintainable import sections in the actual file?

Tomasz already mentioned one interesting part of google's documentation concerning imports, but I think also this section is worth reading!

Django 1.2.4 CSRF verification failed

5 votes

Django 1.2 is consistently giving me this CSRF verification error when I perform a POST form. I "think" I've done all the things asked in the Django 1.2 docs, namely,

  1. Ensure MIDDLEWARE_CLASSES is included with 'django.middleware.csrf.CsrfViewMiddleware'

  2. Ensure the {% csrf_token %}

    <form action="/words/new/" method="post">
    {% csrf_token %}
    {{ form.as_p }}
        <input type="submit" value="Enter" />
    </form>
    
  3. Use RequestContext in my response

    def create(request):
        if request.method == 'POST':
            form = DefinitionForm(request.POST)
            if form.is_valid():
                form.save()
            c = {}
            return render_to_response('dict/thanks.html',c, 
                                        context_instance=RequestContext(request))
        else:
            form = DefinitionForm()
        return render_to_response('dict/create_definition.html', {
            'form' : form,
        })
    

Note that the GET action works in this function. So I think I'm using render_to_response right.

I've even tried to throw in the @csrf_protect decorator and even that didn't seem to work. I'm out of ideas and I'm about to choke myself with my laptop.

Any thing you guys can think of?

Thanks!

You're not following #3. The RequestContext must be used with the rendering of the template that shows the form. It's not necessary for the thanks page.

return render_to_response('dict/create_definition.html', {
    'form' : form,
}, context_instance=RequestContext(request))

And as a side note, you should use the PRG pattern instead of rendering the thanks page directly.

How do I use Django groups and permissions?

5 votes

I understand the basic user stuff. I know authentication, login, creating accounts, etc. But now I want to work on groups and permissions.

Where is the documentation for django groups/permissions? This is not it: http://docs.djangoproject.com/en/dev/topics/auth/

I suppose the first question you need to ask are what permissions do you need and what sort. By what sort, I mean do you want Model- or Object-level. To clarify the difference say you have a model Car. If you want to give permissions on all cars, then Model-level is appropriate, but if you want to give permissions on a per-car basis you want Object-level. You may need both, and this isn't a problem as we'll see.

For Model permissions, Django handles these for you... mostly. For each model Django will create permissions in the form 'appname.permissionname_modelname'. If you have an app called 'drivers' with the Car model then one permission would be 'drivers.delete_car'. The permissions that Django automatically creates will be create, change, and delete. For some strange reason they decided not to include read permissions from CRUD, you will have to do this yourself. Note that Django decided to change CRUD's 'update' to 'change' for some reason. To add more permissions to a model, say read permissions, you use the Meta class:

class Car( models.Model ):
    # model stuff here
    class Meta:
        permissions = ( 
            ( "read_car", "Can read Car" ),
        )

Note that permissions is a set of tuples, where the tuple items are the permission as described above and a description of that permission. You don't have to follow the permname_modelname convention but I usually stick with it.

Finally, to check permissions, you can use has_perm:

obj.has_perm( 'drivers.read_car' )

Where obj is either a User or Group instance. I think it is simpler to write a function for this:

def has_model_permissions( entity, model, perms, app ):
    for p in perms:
        if not entity.has_perm( "%s.%s_%s" % ( app, p, model.__name__ ) ):
            return False
        return True

Where entity is the object to check permissions on (Group or User), model is the instance of a model, perms is a list of permissions as strings to check (e.g. ['read', 'change']), and app is the application name as a string. To do the same check as has_perm above you'd call something like this:

result = has_model_permissions( myuser, mycar, ['read'], 'drivers' )

If you need to use object or row permissions (they mean the same thing), then Django can't really help you by itself. The nice thing is that you can use both model and object permissions side-by-side. If you want object permissions you'll have to either write your own (if using 1.2+) or find a project someone else has written, one I like is django-objectpermissions from washingtontimes.

How does commit_on_success handle being nested?

5 votes

Hi,

I'm a bit confused about how I should handle transactions in a particular situation.

I've got some code that boils down to this:

from django.db import transaction

@transaction.commit_on_success
def process_post():
    #do stuff with database
    for reply in post_replies:
        process_post_reply(reply)

@transaction.commit_on_success
def process_post_reply(reply):
    #do stuff with database

I want to know what happens if a process_post_reply() fails.

How does commit_on_success handle being nested? Will it understand to commit each process_post_reply() or if one fails the whole process_post() rolls back?

Here's the source code of it: http://code.djangoproject.com/browser/django/tags/releases/1.2.4/django/db/transaction.py#L286

And enter_transaction_management is as simple as putting new transaction handling mode on thread stack.

So, in your case, if process_post_reply() fails (i.e. exception occurs), then transaction is rolled back in its entirety, and then the exception propagates upwards from process_post() as well but there is nothing to rollback.

And no, if one process_post_reply() fails then whole process_post() is not being rolled back - there's no magic there, only COMMIT and ROLLBACK on database level, which means that what's get rolled back is only what has been writted to DB after last commited process_post_reply().

Summarizing, I think that what you need is just a single commit_on_success() around process_post, possibly supported by transaction savepoints - which unfortunately are available only in PostgreSQL backend, even though MySQL 5.x supports them as well.

How to bind an image to an edit form in Django?

4 votes

I have the following Model:

class Listing(models.Model):
    name = models.CharField(max_length=50, verbose_name="Title")
    images = models.ManyToManyField('Image')

, with the ManyToManyField linking to this Image class:

class Image(models.Model):
    thumb = ImageField(upload_to='images/uploads/')
    number = models.PositiveSmallIntegerField()

and a corresponding ModelForm like so:

class ListingEditForm(ModelForm):
    image1 = ImageField(required=False, label="Photo 1")
    image2 = ImageField(required=False, label="Photo 2")
    image3 = ImageField(required=False, label="Photo 3")

    class Meta:
        model = Listing
        exclude = ('images')

The idea is to not limit the number of images that can be associated with a Listing in the backend, but at this time I only need 3 images in the form. Uploading the images works fine, but how would you go about binding the form to a Listing instance so that the images are not 'None' when one views the edit form?

Obviously, this alone won't work, because image1, image2 and image3 are only form fields, and not part of the model:

form = forms.ListingEditForm(instance=listing)

So adding a dictionary as the first parameter seems like the obvious thing to do:

form = forms.ListingEditForm({'image1': ...},instance=listing)

but what should the value of that ... be? And how do I retrieve it from the Listing instance?

I'll answer my own question, even though it's not quite the answer I was looking for. I've looked around, and as far as I know, there is no reliable way in HTML to change the contents of a File input field. So, I could be wrong, but even if you send that information with the request, Django will have no way of showing the information in the field (since it doesn't correspond to a file on the local PC).

So, my solution is simply to send the urls of the images with the request, as one normally would:

return render_to_response('edit.html', {'image1': image1_url, ...})

Then, if this information is present, I use jQuery to place the images next to the file input field in the template, and update it if the user selects a new file. It's not the best, but it works.

I'll still be glad to hear any other solutions.

contrib.staticfiles and Django admin media

4 votes

I just switched from 1.2 to trunk (r15175 at this writing) to play with contrib.staticfiles, and now when using the local devserver all my admin media returns a 404. The static media (as managed by the new contrib app) all work as expected, but I'd like to be able to use the admin with the dev server so that I don't have to restart a local apache instance when dev code changes.

Is this known behaviour? I haven't gotten a response in IRC.

edit: Seems related to: Admin media disappear while running django trunk in development mode., but there didn't seem to be an actual answer there.

I was having the same problem, finally noticed this line in the docs for ADMIN_MEDIA_PREFIX:

For integration with staticfiles, this should be the same as STATIC_URL followed by 'admin/'.

Doing that fixed it for me.

PyDev in Eclipse does not recognize db.add_column from South

4 votes

I have just installed South (0.7.3, python-2.6) and successfully completed the tutorial using the python interpreter. Meaning that I am able to create a model and migrate it without any errors, so South appears to be working fine in the python shell. I used an sqlite3 db for the tutorial.

However, when I open my project in Eclipse, Eclipse does not recognize the functions associated with db in the migration folders: 0001_initial.py and 0002_auto__add_field_knight_dances_whenever_able.py files. I get the specific errors ( Undefined variable from import: add_column, create_table, delete_column, delete_table, send_create_signal)

Up until the South install, Eclipse has been working fine for creating django apps. I did point the PyDev interpreter to the south folder under site-packages (C:\python26\Lib\site-packages\south-0.7.3-py2.6.egg) (Other libraries there such as Django and django-picklefield work fine.)

I ran a simple script from the eclipse project and from the python shell and both appear to have the same sys.path's

Any tips on getting the Eclipse python interpreter happier?

One (far from ideal) solution is to put #@PydevCodeAnalysisIgnore in all of your migrations. If you only have a few so far, you can do this manually. I had heaps, so I ran the following shell command, which will add the comment in as the second line of each file:

find . | grep '^.\/[a-z]*\/migrations\/.*\.py$' | xargs -I FILE sed -i '
1 a\
#@PydevCodeAnalysisIgnore
' FILE 

(Note: You should probably run find . | grep '^.\/[a-z]*\/migrations\/.*\.py$' to see which files sed will alter, before running the whole command. You can also run the whole command without the -i flag to see the changes themselves.)

Django i18n setlang not changing session data django_language

4 votes

I don't know what I'm doing wrong, but my session data won't change even if I submit a new language to /i18n/setlang. I am to translate to Filipino language using the code 'tl' but somehow, it just doesn't seem to work. Please help. Here are some code:

# Django settings for ppdjango project.
import os

DEBUG = True
TEMPLATE_DEBUG = DEBUG

ADMINS = (
    # ('Your Name', 'your_email@domain.com'),
)

MANAGERS = ADMINS

DATABASES = {
    'default': {
        'ENGINE': 'django.db.backends.sqlite3', 
        'NAME': 'bookmarksdb',                      
        'USER': '',                      # Not used with sqlite3.
        'PASSWORD': '',                  # Not used with sqlite3.
        'HOST': '',                      # Set to empty string for localhost. Not used with sqlite3.
        'PORT': '',                      # Set to empty string for default. Not used with sqlite3.
    }
}

# Local time zone for this installation. Choices can be found here:
# http://en.wikipedia.org/wiki/List_of_tz_zones_by_name
# although not all choices may be available on all operating systems.
# On Unix systems, a value of None will cause Django to use the same
# timezone as the operating system.
# If running in a Windows environment this must be set to the same as your
# system time zone.
TIME_ZONE = 'America/Chicago'

# Language code for this installation. All choices can be found here:
# http://www.i18nguy.com/unicode/language-identifiers.html
# LANGUAGE_CODE = 'en-us'
LANGUAGE_CODE = 'en-us'

LANGUAGES = (
    ('tl', 'Filipino'),
    ('en', 'English'),
)

SITE_ID = 1

# If you set this to False, Django will make some optimizations so as not
# to load the internationalization machinery.
USE_I18N = True

# If you set this to False, Django will not format dates, numbers and
# calendars according to the current locale
USE_L10N = True

# Absolute path to the directory that holds media.
# Example: "/home/media/media.lawrence.com/"
MEDIA_ROOT = ''

# URL that handles the media served from MEDIA_ROOT. Make sure to use a
# trailing slash if there is a path component (optional in other cases).
# Examples: "http://media.lawrence.com", "http://example.com/media/"
MEDIA_URL = ''

# URL prefix for admin media -- CSS, JavaScript and images. Make sure to use a
# trailing slash.
# Examples: "http://foo.com/media/", "/media/".
ADMIN_MEDIA_PREFIX = '/media/'

# Make this unique, and don't share it with anybody.
SECRET_KEY = '35qqpsggj&v0^!rdabnr7daj(#gu2252hj4&8qw1k6gb@5r)qa'

# List of callables that know how to import templates from various sources.
TEMPLATE_LOADERS = (
    'django.template.loaders.filesystem.Loader',
    'django.template.loaders.app_directories.Loader',
#     'django.template.loaders.eggs.Loader',
)

MIDDLEWARE_CLASSES = (
    'django.middleware.cache.UpdateCacheMiddleware',
    'django.middleware.common.CommonMiddleware',
    'django.contrib.sessions.middleware.SessionMiddleware',
    'django.middleware.locale.LocaleMiddleware',
    'django.middleware.csrf.CsrfViewMiddleware',
    'django.contrib.auth.middleware.AuthenticationMiddleware',
    'django.contrib.messages.middleware.MessageMiddleware',
    'django.middleware.cache.FetchFromCacheMiddleware'
)

ROOT_URLCONF = 'ppdjango.urls'

TEMPLATE_DIRS = (
    # Put strings here, like "/home/html/django_templates" or "C:/www/django/templates".
    # Always use forward slashes, even on Windows.
    # Don't forget to use absolute paths, not relative paths.
    os.path.join(os.path.dirname(__file__), 'templates')
)

TEMPLATE_CONTEXT_PROCESSORS = (
    "django.core.context_processors.auth", 
    "django.core.context_processors.debug", 
    "django.core.context_processors.i18n", 
    "django.core.context_processors.media", 
    'django.core.context_processors.request',
)

INSTALLED_APPS = (
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.sites',
    'django.contrib.messages',
    'django.contrib.comments',
    'bookmarks',

    # Uncomment the next line to enable the admin:
    'django.contrib.admin',
    # Uncomment the next line to enable admin documentation:
    # 'django.contrib.admindocs',
)

LOGIN_URL = '/login/'
CACHE_BACKEND = 'db://cache_table'
CACHE_MIDDLEWARE_SECONDS = 60 * 5

#email
SITE_HOST = '127.0.0.1:8000'
DEFAULT_FROM_EMAIL = 'Django Bookmarks <django.bookmarks@example.com>'
EMAIL_HOST = 'mail.ygamretuta.com'
EMAIL_PORT = ''
EMAIL_HOST_USER = 'dev@ygamretuta.com'
EMAIL_HOST_PASSWORD = ''

My language settings form: {

{% load i18n %}

<!DOCTYPE html>
<html>
  <head>
    <title>
    Django Bookmarks | {% block title %}{% endblock %}
    </title>
    <link rel="stylesheet" type="text/css" href="/site_media/style.css">
    <script type="text/javascript" src="/site_media/jquery.js"></script>
    {% block external %}
      <script type="text/javascript" src="/site_media/search.js"></script>
    {% endblock %}
  </head>

  <body>
  {% block content %}{% endblock %}

    <div id="footer">
      <form action="/i18n/setlang/" method="post">
        {% csrf_token %}
        <input name="next" type="hidden" value="/friend/invite/" />
        <select name="language"> 
          {% for lang in LANGUAGES %}
            <option value="{{ lang.0 }}">{{ lang.1 }}</option>
          {% endfor %}
        </select>
        <input type="submit" value="Switch Language"/>
      </form>
    </div>
  </body>
</html>

my url settings:

# the rest is above
(r'^i18n/', include('django.conf.urls.i18n')),

EDIT My languages are working well because if I make 'tl' the only language in settings, the page get translated to Tagalog

EDIT included the whole settings file

I've investigated this a bit and here's some things to check:

1- Add this line in your /friend/invite/ associated view to ensure the set_lang view is working correctly.

print request.LANGUAGE_CODE

If it does not output 'tl', it's probably because you're missing django locale files for your language since they are in your settings file. These files should be located under django/conf/locale/tl. There's more than one files in there and these won't be generated by the makemessages command.

2- If it does output 'tl', that must mean you have a tl folder in django code tree. Then I would try and make it work with a supported language first. When trying to make your example work, I wasn't able to get tagalog either. By switching to another supported language, french in my case, I've been able to troubleshoot my problems.

3- It would help to have the template to render /friend/invite/ view so we can see what you're translating. In my test I used a django string to avoid having to generate my own messages. I did what the documentation says and copied from english to use in tagalog. I then modified one of the strings in there. The problem is, django uses a binary file generated from the text one so only modifying the text version would still display django strings in english even if under tagalog. I discovered that when instead of using english as a basis, I used the french versions to put under tagalog.

What are the various Python CMS's and their statuses?

4 votes

I'm usually a PHP developer that has lots of experience with Drupal CMS & framework. And I realize Drupal is very mature, but I don't know much about the Python scene.

I've heard the following CMSs be mentioned:

  • Plone
  • Django (framework)

What other CMSs are there, and what do you think are some of the pros and cons? How mature are they? Is it even worth starting to use Python for general web development?

My vote is for Django CMS. Django itself is a development framework (but one that gives you a lot for free, including an excellent pluggable admin interface). DjangoCMS is an application that you can install into a Django application. I am using DjangoCMS and, as a Django user, I think it's perfect. I'm not what non-Django users would think. It's no Wordpress.

How come my South migrations doesn't work for Django?

4 votes

First, I create my database.

create database mydb;

I add "south" to installed Apps. Then, I go to this tutorial: http://south.aeracode.org/docs/tutorial/part1.html

The tutorial tells me to do this:

$ py manage.py  schemamigration wall --initial
>>> Created 0001_initial.py. You can now apply this migration with: ./manage.py migrate wall

Great, now I migrate.

$ py manage.py migrate wall

But it gives me this error...

django.db.utils.DatabaseError: (1146, "Table 'fable.south_migrationhistory' doesn't exist")

So I use Google (which never works. hence my 870 questions asked on Stackoverflow), and I get this page: http://groups.google.com/group/south-users/browse_thread/thread/d4c83f821dd2ca1c

Alright, so I follow that instructions

>> Drop database mydb;
>> Create database mydb;
$ rm -rf ./wall/migrations
$ py manage.py syncdb

But when I run syncdb, Django creates a bunch of tables. Yes, it creates the south_migrationhistory table, but it also creates my app's tables.

Synced:
 > django.contrib.admin
 > django.contrib.auth
 > django.contrib.contenttypes
 > django.contrib.sessions
 > django.contrib.sites
 > django.contrib.messages
 > south
 > fable.notification
 > pagination
 > timezones
 > fable.wall
 > mediasync
 > staticfiles
 > debug_toolbar

Not synced (use migrations):
 - 
(use ./manage.py migrate to migrate these)

Cool....now it tells me to migrate these. So, I do this:

$ py manage.py  migrate wall
The app 'wall' does not appear to use migrations.

Alright, so fine. I'll add wall to initial migrations.

$ py manage.py schemamigration wall --initial

Then I migrate:

$ py manage.py migrate wall

You know what? It gives me this BS:

_mysql_exceptions.OperationalError: (1050, "Table 'wall_content' already exists")

Sorry, this is really pissing me off. Can someone help ? thanks.

How do I get South to work and sync correctly with everything? The only thing I can think of is remove my app from INSTALLED_APPS, then run syncdb, then add it back on.

That is SO SILLY.

South allows you to create migrations when you first start out with a new app and the tables haven't been added to the database yet, as well as creating migrations for legacy apps that already have tables in the database. The key is to know when to do what.

Your first mistake was when you deleted your migrations, as soon as you did that, and then ran syncdb, Django didn't know that you wanted south to manage that app anymore, so it created the tables for you. When you created your initial migrations and then ran migrate, south was trying to create tables that django already created, and thus your error.

At this point you have two options.

  1. Delete the tables for the wall app from your database and then run $ py manage.py migrate wall This will run the migration and create your tables.

  2. Fake out the initial migration run $ py manage.py migrate wall 0001 --fake This will tell south that you already have the tables on the database so just fake it, which will add a row to the south_migrationhistory table, so that the next time you run a migrate it will know that the first migration has already been run.

Here are the steps for setting up south with a brand new project and no database.

  1. create your database
  2. add south to installed apps
  3. run syncdb, this will add the django and south tables to the database
  4. add your apps
  5. for each app run python manage.py schemamigration app_name --initial this will create the initial migration files for your app
  6. then run south migrate python manage.py migrate app_name this will add the tables to the database.

Here are the steps for setting up south with a legacy project and database

  1. add south to installed apps
  2. run syncdb, this will add the south tables to the database
  3. for each of your apps run python manage.py schemamigration app_name --initial This will create your initial migrations
  4. for each of your apps run python manage.py migrate app_name 0001 --fake , this will fake out south, it won't do anything to the database for those models, it will just add records to the south_migrationhistory table so that the next time you want to create a migration, you are all set.

Here are the steps for setting up south with a legacy project and no database

  1. create database
  2. add south to installed apps
  3. for each of your apps run python manage.py schemamigration app_name --initial This will create your initial migrations
  4. run syncdb, this will add any apps that don't have migrations to the database.
  5. then run south migrate python manage.py migrate this will run all migrations for your apps.

Now that you are setup with south, you can start using south to manage model changes to those apps. The most common command to run is python manage.py schemamigration app_name migration_name --auto that will look at the last migration you ran and it will find the changes and build out a migration file for you. Then you just need to run python manage.py migrate and it alter your database for you.

Hope that helps.

How can I disable Django's admin in a deployed project, but keep it for local development?

4 votes

I am currently working in a Django project for which I need access to the admin area for local development, but want to disable it in the deployed site (for security reasons, among others).

How can I achieve this programmatically (ie using settings.py).

Many thanks.

First, establish a scheme so that your production server can have different settings than your development servers. A simple way to do that is with a source-control-ignored local_settings.py file, but there are many fancier ways to do it.

Then, in your settings.py file, put:

ADMIN_ENABLED = True

and in your production-only settings file, put:

ADMIN_ENABLED = False

Then in your urls.py:

if settings.ADMIN_ENABLED:
    urlpatterns += patterns('',
        (r'^admin/(.*)', include(admin.site.urls)),
        # ..maybe other stuff you want to be dev-only, etc...
        )

Django ForeignKey _set on an inherited model

4 votes

I have two models Category and Entry. There is another model ExtEntry that inherits from Entry

class Category(models.Model):
    title = models.CharField('title', max_length=255)
    description = models.TextField('description', blank=True)
    ...

class Entry(models.Model):
    title = models.CharField('title', max_length=255)    
    categories = models.ManyToManyField(Category)
    ...

class ExtEntry(Entry):    
    groups= models.CharField('title', max_length=255)
    value= models.CharField('title', max_length=255)
    ...

I am able to use the Category.entry_set but I want to be able to do Category.blogentry_set but it is not available. If this is not available,then I need another method to get all ExtEntryrelated to one particular Category

EDIT My end goal is to have a QuerySet of ExtEntry objects

Thanks

I need another method to get all ExtEntryrelated to one particular Category

Easy:

ExtEntry.objects.filter(categories=my_category)

Do you know if there is a way to use the _set feature of an inherited

I don't know if there is a direct they for that. It is not mentioned in documentation.

But it is possible to get similar results with the select_related.

for e in category.entry_set.select_related('extentry'):
    e.extentry # already loaded because of `select_related`, 
               # however might be None if there is no Extentry for current e

It is possible to select only entries which has ExtEntry:

for e in category.entry_set.select_related('extentry').exlude(extentry=None):
    e.extentry # now this definitely is something, not None

Bad thing about the exclude is that it generates terrybly inefficient query:

SELECT entry.*, extentry.* FROM entry
LEFT OUTER JOIN `extentry` ON (entry.id = extentry.entry_ptr_id) 
WHERE NOT (entry.id IN (SELECT U0.id FROM entry U0 LEFT OUTER JOIN 
                        extentry U1 ON (U0.id = U1.entry_ptr_id) 
                        WHERE U1.entry_ptr_id IS NULL))

So my resume would be: use ExtEntry.objects.filter() to get your results. The backwards relations (object.something_set) is just a convenience and does not work in every situation.