Home > front end >  Django | Don't show the foreign key valules in dropdown which are already assigned
Django | Don't show the foreign key valules in dropdown which are already assigned

Time:06-16

I am working on a Hostel management system and new in Django field. I have a model Student and Bed . The models code is below:

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

I want that when I select a bed from Student Model dropdown, there should only display the beds which are not already assigned to some other students.

I have tried something like:

bed = models.ForeignKey(Bed, on_delete=models.CASCADE, null=True, blank=True).exclude(----)

but it does not work. I have searched around Please help.

CodePudding user response:

you must filter this field from admin file.

solution 1 for filtering in admin) for example, define a status field for the bed model with true value as default, after that override save method into Student model and with creating a student with a select bed, set status bed field to false

2 for filtering) query on all students and check which beds don't assigned, then show into the admin

but for admin file you have to follow something like the below link enter link description here.

or link 2

or search django admin filtering key word

CodePudding user response:

Assuming you're using a form and do not want to do this in the admin, you can do the following. First, add a related_name= argument to your bed field on the Student model, like so (could be any string) and make migrations and migrate:

bed = models.ForeignKey(Bed, on_delete=models.CASCADE, null=True, blank=True, related_name='all_beds')

Then, using a model form with a custom __init__ method, you can populate your dropdown with only those beds that are not assigned.

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)

Here's what's happening here. The init method is populating the choices on the bed field with whatever .queryset you pass to it.

In this case, you're using the related_name "all_beds" to refer back to the Student model. The all_beds__bed is looking at Student.bed, and all_beds__bed__isnull=True is asking the database to return all Bed instances that do not have some existing relation to Student.bed. In other words, if a Bed instance has some populated bed field on the Student model, do not add it to the queryset.

When you call this model form in your view, for example:

form = StudentForm()

...it will populate accordingly. If you need that form to be dynamically created with data only available in your view, say an ID number or user data, you can instantiate the modelform class in your view. It doesn't HAVE to be in a seperate forms.py file.

  • Related