Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

django admin - select reverse foreign key relationships (not create, I want to add available)

Lets say I have a model School and another model Student.

class Student(models.Model):
   school = models.ForeignKey(School)
   name = models.CharField(max_length=100)

When a school is clicked in admin, then a new page appears showing school model fields and values.

I also want to select the already available list of students in that page itself.

Inlines is different, they will allow the ability to create and edit new records(student) belonging to that school. But I don't want that, lets assume there are already many student records available. I should be able to select them in admin from that school model page.

like image 327
user2139745 Avatar asked Aug 29 '13 07:08

user2139745


People also ask

How do I add a ForeignKey to a Django model?

Create a (default) object of the foreign model. It will automatically have id=1 (if no object existed yet). Change your foreignkey field by replacing null=True, blank=True by default=1 to associate that new object you created to all existing rows.

Can I have multiple foreign keys in a table Django?

If you have more than one foreign key, a validation error will be raised. Your intermediate model must contain one - and only one - foreign key to the source model (this would be Group in our example). If you have more than one foreign key, a validation error will be raised.

What does ForeignKey mean in Django?

What is ForeignKey in Django? ForeignKey is a Field (which represents a column in a database table), and it's used to create many-to-one relationships within tables. It's a standard practice in relational databases to connect data using ForeignKeys.


1 Answers

class SchoolAdminForm(forms.ModelForm):
    students = forms.ModelMultipleChoiceField(
        queryset=Student.objects.all(),
        widget=FilteredSelectMultiple(verbose_name='students', is_stacked=False))

    class Meta:
        model = School
        fields = ['your_school_fields_go_here']

    def __init__(self, *args, **kwargs):
        super(SchoolAdminForm, self).__init__(*args, **kwargs)
        if self.instance:
            # fill initial related values
            self.fields['students'].initial = self.instance.student_set.all()

class SchoolAdmin(admin.ModelAdmin):
   form = SchoolAdminForm

   def save_model(self, request, obj, form, change):
       super().save_model(request, obj, form, change)
       original_students = set(obj.student_set.values_list("id", flat=True))
       current_students = set(map(lambda x: x.id, form.cleaned_data['students']))
       if original_students != current_students:
           add_to_school = current_students - original_students
           Student.objects.filter(id__in=add_to_school).update(school_id=obj.id)
           remove_from_school = original_students - current_students
           Student.objects.filter(id__in=remove_from_school).update(school_id=None)
like image 102
felix Avatar answered Sep 21 '22 01:09

felix