2015-10-14 55 views
2

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

问题是管理员界面在窗体中设置保留时工作正常。

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

但是,创造一个基本的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只是为了让自定义表单流程,但它并不理想。任何想法,将不胜感激。

+0

显示你在那里处理表格的部分 – chem1st

回答

5

最有可能你得到这个错误,因为你尝试创建Agent - 直接Blade关系,但是docs说:

You can’t just create a relationship between a Person and a Group - you need to specify all the detail for the relationship required by the Membership model. The simple add, create and assignment calls don’t provide a way to specify this extra detail. As a result, they are disabled for many-to-many relationships that use an intermediate model. The only way to create this type of relationship is to create instances of the intermediate model.

但由于在BladeReservation型号搜索reserved_until字段允许为空,这可能帮助你:

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

太棒了!这在这种情况下适用于我的需求。只要我保持这些字段可以为空,就可以工作。 –

+2

我认为这是最初的神奇解决方案。唯一的问题是它会创建一个试图删除现有m2m表的新迁移。 如果删除以前的迁移,它只是不会在m2m表中添加额外的字段。 – oailloud

+1

@ oailloud的评论非常重要。一种解决方法是在设置auto_created之前设置'makemigrations',然后添加'managed = False'来防止Django的迁移引擎试图搞乱它。当然,如果需要更改表结构,但它“有效”,则需要临时移除“managed = False”。 –

相关问题