youssefmohamed
youssefmohamed

Reputation: 145

Save a unique order id for each company in django

I would like to have a unique id_order per company, and if already exist, i cannot save the order or form is not valid. In my example, each company save orders, Company A can save id_order 1 id_order 2 id_order 3 ... Company B can save id_order 10 id_order 20 id_order 30... what i want now is that company A cannot save two times id_order 3 or company B cannot save two times id_order 20.

class Company(models.Model):
    name = models.CharField(max_length=240)
    last_order = models.DecimalField(max_digits=20, decimal_places=0)

class Order(models.Model):
    company = models.ForeignKey('Company', on_delete=models.CASCADE)
    id_order = models.DecimalField(max_digits=20, decimal_places=0)

    def save(self, *args, **kwargs):
        created = not self.pk
        super().save(*args, **kwargs)
        if created:
            Company.objects \
                .filter(pk=self.company_id) \
                .update(last_order=self.id_order)

Forms:

class OrderForm(ModelForm):

    class Meta:
        model = Order

    def __init__(self, company , *args, **kwargs):
        super(OrderForm, self).__init__(*args, **kwargs)
        self.fields['company'] = forms.ModelChoiceField(queryset=Company.objects.filter(name=company), initial = company)
        try:
            code = company.last_order + 1
            self.fields["id_order"].initial = code
        except Exception as e:
            print(e)

Upvotes: 1

Views: 193

Answers (1)

willeM_ Van Onsem
willeM_ Van Onsem

Reputation: 477190

You can add a unique constraint on the couple company and id_order:

class Order(models.Model):
    company = models.ForeignKey('Company', on_delete=models.CASCADE)
    id_order = models.IntegerField(max_digits=20, decimal_places=0)

    # …

    class Meta:
        constraints = [
            models.UniqueConstraint(
                fields=['company', 'id_order'],
                name='unique_per_company'
            )
        ]

I would however not store the last_order at the company model. This might be a problem since the order ids are not per se dispatched in order, for example it is possible that the last order id is 4, whereas there is already a 5.

For a company you can simply calculate the maximum value and increment this with one:

from django.db.models import Max

class OrderForm(ModelForm):

    class Meta:
        model = Order

    def __init__(self, company , *args, **kwargs):
        super(OrderForm, self).__init__(*args, **kwargs)
        self.fields['company'] = forms.ModelChoiceField(queryset=Company.objects.filter(pk=company.pk), initial=company)
        code = (company.order_set.aggregate(
            max_id=Max('id_order')
        )['max_id'] or 0) + 1
        self.fields["id_order"].initial = code

You also might want to consider replacing the DecimalField with decimal_places=0 with a BigIntegerField [Django-doc].

Upvotes: 1

Related Questions