Models¶
For the most part, models provided by plugin writers are just regular Django Models.
Note
One slight variation is that the validation is primarily handled in the Django Rest Framework
Serializer. .clean()
is not called.
Most plugins will implement: - model(s) for the specific content type(s) used in the plugin, should be subclassed from Content model - model(s) for the plugin specific remote(s), should be subclassed from Remote model
Adding Model Fields¶
Each subclassed Model will typically store attributes that are specific to the content type. These
attributes need to be added to the model as fields
. You can use any of Django's field types
for your fields. See the Django field documentation, for more in-depth information on
using these fields.
Note
It is required to declare the default_related_name
.
The TYPE class attribute is used for filtering purposes.
class FileContent(Content):
"""
The "file" content type.
Fields:
digest (str): The SHA256 HEX digest.
"""
TYPE = 'file'
digest = models.TextField(null=False)
class Meta:
default_related_name = "%(app_label)s_%(model_name)s"
Here we create a new field digest
using Django's TextField
. After adding/modifying a model, you
can make and run database migrations with:
pulpcore-manager makemigrations $PLUGIN_APP_LABEL
pulpcore-manager migrate
Warning
Do not use settings directly in the model fields, it will lead to a data migration that is specific to the users installation in case those settings change.
If you recognize this syntax, it is because pulpcore-manager is manage.py
configured with
DJANGO_SETTINGS_MODULE="pulpcore.app.settings"
. You can use it anywhere you normally would use
manage.py
or django-admin
.
Uniqueness¶
Model uniqueness (which will also be used as the natural key) is defined by an inner class
Meta
. Pulp Core enforces uniqueness constraints at the database level.
Adding to the simplified FileContent
above:
class FileContent(Content):
"""
The "file" content type.
Content of this type represents a single file uniquely
identified by path and SHA256 digest.
Fields:
digest (str): The SHA256 HEX digest.
"""
TYPE = 'file'
digest = models.TextField(null=False)
class Meta:
# Note the comma, this must be a tuple.
unique_together = ('digest',)
default_related_name = "%(app_label)s_%(model_name)s"
In this example the Content's uniqueness enforced on a single field digest
. For a multi-field
uniqueness, simply add other fields.
class FileContent(Content):
"""
The "file" content type.
Content of this type represents a single file uniquely
identified by path and SHA256 digest.
Fields:
relative_path (str): The file relative path.
digest (str): The SHA256 HEX digest.
"""
TYPE = 'file'
relative_path = models.TextField(null=False)
digest = models.TextField(null=False)
class Meta:
default_related_name = "%(app_label)s_%(model_name)s"
unique_together = (
'relative_path',
'digest',
)
The example above ensures that content is unique on relative_path
and digest
together.
ForeignKey Gotchas¶
The orphan cleanup operation performs mass-deletion of Content units that are not associated with
any repository. Any ForeignKey relationships that refer to Content with a deletion relationship of
PROTECT
will cause Orphan cleanup errors like:
django.db.models.deletion.ProtectedError: ("Cannot delete some instances of model 'MyContent'
because they are referenced through a protected foreign key: 'MyOtherContent.mycontent'"