2015-10-14 62 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」。 –

相關問題