Dango3: Setting up OneToOne relationships correctly

75 Views Asked by At

I want to generate several related Model objects at once that are linked in the model view via stacked.Inline. I can create the objects in the admin view. However, when I go to the list view of the pipeline model I get:

'Pipeline' object has no attribute 'args'

I have pretty much the same setup working with other models, so I am not sure why it is not working in this case. It complains that 'Pipeline' has no args

model.py:

class Pipeline(models.Model):
    config= models.OneToOneField('Config', on_delete=models.SET_NULL, null=True, parent_link=True)


class Config(models.Model):
    args = models.CharField(max_length=256, null=True, default='-p -q -x -u -l -m -r')        
    pipeline = models.OneToOneField('Pipeline', on_delete=models.CASCADE, null=True, parent_link=False)

admin.py:

class ConfigInline(admin.StackedInline):
    model = Config


class PipelineAdmin(admin.ModelAdmin):
    inlines = [ConfigInline]

I did the database migrations.

2

There are 2 best solutions below

10
Abdul Aziz Barkat On

You set parent_link=True in your one to one field. According to the documentation for it:

When True and used in a model which inherits from another concrete model, indicates that this field should be used as the link back to the parent class, rather than the extra OneToOneField which would normally be implicitly created by subclassing.

You obviously don't use this while subclassing another model (This is called multi-table inheritance) hence that doesn't make sense. Change your implementation to:

class Pipeline(models.Model):
    config= models.OneToOneField('Config', on_delete=models.SET_NULL, null=True)


class Config(models.Model):
    args = models.CharField(max_length=256, null=True, default='-p -q -x -u -l -m -r')        
    pipeline = models.OneToOneField('Pipeline', on_delete=models.CASCADE, null=True)

Furthermore it still doesn't make sense as this way you basically have a foreign in both the tables which I believe is not what you want, keep the relation in only one model (whichever table the foreign key would be better suited to be in according to you):

class Pipeline(models.Model):
    pass


class Config(models.Model):
    args = models.CharField(max_length=256, null=True, default='-p -q -x -u -l -m -r')        
    pipeline = models.OneToOneField('Pipeline', on_delete=models.CASCADE, null=True)

# from config to get pipeline:
# related_pipeline = config.pipeline
# from pipeline to get config (Django will automatically add this related accessor):
# config = pipeline.config
0
Soerendip On

According to the conversation with Abdul the OneToOne field should only be used together with model inheritance. The following works, but it is not officially supported. I find the documentation somewhat ambiguous in that regard. So, consider this a hack:

class Pipeline(models.Model):
    pipeline = models.OneToOneField(
         'Pipeline', on_delete=models.CASCADE, null=True )

class Config(models.Model):
    args = models.CharField(
        max_length=256, null=True, default='-p -q -x -u -l -m -r' )        
    pipeline = models.OneToOneField(
        'Pipeline', on_delete=models.CASCADE, null=True, parent_link=True )

So, using the parent link was missing. Otherwise, in the admin pannel, both models cannot be created together.

According to this: "Specifying the parent link field As mentioned, Django will automatically create a OneToOneField linking your child class back to any non-abstract parent models. If you want to control the name of the attribute linking back to the parent, you can create your own OneToOneField and set parent_link=True to indicate that your field is the link back to the parent class." from

https://docs.djangoproject.com/en/dev/topics/db/models/#specifying-the-parent-link-field

Django Admin: OneToOne Relation as an Inline?