ServiceDefinition as part of the through model
This commit is contained in:
parent
267dc56f32
commit
b074a3413a
5 changed files with 185 additions and 82 deletions
|
@ -14,6 +14,7 @@ from servala.core.models import (
|
|||
ServiceCategory,
|
||||
ServiceDefinition,
|
||||
ServiceOffering,
|
||||
ServiceOfferingControlPlane,
|
||||
User,
|
||||
)
|
||||
|
||||
|
@ -176,7 +177,7 @@ class PlanAdmin(admin.ModelAdmin):
|
|||
class ServiceDefinitionAdmin(admin.ModelAdmin):
|
||||
form = ServiceDefinitionAdminForm
|
||||
list_display = ("name", "service")
|
||||
list_filter = ("service", "control_planes")
|
||||
list_filter = ("service",)
|
||||
search_fields = ("name", "description")
|
||||
autocomplete_fields = ("service",)
|
||||
|
||||
|
@ -199,11 +200,27 @@ class ServiceDefinitionAdmin(admin.ModelAdmin):
|
|||
return ["api_definition"]
|
||||
|
||||
|
||||
class ServiceOfferingControlPlaneInline(admin.TabularInline):
|
||||
model = ServiceOfferingControlPlane
|
||||
extra = 1
|
||||
autocomplete_fields = ("control_plane", "service_definition")
|
||||
|
||||
|
||||
@admin.register(ServiceOfferingControlPlane)
|
||||
class ServiceOfferingControlPlaneAdmin(admin.ModelAdmin):
|
||||
list_display = ("service_offering", "control_plane", "service_definition")
|
||||
list_filter = ("service_offering", "control_plane", "service_definition")
|
||||
search_fields = ("service_offering__service__name", "control_plane__name")
|
||||
autocomplete_fields = ("service_offering", "control_plane", "service_definition")
|
||||
|
||||
|
||||
@admin.register(ServiceOffering)
|
||||
class ServiceOfferingAdmin(admin.ModelAdmin):
|
||||
list_display = ("id", "service", "provider")
|
||||
list_filter = ("service", "provider", "control_planes")
|
||||
list_filter = ("service", "provider")
|
||||
search_fields = ("description",)
|
||||
autocomplete_fields = ("service", "provider")
|
||||
filter_horizontal = ("control_planes",)
|
||||
inlines = (PlanInline,)
|
||||
inlines = (
|
||||
ServiceOfferingControlPlaneInline,
|
||||
PlanInline,
|
||||
)
|
||||
|
|
115
src/servala/core/migrations/0007_service_definition.py
Normal file
115
src/servala/core/migrations/0007_service_definition.py
Normal file
|
@ -0,0 +1,115 @@
|
|||
# Generated by Django 5.2b1 on 2025-03-25 11:02
|
||||
|
||||
import django.db.models.deletion
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
("core", "0006_service_slug"),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.RemoveField(
|
||||
model_name="serviceoffering",
|
||||
name="control_plane",
|
||||
),
|
||||
migrations.CreateModel(
|
||||
name="ServiceDefinition",
|
||||
fields=[
|
||||
(
|
||||
"id",
|
||||
models.BigAutoField(
|
||||
auto_created=True,
|
||||
primary_key=True,
|
||||
serialize=False,
|
||||
verbose_name="ID",
|
||||
),
|
||||
),
|
||||
("name", models.CharField(max_length=100, verbose_name="Name")),
|
||||
(
|
||||
"description",
|
||||
models.TextField(blank=True, verbose_name="Description"),
|
||||
),
|
||||
(
|
||||
"api_definition",
|
||||
models.JSONField(
|
||||
blank=True,
|
||||
help_text="Contains group, version, and kind information",
|
||||
null=True,
|
||||
verbose_name="API Definition",
|
||||
),
|
||||
),
|
||||
(
|
||||
"service",
|
||||
models.ForeignKey(
|
||||
on_delete=django.db.models.deletion.CASCADE,
|
||||
related_name="service_definitions",
|
||||
to="core.service",
|
||||
verbose_name="Service",
|
||||
),
|
||||
),
|
||||
],
|
||||
options={
|
||||
"verbose_name": "Service definition",
|
||||
"verbose_name_plural": "Service definitions",
|
||||
},
|
||||
),
|
||||
migrations.CreateModel(
|
||||
name="ServiceOfferingControlPlane",
|
||||
fields=[
|
||||
(
|
||||
"id",
|
||||
models.BigAutoField(
|
||||
auto_created=True,
|
||||
primary_key=True,
|
||||
serialize=False,
|
||||
verbose_name="ID",
|
||||
),
|
||||
),
|
||||
(
|
||||
"control_plane",
|
||||
models.ForeignKey(
|
||||
on_delete=django.db.models.deletion.CASCADE,
|
||||
related_name="offering_connections",
|
||||
to="core.controlplane",
|
||||
verbose_name="Control plane",
|
||||
),
|
||||
),
|
||||
(
|
||||
"service_definition",
|
||||
models.ForeignKey(
|
||||
on_delete=django.db.models.deletion.PROTECT,
|
||||
related_name="offering_control_planes",
|
||||
to="core.servicedefinition",
|
||||
verbose_name="Service definition",
|
||||
),
|
||||
),
|
||||
(
|
||||
"service_offering",
|
||||
models.ForeignKey(
|
||||
on_delete=django.db.models.deletion.CASCADE,
|
||||
related_name="control_plane_connections",
|
||||
to="core.serviceoffering",
|
||||
verbose_name="Service offering",
|
||||
),
|
||||
),
|
||||
],
|
||||
options={
|
||||
"verbose_name": "Service offering control plane connection",
|
||||
"verbose_name_plural": "Service offering control planes connections",
|
||||
"unique_together": {("service_offering", "control_plane")},
|
||||
},
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name="serviceoffering",
|
||||
name="control_planes",
|
||||
field=models.ManyToManyField(
|
||||
related_name="offerings",
|
||||
through="core.ServiceOfferingControlPlane",
|
||||
to="core.controlplane",
|
||||
verbose_name="Control planes",
|
||||
),
|
||||
),
|
||||
]
|
|
@ -1,72 +0,0 @@
|
|||
# Generated by Django 5.2b1 on 2025-03-24 14:41
|
||||
|
||||
import django.db.models.deletion
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
("core", "0006_service_slug"),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.RenameField(
|
||||
model_name="serviceoffering",
|
||||
old_name="control_plane",
|
||||
new_name="control_planes",
|
||||
),
|
||||
migrations.CreateModel(
|
||||
name="ServiceDefinition",
|
||||
fields=[
|
||||
(
|
||||
"id",
|
||||
models.BigAutoField(
|
||||
auto_created=True,
|
||||
primary_key=True,
|
||||
serialize=False,
|
||||
verbose_name="ID",
|
||||
),
|
||||
),
|
||||
("name", models.CharField(max_length=100, verbose_name="Name")),
|
||||
(
|
||||
"description",
|
||||
models.TextField(blank=True, verbose_name="Description"),
|
||||
),
|
||||
(
|
||||
"api_definition",
|
||||
models.JSONField(
|
||||
blank=True,
|
||||
help_text="Contains group, version, and kind information",
|
||||
null=True,
|
||||
verbose_name="API Definition",
|
||||
),
|
||||
),
|
||||
(
|
||||
"service",
|
||||
models.ForeignKey(
|
||||
on_delete=django.db.models.deletion.CASCADE,
|
||||
related_name="service_definitions",
|
||||
to="core.service",
|
||||
verbose_name="Service",
|
||||
),
|
||||
),
|
||||
],
|
||||
options={
|
||||
"verbose_name": "Service definition",
|
||||
"verbose_name_plural": "Service definitions",
|
||||
},
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name="controlplane",
|
||||
name="service_definition",
|
||||
field=models.ForeignKey(
|
||||
default=1,
|
||||
on_delete=django.db.models.deletion.PROTECT,
|
||||
related_name="control_planes",
|
||||
to="core.servicedefinition",
|
||||
verbose_name="Service definition",
|
||||
),
|
||||
preserve_default=False,
|
||||
),
|
||||
]
|
|
@ -13,6 +13,7 @@ from .service import (
|
|||
ServiceCategory,
|
||||
ServiceDefinition,
|
||||
ServiceOffering,
|
||||
ServiceOfferingControlPlane,
|
||||
)
|
||||
from .user import User
|
||||
|
||||
|
@ -29,5 +30,6 @@ __all__ = [
|
|||
"ServiceCategory",
|
||||
"ServiceDefinition",
|
||||
"ServiceOffering",
|
||||
"ServiceOfferingControlPlane",
|
||||
"User",
|
||||
]
|
||||
|
|
|
@ -103,12 +103,6 @@ class ControlPlane(models.Model):
|
|||
related_name="control_planes",
|
||||
verbose_name=_("Cloud provider"),
|
||||
)
|
||||
service_definition = models.ForeignKey(
|
||||
to="ServiceDefinition",
|
||||
related_name="control_planes",
|
||||
verbose_name=_("Service definition"),
|
||||
on_delete=models.PROTECT,
|
||||
)
|
||||
|
||||
class Meta:
|
||||
verbose_name = _("Control plane")
|
||||
|
@ -263,6 +257,18 @@ class ServiceDefinition(models.Model):
|
|||
verbose_name=_("Service"),
|
||||
)
|
||||
|
||||
@property
|
||||
def control_planes(self):
|
||||
return ControlPlane.objects.filter(
|
||||
offering_connections__service_definition=self
|
||||
).distinct()
|
||||
|
||||
@property
|
||||
def service_offerings(self):
|
||||
return ServiceOffering.objects.filter(
|
||||
control_plane_connections__service_definition=self
|
||||
).distinct()
|
||||
|
||||
class Meta:
|
||||
verbose_name = _("Service definition")
|
||||
verbose_name_plural = _("Service definitions")
|
||||
|
@ -271,6 +277,40 @@ class ServiceDefinition(models.Model):
|
|||
return self.name
|
||||
|
||||
|
||||
class ServiceOfferingControlPlane(models.Model):
|
||||
"""
|
||||
Each combination of ServiceOffering and ControlPlane can have a different
|
||||
ServiceDefinition, which is here modeled as the "through" model.
|
||||
"""
|
||||
|
||||
service_offering = models.ForeignKey(
|
||||
to="ServiceOffering",
|
||||
on_delete=models.CASCADE,
|
||||
related_name="control_plane_connections",
|
||||
verbose_name=_("Service offering"),
|
||||
)
|
||||
control_plane = models.ForeignKey(
|
||||
to="ControlPlane",
|
||||
on_delete=models.CASCADE,
|
||||
related_name="offering_connections",
|
||||
verbose_name=_("Control plane"),
|
||||
)
|
||||
service_definition = models.ForeignKey(
|
||||
to="ServiceDefinition",
|
||||
on_delete=models.PROTECT,
|
||||
related_name="offering_control_planes",
|
||||
verbose_name=_("Service definition"),
|
||||
)
|
||||
|
||||
class Meta:
|
||||
verbose_name = _("Service offering control plane connection")
|
||||
verbose_name_plural = _("Service offering control planes connections")
|
||||
unique_together = [("service_offering", "control_plane")]
|
||||
|
||||
def __str__(self):
|
||||
return f"{self.service_offering} on {self.control_plane} with {self.service_definition}"
|
||||
|
||||
|
||||
class ServiceOffering(models.Model):
|
||||
"""
|
||||
A service offering, e.g. "PostgreSQL on AWS", "MinIO on GCP".
|
||||
|
@ -290,6 +330,7 @@ class ServiceOffering(models.Model):
|
|||
)
|
||||
control_planes = models.ManyToManyField(
|
||||
to="ControlPlane",
|
||||
through="ServiceOfferingControlPlane",
|
||||
related_name="offerings",
|
||||
verbose_name=_("Control planes"),
|
||||
)
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue