Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/python/314.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/django/21.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Python 使用django admin进行一对多内联选择_Python_Django_Django Models_Django Admin - Fatal编程技术网

Python 使用django admin进行一对多内联选择

Python 使用django admin进行一对多内联选择,python,django,django-models,django-admin,Python,Django,Django Models,Django Admin,我建立了一个标准的多对一关系。有很多字段,但出于我们的目的,相关模型如下: class Class(models.Model): name = models.CharField(max_length=128) class Student(models.Model): class = models.ForeignKey(Class) name = models.CharField(max_length=128) address = models.CharField

我建立了一个标准的多对一关系。有很多字段,但出于我们的目的,相关模型如下:

class Class(models.Model):
    name = models.CharField(max_length=128)

class Student(models.Model):
    class = models.ForeignKey(Class)
    name = models.CharField(max_length=128)
    address = models.CharField(max_length=128)
    # ...etc
我创建了一个管理员,效果很好。当我编辑一个学生时,它甚至可以自动为我设置类。然而,当我去创建/编辑一个类时,我得到的只是一个名称输入框


有没有办法添加一个框/字段,学生可以从班级管理页面添加为班级成员?我可以在线制作表单,但那是为了创建新的学生。我已经创建了我所有的学生,正在寻找一种快速方法,将多个现有学生添加到不同的班级。

有!您需要
InlineModelAdmin

简单的示例代码:

class StudentAdminInline(admin.TabularInline):
    model = Student

class ClassAdmin(admin.ModelAdmin):
    inlines = (StudentAdminInline, )
admin.site.register(Class, ClassAdmin)
这是Luke Sneeringer建议的“自定义表单”解决方案。不管怎么说,对于这个(相当自然而且可能是常见的)问题,没有现成的Django解决方案,我感到惊讶。我错过什么了吗

from django import forms
from django.db import models
from django.contrib import admin

class Foo(models.Model):
    pass

class Bar(models.Model):
    foo = models.ForeignKey(Foo)

class FooForm(forms.ModelForm):
    class Meta:
        model = Foo

    bars = forms.ModelMultipleChoiceField(queryset=Bar.objects.all())

    def __init__(self, *args, **kwargs):
        super(FooForm, self).__init__(*args, **kwargs)
        if self.instance:
            self.fields['bars'].initial = self.instance.bar_set.all()

    def save(self, *args, **kwargs):
        # FIXME: 'commit' argument is not handled
        # TODO: Wrap reassignments into transaction
        # NOTE: Previously assigned Foos are silently reset
        instance = super(FooForm, self).save(commit=False)
        self.fields['bars'].initial.update(foo=None)
        self.cleaned_data['bars'].update(foo=instance)
        return instance

class FooAdmin(admin.ModelAdmin):
    form = FooForm

您还可以通过第二个模型运行学生姓名,使其成为
外键。例如,在原始代码后添加:

class AssignedStudents(models.Model):
    assigned_to = models.ForeignKey(Class, on_delete=models.CASCADE)
    student = models.ForeignKey(Student, on_delete=models.CASCADE)
然后像Luke Sneeringer说的那样将内联添加到管理员。最后是一个下拉列表,您可以从中选择学生姓名。尽管如此,仍然可以选择创建新学生。

这可能有助于: 我使用了所描述的方法,但改变了方法
save
save_m2m
,方法如下:

from django import forms
from django.db import models
from django.contrib import admin

class Foo(models.Model):
     pass

class Bar(models.Model):
     foo = models.ForeignKey(Foo)

class FooForm(forms.ModelForm):
    class Meta:
        model = Foo

    bars = forms.ModelMultipleChoiceField(queryset=Bar.objects.all())

    def __init__(self, *args, **kwargs):
        super(FooForm, self).__init__(*args, **kwargs)
        if self.instance:
            self.fields['bars'].initial = self.instance.bar_set.all()

    def save_m2m(self):
        pass

    def save(self, *args, **kwargs):
        self.fields['bars'].initial.update(foo=None)
        foo_instance = Foo()
        foo_instance.pk = self.instance.pk
        # Copy all other fields.
        # ... #
        foo_instance.save()
        self.cleaned_data['bars'].update(foo=instance)
        return instance

class FooAdmin(admin.ModelAdmin):
    form = FooForm

如果目的是让学生独立于班级而存在,然后能够在班级中添加或删除他们,那么这将建立一种不同的关系:

  • 许多学生可以成为一个班级的一员
  • 一个学生可以参加许多课程
实际上,这描述的是一种多对多关系。简单交换

class Student(models.Model):
    class = models.ForeignKey(Class) ...
为了

将立即在Django admin中提供所需的效果


在2021年,这个问题没有直接的解决方案

我所做的是将
manytomy
symmetric=False
一起使用。多读一本。只有在这种情况下,您才能在
django admin

parent_questions = models.ManyToManyField('self', related_name='parent_questions',
                                         blank=True, symmetrical=False)

