Django | Не показывать в выпадающем списке значения внешнего ключа, которые уже назначены
Я работаю над системой управления хостелом и новичок в области Django. У меня есть модель Student и Bed . Код моделей приведен ниже:
class Bed(models.Model):
name = models.CharField("Bed No.",max_length=200)
room = models.ForeignKey(Room, on_delete=models.CASCADE, default='1')
class Meta:
verbose_name_plural = "Bed"
def __str__(self):
return self.name
class Student(models.Model):
name = models.CharField("name",max_length=200)
cell_no = models.CharField("cell No",max_length=200)
photo = models.ImageField(upload_to ='students_pics/')
emergency_cell_no = models.CharField("Emergency Cell No", max_length=200)
bed = models.ForeignKey(Bed, on_delete=models.CASCADE, null=True, blank=True)
created_at = models.DateTimeField(auto_now_add=True)
class Meta:
verbose_name_plural = "Student"
def __str__(self):
return self.name
Я хочу, чтобы при выборе кровати из выпадающего списка "Модель студента" отображались только те кровати, которые еще не назначены другим студентам.
Я пробовал что-то вроде:
bed = models.ForeignKey(Bed, on_delete=models.CASCADE, null=True, blank=True).exclude(----)
но это не работает. Я все обыскал Пожалуйста, помогите.
вы должны отфильтровать это поле из файла администратора.
решение 1 для фильтрации в админке) например, определите поле status для модели кровати со значением true по умолчанию, затем переопределите метод save в модели Student и при создании студента с выбранной кроватью установите поле status bed в false
2 для фильтрации) сделать запрос на всех студентов и проверить, какие кровати не назначены, затем показать в админке
но для файла администратора вам нужно перейти по ссылке, приведенной ниже введите описание ссылки здесь.
или ссылка 2
или поиск django admin фильтрация ключевого слова
Предполагая, что вы используете форму и не хотите делать это в админке, вы можете сделать следующее. Во-первых, добавьте аргумент related_name=
к вашему полю bed
в модели Student
, например, так (это может быть любая строка) и сделайте миграции и migrate:
bed = models.ForeignKey(Bed, on_delete=models.CASCADE, null=True, blank=True, related_name='all_beds')
Затем, используя модель формы с пользовательским методом __init__
, вы можете заполнить выпадающий список только теми кроватями, которые не назначены.
class StudentForm(forms.ModelForm):
class Meta:
model = Student
fields = ['name', 'cell_no', 'emergency_cell_no', 'bed', 'photo']
def __init__(self, *args, **kwargs):
super (StudentForm, self).__init__(*args, **kwargs)
self.fields['bed'].queryset = Bed.objects.filter(all_beds__bed__isnull=True)
Вот что здесь происходит. Метод init заполняет варианты выбора в поле bed
тем .queryset
, что вы ему передаете.
В данном случае вы используете related_name
"all_beds" для ссылки на модель Student
. Модель all_beds__bed
смотрит на Student.bed
, а all_beds__bed__isnull=True
просит базу данных вернуть все экземпляры Bed
, которые не имеют некоторого существующего отношения к Student.bed
. Другими словами, если экземпляр Bed
имеет какое-то заполненное поле bed
в модели Student
, не добавляйте его в набор запросов.
Когда вы вызываете эту модель формы в вашем представлении, например:
form = StudentForm()
... она будет заполняться соответствующим образом. Если вам нужно, чтобы форма динамически создавалась с данными, доступными только в вашем представлении, например, ID номер или данные пользователя, вы можете инстанцировать класс modelform в вашем представлении. Это не обязательно должно быть в отдельном forms.py
файле.
Вышеприведенный ответ работает так, как ожидалось в вопросе. Но когда я обновляю форму студента, поле формы "кровать" не заполняется значениями. Я также использовал instance=student
. Мой код для обновления вида выглядит следующим образом:
def updatestudent(request,id):
student = Student.objects.get(pk=id)
form = StudentForm(instance=student)
if request.method == 'POST':
#print('Printing Post:', request)
form = StudentForm(request.POST, instance=student)
if form.is_valid():
form.save()
messages.success(request, "Student updated successfully.")
return redirect('/student/view/'+id)
context= {'form':form}
return render(request, 'new-student.html', context)