views:

147

answers:

3
def __number():
    # This line returns the number of the latest created object
    # as a "Factura" object in format "n/year"
    last = Factura.objects.filter(f_type__exact=False).latest('number')

    # We convert it into a string and split it to get only the first number
    spl = str(last).split('/')[0]

    # Convert it into integer so we can do math
    n = int(spl)

    # Get the current year
    y = date.today().strftime('%y')

    # If none return 1/year
    if n == None:
        return str(1) + '/' + str(y)

    # Else we increment the number in one.
    else:
        n = n + 1
        return str(n) + '/' + str(y)

What it does: It autogenerates a number in the format '1/year' '2/year' etc. If the user introduces other number, p.e. 564/10 the function follows it and the next will be 565/10.

Even if the user introduces p.e. 34/10 after the entry with 564/10 the function will follow the largest number.

Did I do this right or there's a better way to do it?


Update:

def __number():
    current_year = date.today().strftime('%y')
    try:
        facturas_emmited = Factura.objects.filter(f_type__exact=False)
        latest_object = facturas_emmited.latest('number').__str__()
        first_number = int(latest_object.split("/")[0]) + 1
    except Factura.DoesNotExist:
        first_number = 1
    return '%s/%s' % (first_number, current_year)
+1  A: 

Can last be None? If so it would be good to check for that:

# get last as before

if last:
    n = int(str(last).split("/")[0]) + 1
else:
    n = 1

# get y as before

return str(n) + "/" + str(y)

Another improvement here is that you only build the result string in one place.

I don't know what the Factura object is, but can you not get the value of n by calling some method on it? This would be better than converting it to a string, splitting it and taking the last part.

Richard Fearn
`last` can't be None (if no objects are found it raises a DoesNotExist exception), but I can wrap it in a try:...except clause. I'll put the code in the question. Also, there's no way to obtain `n` directly since `number` is a string.
Oscar Carballal
+2  A: 

This is really just the beginning, but I'd start by replacing some comments with self-documenting code.

def __number():
    # "Factura" object in format "n/year"
    latest_object = Factura.objects.filter(f_type__exact=False).latest('number')

    # Better name can be available if you explain why the first number is important and what it means
    # Do Factura objects not have a __repr__ or __str__ method that you must cast it?
    first_number = int(str(latest_object).split('/')[0])
    current_year = date.today().strftime('%y')
    # Use "is None" rather than "== None"
    if first_number is None:
        return '1/%d' % current_year
    # No else needed because of return above
    # Why do we add 1 to first number? Comments should explain _why_, not how
    return '%d/%d' % (first_number + 1, current_year)
Daenyth
The comments where just to explain the code here, in fact, the function isn't documented yet (my fault). BTW first_number can't be None.
Oscar Carballal
There's a `__str__` method I can use, but the latest_object variable is getting huge. What can I do about that?
Oscar Carballal
A: 

I solved similar problem some time ago by using object.id/year (where object/id is database id).

It guarantees that this will be unique, autoincremented (you don't need to do n = n + 1, which theoretically can lead to duplicate values in a db).

You can do this by overriding save method and only trick is that you need first to save an object (id is assigned) and then create id/year number and save again (maybe there is better way to do this than double save).

def save(self, force_insert = False, force_update = False):
    super(Factura, self).save(force_insert, force_update)
    current_year = date.today().strftime('%y')
    self.identifier = '%s/%s'%(self.id, current_year)
    super(Factura, self).save(force_insert, force_update)
Lukasz Dziedzia
Yeah, but in my case that method has 2 problems: a) It creates number/year for every Factura object, instead of doing only for the ones with f_type=False. b) My function is called on field.default() so as soon as you add an object, the field is autofilled with the number. Thanks anyway for the answer :)
Oscar Carballal
I just wanted to show some different approach. You can easily modify this for your needs:def save(self, force_insert = False, force_update = False): super(Factura, self).save(force_insert, force_update) if self.f_type: current_year = date.today().strftime('%y') self.identifier = '%s/%s'%(self.id, current_year) super(Factura, self).save(force_insert, force_update)
Lukasz Dziedzia
BTW in my use case, the user can start either by 1 or any other number, (p.e. the first object can be 342/10) so the generator must follow it. If use PK it can only follow the PK order (342/10 will become 1/10)
Oscar Carballal