partner categories
This commit is contained in:
parent
83504f6b7c
commit
c6b50da971
8 changed files with 75 additions and 4 deletions
|
@ -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",
|
||||
{
|
||||
|
|
23
hub/services/migrations/0046_add_partner_category.py
Normal file
23
hub/services/migrations/0046_add_partner_category.py
Normal file
|
@ -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,
|
||||
),
|
||||
),
|
||||
]
|
|
@ -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"
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -65,6 +65,9 @@
|
|||
</div>
|
||||
{% endif %}
|
||||
<p class="card-text">{{ article.related_consulting_partner.name }}</p>
|
||||
<div class="mb-2">
|
||||
<span class="badge bg-primary">{{ article.related_consulting_partner.get_category_display_badge }}</span>
|
||||
</div>
|
||||
<a href="{{ article.related_consulting_partner.get_absolute_url }}" class="btn btn-primary btn-sm">View Partner</a>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
@ -153,7 +153,7 @@
|
|||
<h2 class="fs-50 fw-semibold lh-1 mb-12">{{ partner.name }}</h2>
|
||||
</header>
|
||||
<div class="fs-19 text-gray-500">
|
||||
<button class="btn btn-tertiary btn-sm mr-12">Servala Consulting Partner</button>
|
||||
<button class="btn btn-tertiary btn-sm mr-12">{{ partner.get_category_display_badge }}</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
|
|
@ -94,6 +94,23 @@
|
|||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Category Filter -->
|
||||
<div class="pt-24 mb-24">
|
||||
<div class="d-flex justify-content-between align-items-center h-33 mb-5px" role="button">
|
||||
<h3 class="sidebar-title mb-0">Category</h3>
|
||||
</div>
|
||||
<div>
|
||||
<select class="form-select" id="category" name="category" @change="submitForm()">
|
||||
<option value="">All Categories</option>
|
||||
{% for category_value, category_label in partner_categories %}
|
||||
<option value="{{ category_value }}" {% if request.GET.category == category_value %}selected{% endif %}>
|
||||
{{ category_label }}
|
||||
</option>
|
||||
{% endfor %}
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Filter Actions -->
|
||||
<div class="d-flex gap-2">
|
||||
<a href="{% url 'services:partner_list' %}" class="btn btn-outline-secondary btn-sm">Clear</a>
|
||||
|
@ -126,6 +143,9 @@
|
|||
<h3 class="card__title">
|
||||
<a href="{{ partner.get_absolute_url }}" class="text-decoration-none clickable-link">{{ partner.name }}</a>
|
||||
</h3>
|
||||
<div class="mb-2">
|
||||
<span class="badge bg-primary">{{ partner.get_category_display_badge }}</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="card__desc flex-grow-1 rich-text-content">
|
||||
|
|
|
@ -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)
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue