Django ManyToManyField,它指定了一个中间模型。通过OneToOneField关系

时间:2015-10-14 18:27:58

标签: python django forms django-forms

我有一个模型设置,我在研究中没有遇到过。它是一个带有直通关系表的模型,它是OneToOne关系。

问题是在表单中设置预订时,Admin界面正常工作。

 class AgentForm(forms.ModelForm):
     class Meta:
         model = Agent

但是创建一个Basic ModelForm会导致错误:

AttributeError: Cannot set values on a ManyToManyField which specifies an intermediary model.  Use podman.BladeReservation's Manager instead.

models.py

class Node(models.Model):
    name = models.CharField(_('Name'), help_text=_('A name for the node.'), max_length=128)
    hostname = models.CharField(
        verbose_name=_('Hostname'),
        max_length=255,
        blank=True, null=True
    )
    class Meta:
        abstract = True
        ordering = ['name', 'hostname']

class Blade(Node):
    serial_number = models.CharField(_('Serial Number'), max_length=255, unique=True)
    uuid = models.CharField(
        verbose_name=_('UUID'),
        help_text=_('Node UUID'),
        max_length=50,
        null=True, blank=True
    )
    ...

class Agent(models.Model):
    name = models.CharField(_('Name'), max_length=128, help_text=_('This name is a friendly handle for humans.'))
    slug = models.SlugField(
        verbose_name=_(u'Slug'),
        help_text=_('Uri identifier. This name is the lookup key for Automation'),
        max_length=100,
        unique=True
    )
    ...

    blades = models.ManyToManyField('podman.Blade', related_name='blades', through='podman.BladeReservation')
    ...

class BladeReservation(models.Model):
    blade = models.OneToOneField('podman.Blade')
    agent = models.ForeignKey('podman.Agent')
    reserved_until = models.DateTimeField(null=True, blank=True)

admin.py

class AgentAdmin(CompareNoDuplicates):
    prepopulated_fields = {'slug': ('name',)}
    inlines = [BladeReservationInline]
    filter_horizontal = ('blades',)
    list_display_links = ('__str__',)
    preserve_filters = True

class BladeReservationInline(admin.TabularInline):
    model = BladeReservation

    def get_formset(self, request, obj=None, **kwargs):
        kwargs['formfield_callback'] = partial(self.formfield_for_dbfield, request=request, obj=obj)
        return super(BladeReservationInline, self).get_formset(request, obj, **kwargs)

    def formfield_for_dbfield(self, db_field, **kwargs):
        agent = kwargs.pop('obj', None)
        formfield = super(BladeReservationInline, self).formfield_for_dbfield(db_field, **kwargs)
        if db_field.name == "blade" and agent:
            formfield.queryset = formfield.queryset.filter(chassis__pod__in=[p for p in agent.container.pods.all()])
        return formfield

我目前正在制作一个WizardView来获取自定义表单流,但它并不理想。任何想法都将不胜感激。

1 个答案:

答案 0 :(得分:5)

您很可能会收到此错误,因为您尝试直接创建Agent - Blade关系,但docs说:

  

你不能只在一个人和一个群体之间建立一种关系 -   您需要指定所需关系的所有详细信息   会员制模式。简单的添加,创建和赋值调用   不提供指定此额外细节的方法。结果,他们   对于使用中间件的多对多关系禁用   模型。创建这种关系的唯一方法是创建   中间模型的实例。

但是,由于reserved_until模型中的BladeReservation字段可以为空,这可能会对您有所帮助:

class BladeReservation(models.Model):
    # ...
    class Meta():
        auto_created=True