Incremental auto-filled fields in django-admin

Lately I’m working a lot with django and I had to implement a function which, as far as I have seen, lots of people need but everytime someone asks a django guru, the answer is: “Just use/hack the primary key!”.

But there are some use cases where the primary key does not meet the requierements, because you need:

  • An auto-filled field, before calling the save() method.
  • A particular data format (in my case number/year).
  • To be incremental, just like the PK.

To implement this I’ve used the new update of the default() parameter, which allows us to call functions. The problems:

  • That field had to be unique across all the DB (we can use unique=True).
  • If no objects, default to 1 (p.e. 1/2010).
  • If the user needs to jump to another number, p.e. from 75/2010 to 465/2010 the function must follow it and continue from the highest one.

So this is what I did. My model is called “Bill”, and this is the final code: (I have ommitted the imports)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
class Bill(models.Model):
    def __number():
        """
        Automatic bill number generator.
 
        bill_emmited: returns a list with all the bill objects
                      with bill_type=False
        latest_object: from bill_emmited get the latest one
                       and convert it to string to manipulate
        first_number: returns the first number of the latest_object field
                      and increments in 1
        If there's no bill objects, return first_number=1. The overall
        function returns either an incremented first_number slash year or
        one slash year.
        """
        current_year = date.today().strftime('%Y')
        try:
            bill_emmited = Bill.objects.filter(bill_type__exact=False)
            latest_object = bill_emmited.latest('number').__str__()
            first_number = int(latest_object.split("/")[0]) + 1
        except Bill.DoesNotExist:
            first_number = 1
        return '%s/%s' % (first_number, current_year)
 
    number = models.CharField(_('Bill number'), max_length=10, unique=True, \
    default=__number)
    # True for incoming, False for outgoing
    bill_type = models.BooleanField()

The bill_type variable is for setting the bill as incoming or outgoing. Since we only need to enumerate the outgoing ones we filter by it.

Take in care:

The latest() function is supposed to be used only with date fields, but after all the tests it became clear that the function could figure out which of the number fields is the highest, so take this in care: latest() is not designed to work like this, it’s an exceptional case. See it’s documentation

Escrito el 30 de junio, 2010 en django, django-admin, english, python.

Deja un comentario:

I you want to put code you must enclose it between -pre- tags like this:

<pre lang="SOURCE CODE LANGUAGE" line="1">your code</pre>