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.