diff --git a/hub/services/admin/providers.py b/hub/services/admin/providers.py index d4aa5c2..51f6d59 100644 --- a/hub/services/admin/providers.py +++ b/hub/services/admin/providers.py @@ -107,6 +107,7 @@ class ConsultingPartnerAdmin(SortableAdminMixin, admin.ModelAdmin): list_display = ( "name", + "category", "website", "logo_preview", "disable_listing", @@ -114,12 +115,13 @@ class ConsultingPartnerAdmin(SortableAdminMixin, admin.ModelAdmin): "order", ) search_fields = ("name", "description") + list_filter = ("category", "is_featured", "disable_listing") prepopulated_fields = {"slug": ("name",)} filter_horizontal = ("services", "cloud_providers") ordering = ("order",) fieldsets = ( - (None, {"fields": ("name", "slug", "description", "order")}), + (None, {"fields": ("name", "slug", "description", "category", "order")}), ( "Images", { diff --git a/hub/services/migrations/0046_add_partner_category.py b/hub/services/migrations/0046_add_partner_category.py new file mode 100644 index 0000000..109943e --- /dev/null +++ b/hub/services/migrations/0046_add_partner_category.py @@ -0,0 +1,23 @@ +# Generated by Django 5.2 on 2025-07-11 08:40 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ("services", "0045_add_og_image_to_article"), + ] + + operations = [ + migrations.AddField( + model_name="consultingpartner", + name="category", + field=models.CharField( + choices=[("CONSULTING", "Consulting"), ("TRAINING", "Training")], + default="CONSULTING", + help_text="Category of the consulting partner", + max_length=20, + ), + ), + ] diff --git a/hub/services/models/base.py b/hub/services/models/base.py index 6a4ac7d..cbbcf52 100644 --- a/hub/services/models/base.py +++ b/hub/services/models/base.py @@ -106,6 +106,11 @@ class Unit(models.TextChoices): CPU = "CPU", "vCPU" +class PartnerCategory(models.TextChoices): + CONSULTING = "CONSULTING", "Consulting" + TRAINING = "TRAINING", "Training" + + # This should be a relation, but for now this is good enough :TM: class ManagedServiceProvider(models.TextChoices): VS = "VS", "VSHN" diff --git a/hub/services/models/providers.py b/hub/services/models/providers.py index e7a33b9..3589d66 100644 --- a/hub/services/models/providers.py +++ b/hub/services/models/providers.py @@ -2,7 +2,7 @@ from django.db import models from django.urls import reverse from django.utils.text import slugify -from .base import validate_image_size, get_prose_editor_field +from .base import validate_image_size, get_prose_editor_field, PartnerCategory from .images import ImageReference @@ -51,6 +51,14 @@ class ConsultingPartner(ImageReference): email = models.EmailField(max_length=254, blank=True, null=True) address = models.TextField(max_length=250, blank=True, null=True) + # Partner category (hardcoded choices as requested) + category = models.CharField( + max_length=20, + choices=PartnerCategory.choices, + default=PartnerCategory.CONSULTING, + help_text="Category of the partner", + ) + services = models.ManyToManyField( "services.Service", related_name="consulting_partners", blank=True ) @@ -69,7 +77,11 @@ class ConsultingPartner(ImageReference): ordering = ["order"] def __str__(self): - return self.name + return f"{self.name} ({self.get_category_display()})" + + def get_category_display_badge(self): + """Returns category display suitable for badges/UI""" + return self.get_category_display() def save(self, *args, **kwargs): if not self.slug: diff --git a/hub/services/templates/services/article_detail.html b/hub/services/templates/services/article_detail.html index 3d864e8..c9f3cdb 100644 --- a/hub/services/templates/services/article_detail.html +++ b/hub/services/templates/services/article_detail.html @@ -65,6 +65,9 @@ {% endif %}

{{ article.related_consulting_partner.name }}

+
+ {{ article.related_consulting_partner.get_category_display_badge }} +
View Partner diff --git a/hub/services/templates/services/partner_detail.html b/hub/services/templates/services/partner_detail.html index 477af4a..1f3968e 100644 --- a/hub/services/templates/services/partner_detail.html +++ b/hub/services/templates/services/partner_detail.html @@ -153,7 +153,7 @@

{{ partner.name }}

- +
diff --git a/hub/services/templates/services/partner_list.html b/hub/services/templates/services/partner_list.html index f05ca5b..59765b0 100644 --- a/hub/services/templates/services/partner_list.html +++ b/hub/services/templates/services/partner_list.html @@ -94,6 +94,23 @@ + +
+
+ +
+
+ +
+
+
Clear @@ -126,6 +143,9 @@

{{ partner.name }}

+
+ {{ partner.get_category_display_badge }} +
diff --git a/hub/services/views/partners.py b/hub/services/views/partners.py index ac3668e..4651a14 100644 --- a/hub/services/views/partners.py +++ b/hub/services/views/partners.py @@ -1,6 +1,7 @@ from django.shortcuts import render, get_object_or_404 from django.db.models import Q from hub.services.models import ConsultingPartner, CloudProvider, Service +from hub.services.models.base import PartnerCategory def partner_list(request): @@ -8,6 +9,7 @@ def partner_list(request): search_query = request.GET.get("search", "") service_id = request.GET.get("service", "") cloud_provider_id = request.GET.get("cloud_provider", "") + category = request.GET.get("category", "") # Start with all active partners partners = ConsultingPartner.objects.filter(disable_listing=False).order_by("order") @@ -24,6 +26,9 @@ def partner_list(request): if cloud_provider_id: partners = partners.filter(cloud_providers__id=cloud_provider_id) + if category: + partners = partners.filter(category=category) + # Get available services from filtered partners available_service_ids = partners.values_list("services__id", flat=True).distinct() available_services = Service.objects.filter( @@ -68,6 +73,7 @@ def partner_list(request): ), "available_services": available_services, "available_cloud_providers": available_cloud_providers, + "partner_categories": PartnerCategory.choices, } return render(request, "services/partner_list.html", context)