nimasmi
nimasmi

Reputation: 4138

Django filter model using only unicode of an object

I have a model 'Objective', where the usual way to refer to objects is by the unicode method.

models.py:

class Objective(models.Model):
    level = models.IntegerField()
    strand = models.ForeignKey(Strand)
    order = models.IntegerField()
    description = models.TextField()
    def __unicode__(self):
        return u'%s%s%s' % (self.level, self.strand.code, self.order)

    class Meta:
        unique_together = ("strand", "level", "order")
        ordering = ['level', 'strand', 'order']

An example object in this model would be called e.g. 6ssm4, for the fourth entry in the ssm strand at level 6. I want to do my lookups (say from url parsing) by referring to this unicode string.

urls.py:

(r'^(?P<objective>[^/]+)/$', 'display_objective'),

I have tried all of the following variations as lines in views.py (not all at once!):

def display_objective(request, objective):
    theobjective = Objective.objects.get(unicode() = objective)
    theobjective = Objective.objects.get(self.unicode = objective)
    theobjective = Objective.objects.get(__unicode__ = objective)
    theobjective = Objective.objects.get(objective__iexact = objective)
    theobjective = Objective.objects.get(objective)
    theobjective = Objective.objects.get(unicode() = objective)

But if I go to http://localhost:8000/6ssm4/ I get the error page with errors like "Keyword can't be an expression" or "Cannot resolve keyword 'self' into field. Choices are: assessment, description, id, level, order, strand".

Is this a legitimate way to lookup objects, or should I be dissecting the keyword? If it is legit, what is the correct syntax?

Upvotes: 1

Views: 2487

Answers (1)

Elf Sternberg
Elf Sternberg

Reputation: 16361

The ORM converts filter lvalues (the things on the left side of the equals sign) into SQL lookup terms, which is why it has a limited syntax. You can't make a Python function a SQL lookup term; the database knows nothing about Python.

One correct way to do this would be to create a new field in your table, call it index or lookup, and then do this:

def save(self, *args, **kwargs):
    self.lookup = self.__unicode__()
    super(Objective, self).save(*args, **kwargs)

The lookup field becomes a pre-processed member of your table; every time you save an Objective, a lookup-ready version of it gets stored in the table. You can then:

theobjective = Objective.objects.get(lookup = objective)

Your alternative is to break the objective into its component parts and filter on level, strand, and order, but that only works if they're sufficiently regular for a regular expression.

This is a classic tradeoff of programmer time vs. responsiveness vs. storage (pick two). In this case, I've made the call that programmer time and responsiveness are more important that storage considerations.

Upvotes: 1

Related Questions