Создание списка выбора из одного поля в другое через внешний ключ Django
У меня есть две модели, связанные между собой внешним ключом, как показано ниже :
class Service(models.Model):
title = models.CharField(max_length=100)
counter = models.PositiveIntegerField()
def __str__(self) -> str:
return f'{self.title}'
class Reservation(models.Model):
user = models.ForeignKey(User, on_delete=models.CASCADE)
service = models.ForeignKey(Service, on_delete=models.CASCADE)
turn = models.PositiveIntegerField()
def __str__(self) -> str:
return f'{self.user}'
Я хочу сделать так: поле turn
в Reservation
получает опцию choices
и значения выбора от 1 до service.counter
. service
является внешним ключом. Например, если counter
в модели Service
равно 5, то поле turn
в Reservation
будет выглядеть следующим образом :
turn = models.PositiveIntegerField(choices=[1,2,3,4,5])
. цикл for явно не будет работать :) .
Должен ли я создать поле property
или класс Meta?
В любом случае, как я могу изменить мое поле таким образом?
Любая помощь будет признательна и благодарна.
Вариант 1: Только Service
уже существует, а вы хотите создать совершенно новый Reservation
и позволить пользователю выбрать подключенный Service
. Ответ на этот вариант, скорее всего, не будет найден в django, бэкенде, а должен быть обработан во фронтенде. Причина в том, что требуется переключать возможные варианты turn
на лету, когда пользователь выбирает другой подключенный Service
.
Вариант 2: Начальный Reservation
-объект с подключенным Service
уже существует, когда пользователю предлагается выбрать turn
. Это можно сделать с помощью django. Но не на уровне models.py. Эта логика должна быть в forms.py. Нам нужна модель формы, в которой нужно заполнить только поле turn
.
class ReservationForm(forms.ModelForm):
class Meta:
model = Reservation
fields = ['turn']
widgets = {
'turn': forms.Select(), # Set the widget for the 'turn' field to Select
}
def __init__(self, *args, **kwargs):
service_instance = kwargs.pop('service_instance', None)
super(ReservationForm, self).__init__(*args, **kwargs)
if service_instance:
# Set the choices for the 'turn' field based on the service instance's counter
self.fields['turn'].choices = [(i, i) for i in range(service_instance.counter + 1)]
else:
# If no service instance is provided, default to an empty list
self.fields['turn'].choices = []
# views.py
service_instance = Service.objects.get(id=service_id)
form = ReservationForm(service_instance=service_instance)
Выше показано, как делать динамические формы. По сути, вы заранее выбираете в представлении, что вы хотите передать форме. Затем в методе __init__
вы перехватываете это и устанавливаете соответствующим образом.
Поскольку вы сказали, что эта форма всегда уже привязана к объекту и, следовательно, уже подключена к службе, вы можете выбрать этот вариант:
class ReservationForm(forms.ModelForm):
class Meta:
model = Reservation
fields = ['turn']
widgets = {
'turn': forms.Select(), # Set the widget for the 'turn' field to Select
}
def __init__(self, *args, **kwargs):
super(ReservationForm, self).__init__(*args, **kwargs)
# next line checks if an object is already connected to the form and a service connected
service_id = self.data.get('service') if self.is_bound else None
if service_id:
try:
service_instance = Service.objects.get(id=service_id)
# Set the choices for the 'turn' field based on the service instance's counter
self.fields['turn'].choices = [(i, i) for i in range(service_instance.counter + 1)]
except Service.DoesNotExist:
# If the service does not exist, default to an empty list
self.fields['turn'].choices = []
else:
# If no service ID is provided, default to an empty list
self.fields['turn'].choices = []
# views.py
# here you need to pass an instance to the form
form = ReservationForm(request.POST, instance=Reservation.objects.get(id=1)