Pulp Platform Application Layout¶
The Pulp Platform is built using two key frameworks, the Django Web Framework and the Django REST Framework. Where possible, conforming to the conventions of these frameworks is encouraged. The Pulp Platform strives to leverage these frameworks as much as possible, ideally making Pulp Platform development a work of implementation before innovation.
In the event that one of these components offers functionality that augments or supersedes functionality in another component, the order of precedence of these frameworks is:
- Pulp Platform
- Django REST Framework (DRF)
- Django Web Framework (Django)
So, features provided by the Pulp Platform should preferred over similar features provided by DRF, and features in DRF should be preferred over similar features provided by Django.
Module Layout¶
This is the basic layout of the pulpcore.app
package, on the filesystem:
pulpcore
├── app
│ ├── apps.py
│ ├── fields.py
│ ├── __init__.py
│ ├── logs.py
│ ├── management
│ │ ├── commands
│ │ │ ├── __init__.py
│ │ │ └── ...
│ │ └── __init__.py
│ ├── manage.py
│ ├── migrations
│ ├── models
│ │ ├── __init__.py
│ │ └── ...
│ ├── pagination.py
│ ├── response.py
│ ├── serializers
│ │ ├── __init__.py
│ │ └── ...
│ ├── settings.py
│ ├── tasks
│ │ ├── __init__.py
│ │ └── ...
│ ├── templates
│ │ └── ...
│ ├── tests
│ │ └── ...
│ ├── urls.py
│ ├── viewsets
│ │ ├── __init__.py
│ │ └── ...
│ └── wsgi.py
└── __init__.py
The contents of this package are documented in detail in the ../platform-api/index
documentation. Details how this package is organized can be found
below, along with information about some of the modules found in this namespace.
Tip
This tree is incomplete, and maybe be out of date. Only the most notable and
durable modules have been listed; the most complete listing of modules in this
namespace will always be the ../platform-api/index
documentation.
Module Imports¶
For modules in the pulpcore.app
namespace that are large and capture behaviors
across multiple concerns of pulp, such as our models, we have separated these
packages into subpackages. All public identifiers and objects defined
in submodules are then collected into that module's __init__.py
, from which
they will be imported by other Pulp Platform modules.
Using pulpcore.app.models
as an example, this means that when breaking up the
models
package in pulpcore.app
, the following things are true:
-
No models are defined in the
__init__.py
ofpulpcore.app.models
. -
All models are defined in submodules located in the
pulpcore.app.models
module directory (where its__init__.py
can be found). -
The
__init__.py
inpulpcore.app.models
should consist only of import statements, ordered to prevent any circular import issues that may result based on the imports that are done in any included submodules. -
Any models defined in submodules in
pulpcore.app.models
namespace must be imported from thepulpcore.app.models
namespace, not the submodule in which they are defined. Yes:from pulpcore.app.models import PulpModel
, No:from pulpcore.app.models.pulp import PulpModel
. -
When adding new models, they must be imported into the
pulpcore.app.models
__init__.py
, so that they are available to be imported by any other Pulp Platform components that use them from thepulpcore.app.models
namespace. -
Imports done inside any submodules should be relative, e.g.
from .submodule import identifier
orfrom . import submodule
, avoiding the creation of circular imports. -
Imports done inside the module's
__init__.py
should be relative and explict, e.g. -
Yes:
from .submodule import identifier1, identifier2
- No:
from submodule import identifier1, identifier2
- No:
from .submodule import *
Any module in pulpcore.app
broken up in this way, such as
pulpcore.app.serializers
or pulpcore.app.viewsets
, should do so in such a way
that renders the implementation invisible to anyone importing from that module.
pulpcore.app¶
pulpcore.app is the package containing the core Pulp Platform Django application. This package contains all of the Pulp Platform models, serializers, and viewsets required to assemble Pulp's REST API and underlying database.
pulpcore.app.apps¶
This module defines the pulpcore.app.apps.PulpPluginAppConfig
base class
used by all Pulp plugins to identify themselves to the Pulp Platform as plugins.
This module also includes the pulpcore.app.apps.PulpAppConfig
class which
is the Pulp Platform application config.
pulpcore.app.settings¶
This is the main settings module for the platform Django project, which puts together all of the various Django applications that the Pulp Platform depends on to function, as well as the Pulp Platform application itself and its plugins.
Many things are defined in here, including the database settings, logging configuration,
REST API settings, etc. This file also finds and registers Pulp plugins with the Pulp
Platform Django Project, using the pulpcore.plugin
entry point.
In order to use django-related tools with the Pulp Platform, the platform must be installed,
and the DJANGO_SETTINGS_MODULE
environment var must be set to
pulpcore.app.settings
.
pulpcore.app.urls¶
This module contains the API pulpcore.app.urls.root_router
, and is where all non-API
views (should we ever write any) are mapped to URLs.
pulpcore.app.models¶
All models are contained in pulpcore.app.models
.
The Platform models are all importable directly from the pulpcore.app.models
namespace. All Pulp models should subclass pulpcore.app.models.Model
, or
one of its subclasses.
Note
All models must exist in the pulpcore.app.models namespace in order to be recognized by Django and included in the Django ORM.
Master/Detail Models¶
A few Pulp Platform models, including the Content model as well as
Remotes and Publishers, implement a strategy we refer to as "Master/Detail".
The Master/Detail strategy, as implemented in Pulp, allows us to define
necessary relationships on a single master Model, while still allowing
plugin developers to extend these Master classes with details pertinent
to the plugin's requirements. Using the pulpcore.app.models.Content
model as an example, pulpcore.app.models.Repository
relates to the
Content model. This causes all content to relate to the repositories that
contain them the same way while still allowing plugin writers to add any
additional fields or behaviors to the model as-needed for their use cases.
In the Pulp Platform, models requiring this sort of behavior should subclass
pulpcore.app.models.MasterModel
.
Serializers, ViewSets, and other Model-Related Classes¶
The modules containing Serializers and ViewSets, located in pulpcore.app.serializers
and
pulpcore.app.viewsets
, respectively, should be organized similarly to the models that
they represent where possible. For example, if pulpcore.app.models.Repository
is defined
in the pulpcore.app.models.repository
module, its corresponding serializer should be
defined in pulpcore.app.serializers.repository
, and its corresponding viewset should be
defined in pulpcore.app.viewsets.repository
, making it easy to find.
These, and other model-related classes, should be named in such a way as to make their
relationship to their Model unambiguous. To that end, model-related classes should include
the name of the model class they're related to in their name. So, the serializer for the
pulpcore.app.models.Repository
model should be named RepositorySerializer
, and the viewset
related to that model should be named RepositoryViewSet
.
Classes not directly related to a model, or related to multiple models, should still of course be named in such a way as to make their purpose obvious an unambiguous.
ViewSet Registration¶
In order for ViewSets to be automatically registered with the Pulp Platform API router,
they must subclass pulpcore.app.viewsets.base.NamedModelViewSet
and be imported into the
pulpcore.app.viewsets
namespace.
ViewSets not meeting this criteria must be manually registered with the API router in
pulpcore.app.urls
by using the router's register
method during application setup.