Сохраните уникальный идентификатор заказа для каждой компании в django

#django #django-models #django-views #django-forms

#django #django-модели #django-просмотры #django-forms

Вопрос:

Я хотел бы иметь уникальный id_order для каждой компании, и если он уже существует, я не могу сохранить заказ или форма недействительна. В моем примере каждая компания сохраняет заказы, компания A может сохранять id_order 1 id_order 2 id_order 3 … Компания B может сохранить id_order 10 id_order 20 id_order 30… теперь я хочу, чтобы компания A не могла сохранить два раза id_order 3 или компания B не может сохранить два раза 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)
 

Формы:

 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)
 

Ответ №1:

Вы можете добавить уникальное ограничение для пары company и 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'
            )
        ] 

Однако я бы не стал хранить модель last_order at the company. Это может быть проблемой, поскольку идентификаторы заказов сами по себе не отправляются по порядку, например, возможно, что последний идентификатор заказа есть 4 , тогда как уже есть 5 .

Для компании вы можете просто вычислить максимальное значение и увеличить его на единицу:

 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 

Вы также можете рассмотреть DecimalField возможность замены decimal_places=0 with на BigIntegerField [Django-doc].

Комментарии:

1. отлично ! большое спасибо. пожалуйста, есть ли какое-либо решение в случае уже существующего сообщения об ошибке, чтобы показывать только уже существующее сообщение об ошибке или поле вместо желтой страницы ошибок со значением исключения: заказ не может быть создан, поскольку данные не были проверены.