Django ManyToManyField 指定了一个中介模型。通过 OneToOneField 关系
Django ManyToManyField which specifies an intermediary model. Through a OneToOneField Relationship
我有一个我在研究中没有遇到过的模型设置。这是一个具有直通关系 table 的模型,即 OneToOne 关系。
问题是在表单中设置预订时管理界面工作正常。
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 只是为了获得自定义表单流,但它并不理想。任何想法将不胜感激。
您很可能会收到此错误,因为您尝试直接创建 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
我有一个我在研究中没有遇到过的模型设置。这是一个具有直通关系 table 的模型,即 OneToOne 关系。
问题是在表单中设置预订时管理界面工作正常。
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 只是为了获得自定义表单流,但它并不理想。任何想法将不胜感激。
您很可能会收到此错误,因为您尝试直接创建 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