Установите ограничение для форм с одинаковым значением Django

#django #forms #limit

Вопрос:

Поэтому я хочу установить ограничение на количество форм с одинаковым значением. Существуют различные виды деятельности, отличные от иностранной модели, к которым студенты могут обратиться. У меня есть имя(naam), номер студента(studentnummer), активность(activiteit) и класс(klas), и я хочу установить ограничение в 10 форм с одним и тем же видом деятельности (максимальное количество людей, которые могут выполнять одно и то же действие) и ограничение в 1 для числа студентов (поэтому студенты могут подавать заявки только на одно занятие).

models.py

 class Klas(models.Model):  klas = models.CharField(max_length=8)   def __str__(self):  return f"{self.klas}"   class Activiteit(models.Model):  titel = CharField(max_length=64)  docent = CharField(max_length=32)  icon = models.ImageField()  uitleg = models.TextField()   def __str__(self):  return f"{self.id}:{self.titel}:{self.docent}"   class Aanmelden(models.Model):  naam = CharField(max_length=32)  studentnummer = IntegerField()  klas = ForeignKey(Klas, on_delete=models.CASCADE, default=None, blank=True)  activiteit = ForeignKey(Activiteit, on_delete=models.CASCADE, default=None, blank=True)   def __str__(self):  return f"{self.id}:{self.naam}:{self.studentnummer}"    

views.py

 def home(request):  activiteiten = Activiteit.objects.all()    form = AanmeldenForm()  if request.method == 'POST':  form = AanmeldenForm(request.POST)  if form.is_valid():  form.save()    return render(request, 'home.html', {  'activiteiten': activiteiten,  'form':form,  })  

forms.py

 class AanmeldenForm(forms.ModelForm):  class Meta:  model = Aanmelden  fields = (  'naam','studentnummer','klas','activiteit'  )  

Если вы знаете, как решить эту проблему, или у вас есть лучшая идея создания такой системы, пожалуйста, дайте мне знать. Заранее спасибо!!

Ответ №1:

Вероятно, вам понадобится переменная внутри вашего Aktiviteit класса, например, plaatsen_beschikbaar которая инициализируется в 10 при создании нового экземпляра an Aktiviteit . Затем при успешном Aanmelden переходе к экземпляру вы уменьшаете его на единицу. Вам нужно убедиться, что в вашей модели это plaatsen_beschikbaar не может быть меньше нуля, и если кто-то удалит aanmelding, увеличьте переменную на 1. Изменить: или вы используете валидатор, подобный приведенному ниже, для ограничения доступа. Вы также можете сделать так, чтобы ваша модель имела свойство@, которое возвращает значение plaatsen_beschikbaar вместо использования поля. С другой стороны, это кажется лучшим планом, поэтому это редактирование

Чтобы убедиться , что у ученика может быть только 1 Aanmelden , вы можете просто сделать свой studentnummer уникальный в своем Aanmelden классе. Но это делает вашу модель неуязвимой для будущего, если в будущем вы решите, что студенты могут подписаться на два или три мероприятия. В этом случае вам необходимо иметь отношение к внешнему ключу Student и ограничить его количество Aanmelden , которое может быть у учащегося, например, с помощью валидатора, подобного этому

 def beperk_aanmelden(value):  if Aanmelden.objects.filter(student_id=value).count() gt;= 1:  raise ValidationError('Student heeft al de maximale aanmeldingen')  else:  return value  

Затем в вашей Aanmelden модели:

 student = ForeignKey(Student, validators=[beperk_aanmelden,])  

Изменить: на основе вашей текущей модели это будет выглядеть так:

 def beperk_aanmelden(value):  if Aanmelden.objects.filter(studentnummer=value).count() gt;= 1:  raise ValidationError('Student heeft al de maximale aanmeldingen')  else:  return value  

И в вашей модели:

 studentnummer = IntegerField(validators=[beperk_aanmelden,])  

Правка 2:

Чтобы проверить plaatsen_beschikbaar , вы могли бы сделать что-то вроде этого:

 def beperk_activiteit(value):  if Activiteit.objects.get(activiteit_id=value).plaatsen_beschikbaar lt;= 0:  raise ValidationError('Activiteit heeft geen plaatsen beschikbaar meer! Kies een andere activiteit.')  

Затем для поля в вашей модели:

 activiteit = ForeignKey(Activiteit, on_delete=models.CASCADE, default=None, blank=True, validators=[beperk_activiteit,])  

Правка 3:

Для plaatsen_beschikbaar этого я бы сделал что-то подобное. В каждом Activiteit из них есть capaciteit место, где вы устанавливаете максимальное количество доступных мест. Затем определите @property , что дает вам вычисляемое поле, не относящееся к бд, к которому вы можете получить доступ точно так же, как к обычному полю. Разница в том, что он не сохраняется, а пересчитывается каждый раз, когда вы обращаетесь к нему. Внутри подсчитайте количество экземпляров Aanmelden , имеющих Activiteit экземпляр в качестве связанного объекта. Это ваш номер уже забронированного места. Затем вычтите это из capaciteit , и у вас будет текущий plaatsen_beschikbaar

 class Activiteit(models.Model):  titel = CharField(max_length=64)  docent = CharField(max_length=32)  icon = models.ImageField()  uitleg = models.TextField()  capaciteit = models.IntegerField()   @property  def plaatsen_beschikbaar(self):  geboekt = Aanmelden.objects.filter(activiteit_id=self.id).count()  return self.capaciteit - geboekt   def __str__(self):  return f"{self.id}:{self.titel}:{self.docent}"  

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

1. Эй, первый вариант работает идеально, но у меня возникли некоторые проблемы с применением второго, потому что у меня нет класса для студентов. Как я мог создать студенческий класс и при этом включить его в ту же форму, что и Aanmelden? идея заключается в том, что люди анонимно заходят на сайт, заполняют форму и попадают в группу активности.

2. @enmanuel-v I Валидатор также должен работать для целого числа studentnummer=value в валидаторе, а затем в модели studentnummer = Integerfield(validators=[beperk_aanmelden,])

3. @Enmanuel-V обновил мой ответ

4. @Enmanuel-V Извините, я только что понял, что забыл добавить return функцию проверки в свой первоначальный ответ. Прошу прощения! Я просто поправил.

5. Затем вам придется провести некоторую отладку. К сожалению, я в постели с ковидом и отвечаю тебе по памяти на мобильный телефон, лол. Проверьте plaatsen_beschikbaar , возвращает ли оно правильное значение. Возможно, валидатор не совсем работает? Вместо проверки поля с помощью валидатора вы также можете легко сделать это внутри clean(self) метода вашей Aanmelden модели, что проще для понимания. Посмотрите на документы, которые я ссылал выше. Внутри clean(self) вы проверяете, достаточно ли plaatsen_beschikbaar, и вызываете ошибку проверки, если ее нет.