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

前端 未结 4 1494
南旧
南旧 2021-02-14 02:09

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

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


        
相关标签:
4条回答
  • 2021-02-14 02:40
    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):
           original_students = obj.student_set.all()
           new_students = form.cleaned_data['students']
           remove_qs = original_students.exclude(id__in=new_students.values('id'))
           add_qs = new_students.exclude(id__in=original_students.values('id'))
           for item in remove_qs:
               obj.student_set.remove(item)
           for item in add_qs:
               obj.student_set.add(item)
           obj.save()
    
    0 讨论(0)
  • 2021-02-14 02:41

    I did what felix suggested. the only problem is that it gives a error like this:

    ValueError: Unsaved model instance <School: disscount_None> cannot be used in an ORM query.
    

    and the reason I found was that you can not change the foreign key in student's object BEFORE saving your current School model. because there is nothing to add to fk attribute yet! so use felix solution but in save_model function use the obj.save() before "for"

       def save_model(self, request, obj, form, change):
           original_students = obj.student_set.all()
           new_students = form.cleaned_data['students']
           remove_qs = original_students.exclude(id__in=new_students.values('id'))
           add_qs = new_students.exclude(id__in=original_students.values('id'))
    
    
           obj.save()   
    
           for item in remove_qs:
                   obj.student_set.remove(item)
           for item in add_qs:
                   obj.student_set.add(item)
               
    
    0 讨论(0)
  • 2021-02-14 02:44

    You can disable the inline 'add' permission. See InlineModelAdmin

    0 讨论(0)
  • 2021-02-14 02:46

    Do you mean that for a given School instance you want to be able to get a list of all the students related to that school?

    In which case you use the related_name attribute of the ForeignKey relationship you specified. You haven't defined the related_name where you do:

    school = models.ForeignKey(School)
    

    which is fine, it just uses the default related name which is the name of the child class (student) followed by _set

    so for your school instance:

    school = School.objects.get(pk=1)
    students = school.student_set.all()  # or .filter() or .exclude() etc
    

    then you can pass that student queryset into your template.

    0 讨论(0)
提交回复
热议问题