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)
Вернуться на верх