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
- 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
- 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("/")) + 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()
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:
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