diff --git a/hub/services/admin.py b/hub/services/admin.py
index 8afe9d1..65a18c4 100644
--- a/hub/services/admin.py
+++ b/hub/services/admin.py
@@ -1,6 +1,13 @@
from django.contrib import admin
from django.utils.html import format_html
-from .models import CloudProvider, Country, ServiceLevel, Service, Category
+from .models import (
+ CloudProvider,
+ ConsultingPartner,
+ Country,
+ ServiceLevel,
+ Service,
+ Category,
+)
@admin.register(Category)
@@ -42,17 +49,23 @@ class ServiceLevelAdmin(admin.ModelAdmin):
class ServiceAdmin(admin.ModelAdmin):
list_display = (
"name",
- "slug",
"cloud_provider",
"service_level",
"price",
"logo_preview",
"category_list",
+ "partner_list",
)
- list_filter = ("cloud_provider", "service_level", "countries", "categories")
+ list_filter = (
+ "cloud_provider",
+ "service_level",
+ "countries",
+ "categories",
+ "consulting_partners",
+ )
+ filter_horizontal = ("countries", "categories", "consulting_partners")
search_fields = ("name", "description", "slug")
prepopulated_fields = {"slug": ("name",)}
- filter_horizontal = ("countries", "categories")
def logo_preview(self, obj):
if obj.logo:
@@ -64,4 +77,22 @@ class ServiceAdmin(admin.ModelAdmin):
def category_list(self, obj):
return ", ".join([cat.name for cat in obj.categories.all()])
+ def partner_list(self, obj):
+ return ", ".join([partner.name for partner in obj.consulting_partners.all()])
+
+ partner_list.short_description = "Consulting Partners"
category_list.short_description = "Categories"
+
+
+@admin.register(ConsultingPartner)
+class ConsultingPartnerAdmin(admin.ModelAdmin):
+ list_display = ("name", "website", "logo_preview")
+ search_fields = ("name", "description")
+ prepopulated_fields = {"slug": ("name",)}
+
+ def logo_preview(self, obj):
+ if obj.logo:
+ return format_html(
+ '', obj.logo.url
+ )
+ return "No logo"
diff --git a/hub/services/migrations/0007_consultingpartner_service_consulting_partners.py b/hub/services/migrations/0007_consultingpartner_service_consulting_partners.py
new file mode 100644
index 0000000..6387c47
--- /dev/null
+++ b/hub/services/migrations/0007_consultingpartner_service_consulting_partners.py
@@ -0,0 +1,50 @@
+# Generated by Django 5.1.5 on 2025-01-28 07:49
+
+import services.models
+from django.db import migrations, models
+
+
+class Migration(migrations.Migration):
+
+ dependencies = [
+ ("services", "0006_service_slug"),
+ ]
+
+ operations = [
+ migrations.CreateModel(
+ name="ConsultingPartner",
+ fields=[
+ (
+ "id",
+ models.BigAutoField(
+ auto_created=True,
+ primary_key=True,
+ serialize=False,
+ verbose_name="ID",
+ ),
+ ),
+ ("name", models.CharField(max_length=200)),
+ ("slug", models.SlugField(unique=True)),
+ ("description", models.TextField(blank=True)),
+ (
+ "logo",
+ models.ImageField(
+ blank=True,
+ null=True,
+ upload_to="partner_logos/",
+ validators=[services.models.validate_image_size],
+ ),
+ ),
+ ("website", models.URLField(blank=True)),
+ ("created_at", models.DateTimeField(auto_now_add=True)),
+ ("updated_at", models.DateTimeField(auto_now=True)),
+ ],
+ ),
+ migrations.AddField(
+ model_name="service",
+ name="consulting_partners",
+ field=models.ManyToManyField(
+ blank=True, related_name="services", to="services.consultingpartner"
+ ),
+ ),
+ ]
diff --git a/hub/services/models.py b/hub/services/models.py
index f6576b3..75b1260 100644
--- a/hub/services/models.py
+++ b/hub/services/models.py
@@ -68,6 +68,32 @@ class CloudProvider(models.Model):
return reverse("services:provider_detail", kwargs={"slug": self.slug})
+class ConsultingPartner(models.Model):
+ name = models.CharField(max_length=200)
+ slug = models.SlugField(unique=True)
+ description = ProseEditorField(blank=True)
+ logo = models.ImageField(
+ upload_to="partner_logos/",
+ validators=[validate_image_size],
+ null=True,
+ blank=True,
+ )
+ website = models.URLField(blank=True)
+ created_at = models.DateTimeField(auto_now_add=True)
+ updated_at = models.DateTimeField(auto_now=True)
+
+ def __str__(self):
+ return self.name
+
+ def save(self, *args, **kwargs):
+ if not self.slug:
+ self.slug = slugify(self.name)
+ super().save(*args, **kwargs)
+
+ def get_absolute_url(self):
+ return reverse("services:partner_detail", kwargs={"slug": self.slug})
+
+
class Country(models.Model):
name = models.CharField(max_length=100)
code = models.CharField(max_length=2)
@@ -93,6 +119,9 @@ class Service(models.Model):
slug = models.SlugField(max_length=250, unique=True)
description = ProseEditorField()
cloud_provider = models.ForeignKey(CloudProvider, on_delete=models.CASCADE)
+ consulting_partners = models.ManyToManyField(
+ ConsultingPartner, related_name="services", blank=True
+ )
service_level = models.ForeignKey(ServiceLevel, on_delete=models.CASCADE)
categories = models.ManyToManyField(Category, related_name="services")
countries = models.ManyToManyField(Country)
diff --git a/hub/services/templates/services/partner_detail.html b/hub/services/templates/services/partner_detail.html
new file mode 100644
index 0000000..0e01ff7
--- /dev/null
+++ b/hub/services/templates/services/partner_detail.html
@@ -0,0 +1,77 @@
+{% extends 'services/base.html' %}
+
+{% block content %}
+
+
+ Service Level: {{ service.service_level.name }}
+ Price: ${{ service.price }}
+
+