在Django 3.0.9中适合我的东西

模型中.py

from django import forms
from django.db import models

class Student(models.Model):
    name = models.CharField(max_length=100)
    course = models.ForeignKey(Course, on_delete=models.CASCADE, null=True, blank=True)

    def __str__(self):
        return self.name


class CourseForm(forms.ModelForm):

    students = forms.ModelMultipleChoiceField(
        queryset=Student.objects.all(), required=False
    )
    name = forms.CharField(max_length=100)

    class Meta:
        model = Student
        fields = ["students", "name"]

    def __init__(self, *args, **kwargs):
        super(CourseForm, self).__init__(*args, **kwargs)
        if self.instance:
            self.fields["students"].initial = self.instance.student_set.all()

    def save_m2m(self):
        pass

    def save(self, *args, **kwargs):
        self.fields["students"].initial.update(course=None)
        course_instance = Course()
        course_instance.pk = self.instance.pk
        course_instance.name = self.instance.name
        course_instance.save()
        self.cleaned_data["students"].update(course=course_instance)
        return course_instance

from django.contrib import admin
from .models import Student, Course

class StudentAdmin(admin.ModelAdmin):
    pass

class CourseAdmin(admin.ModelAdmin):
    form = CourseForm

admin.site.register(Student, StudentAdmin)
admin.site.register(Course, CourseAdmin)
管理py中

from django import forms
from django.db import models

class Student(models.Model):
    name = models.CharField(max_length=100)
    course = models.ForeignKey(Course, on_delete=models.CASCADE, null=True, blank=True)

    def __str__(self):
        return self.name


class CourseForm(forms.ModelForm):

    students = forms.ModelMultipleChoiceField(
        queryset=Student.objects.all(), required=False
    )
    name = forms.CharField(max_length=100)

    class Meta:
        model = Student
        fields = ["students", "name"]

    def __init__(self, *args, **kwargs):
        super(CourseForm, self).__init__(*args, **kwargs)
        if self.instance:
            self.fields["students"].initial = self.instance.student_set.all()

    def save_m2m(self):
        pass

    def save(self, *args, **kwargs):
        self.fields["students"].initial.update(course=None)
        course_instance = Course()
        course_instance.pk = self.instance.pk
        course_instance.name = self.instance.name
        course_instance.save()
        self.cleaned_data["students"].update(course=course_instance)
        return course_instance

from django.contrib import admin
from .models import Student, Course

class StudentAdmin(admin.ModelAdmin):
    pass

class CourseAdmin(admin.ModelAdmin):
    form = CourseForm

admin.site.register(Student, StudentAdmin)
admin.site.register(Course, CourseAdmin)

顺便说一下,将模型类命名为“class”时要非常小心。它确实有效,但稍后会咬到你(例如,在
学生的第一行中)。而且,
class=models.ForeignKey(class)
不起作用,因为“class”是一个保留字。已尝试实现,但这并不能满足我的需要。正如我在问题中所说的,我知道如何添加内联表单,但tablarinline是用来创建新对象的。我只想允许用户从我已有的学生列表中进行选择。我定义为相关的学生将显示在内联列表中。我想要一个内联设置现有的学生作为相关的。啊,我现在理解这个问题了。您可以定义一个自定义的
表单
类,并将其分配给
ModelAdmin
类的
表单
属性。这显然不能回答问题!它正在寻找一种将多个现有学生添加到不同班级的快速方法。。。再说一次,存在不是为了创造新的……我真的不知道我最终做了什么来解决这个问题。不过,我很确定这与此类似。是的,这真的很奇怪,他们没有预先制作/更简单的东西。我喜欢这个解决方案,但想确定你所说的“FIXME:‘commit’参数是热处理的”。这里的问题是什么?为了与ModelFormAPI保持一致,foo_form.save(commit=False)应该返回一个尚未保存到数据库的对象(请参阅);Howewer提供的实现忽略“提交”参数。您很可能不会使用commit=False;如果是这样,那就没有问题了。两年过去了,这仍然是我能找到的唯一解决办法——除非你知道任何新的发展?请问:self.fields['bar'].initial.update(foo=None)行的用途是什么?@zag你好!就在2018年,这是我发现的最相关的、实际上只有部分功能的代码,这是令人悲哀的。但是,当我试图保存Foo对象时。这给了我一个错误:未保存的模型实例不能用于ORM查询,有什么想法吗?没有办法。我在持续的谷歌搜索之后没有找到解决方案……是的,你刚才描述的是一种多对多的关系。我的问题不是关于这个,而是一对多。在Django3中,这是我找到的唯一解决方案,谢谢。我们必须重写
save_m2m
并手动创建一个实例,这很烦人,但是嘿。这实际上创建了一个多对多关系,其中
AssignedStudents
是关联表。它可以在管理界面中达到预期的效果,但代价是添加一个额外的表。我想在大多数情况下,这是一种不可接受的做法。