2015-10-14 3 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.

Но так как ваш reserved_until поле в BladeReservation модели позволено быть пустым, это может помочь вам :

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

Удивительный! В этом случае это работает для моих нужд. Пока я сохраняю поля как обнуляемые, он работает. –

+2

Я думал, что это было волшебное решение. Проблема только в том, что он создаст новую миграцию, которая пытается удалить существующую таблицу m2m. Если вы удалите предыдущие миграции, он просто не добавит лишние поля в таблицу m2m. – oailloud

+1

@ Замечание oailloud очень важно. Один из способов решения проблемы - «makemigrations» перед установкой auto_created, а затем добавьте 'managed = False', чтобы предотвратить работу механизма переноса Django. Конечно, вам нужно временно удалить «managed = False», если вам нужно изменить структуру таблицы, но она «работает». –

Смежные вопросы