add external links
This commit is contained in:
parent
7b21d9d612
commit
8ed39690f1
5 changed files with 98 additions and 1 deletions
|
@ -8,6 +8,7 @@ from .models import (
|
||||||
Currency,
|
Currency,
|
||||||
Plan,
|
Plan,
|
||||||
PlanPrice,
|
PlanPrice,
|
||||||
|
ExternalLink,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
@ -33,6 +34,13 @@ class PlanInline(admin.StackedInline):
|
||||||
return formset
|
return formset
|
||||||
|
|
||||||
|
|
||||||
|
class ExternalLinkInline(admin.TabularInline):
|
||||||
|
model = ExternalLink
|
||||||
|
extra = 1
|
||||||
|
fields = ("description", "url", "order")
|
||||||
|
ordering = ("order", "description")
|
||||||
|
|
||||||
|
|
||||||
@admin.register(Category)
|
@admin.register(Category)
|
||||||
class CategoryAdmin(admin.ModelAdmin):
|
class CategoryAdmin(admin.ModelAdmin):
|
||||||
list_display = ("name", "slug", "parent", "order")
|
list_display = ("name", "slug", "parent", "order")
|
||||||
|
@ -73,7 +81,7 @@ class ServiceAdmin(admin.ModelAdmin):
|
||||||
filter_horizontal = ("categories", "consulting_partners")
|
filter_horizontal = ("categories", "consulting_partners")
|
||||||
search_fields = ("name", "description", "slug")
|
search_fields = ("name", "description", "slug")
|
||||||
prepopulated_fields = {"slug": ("name",)}
|
prepopulated_fields = {"slug": ("name",)}
|
||||||
inlines = [PlanInline]
|
inlines = [PlanInline, ExternalLinkInline]
|
||||||
|
|
||||||
def logo_preview(self, obj):
|
def logo_preview(self, obj):
|
||||||
if obj.logo:
|
if obj.logo:
|
||||||
|
|
46
hub/services/migrations/0012_externallink.py
Normal file
46
hub/services/migrations/0012_externallink.py
Normal file
|
@ -0,0 +1,46 @@
|
||||||
|
# Generated by Django 5.1.5 on 2025-01-28 09:58
|
||||||
|
|
||||||
|
import django.db.models.deletion
|
||||||
|
from django.db import migrations, models
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
("services", "0011_lead_plan"),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.CreateModel(
|
||||||
|
name="ExternalLink",
|
||||||
|
fields=[
|
||||||
|
(
|
||||||
|
"id",
|
||||||
|
models.BigAutoField(
|
||||||
|
auto_created=True,
|
||||||
|
primary_key=True,
|
||||||
|
serialize=False,
|
||||||
|
verbose_name="ID",
|
||||||
|
),
|
||||||
|
),
|
||||||
|
("url", models.URLField()),
|
||||||
|
("description", models.CharField(max_length=200)),
|
||||||
|
("order", models.IntegerField(default=0)),
|
||||||
|
("created_at", models.DateTimeField(auto_now_add=True)),
|
||||||
|
("updated_at", models.DateTimeField(auto_now=True)),
|
||||||
|
(
|
||||||
|
"service",
|
||||||
|
models.ForeignKey(
|
||||||
|
on_delete=django.db.models.deletion.CASCADE,
|
||||||
|
related_name="external_links",
|
||||||
|
to="services.service",
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
options={
|
||||||
|
"verbose_name": "External Link",
|
||||||
|
"verbose_name_plural": "External Links",
|
||||||
|
"ordering": ["order", "description"],
|
||||||
|
},
|
||||||
|
),
|
||||||
|
]
|
|
@ -205,3 +205,33 @@ class Lead(models.Model):
|
||||||
|
|
||||||
def __str__(self):
|
def __str__(self):
|
||||||
return f"{self.name} - {self.company} ({self.service})"
|
return f"{self.name} - {self.company} ({self.service})"
|
||||||
|
|
||||||
|
|
||||||
|
class ExternalLink(models.Model):
|
||||||
|
service = models.ForeignKey(
|
||||||
|
Service, on_delete=models.CASCADE, related_name="external_links"
|
||||||
|
)
|
||||||
|
url = models.URLField()
|
||||||
|
description = models.CharField(max_length=200)
|
||||||
|
order = models.IntegerField(default=0)
|
||||||
|
created_at = models.DateTimeField(auto_now_add=True)
|
||||||
|
updated_at = models.DateTimeField(auto_now=True)
|
||||||
|
|
||||||
|
class Meta:
|
||||||
|
ordering = ["order", "description"]
|
||||||
|
verbose_name = "External Link"
|
||||||
|
verbose_name_plural = "External Links"
|
||||||
|
|
||||||
|
def __str__(self):
|
||||||
|
return f"{self.description} ({self.url})"
|
||||||
|
|
||||||
|
def clean(self):
|
||||||
|
from django.core.validators import URLValidator
|
||||||
|
from django.core.exceptions import ValidationError
|
||||||
|
|
||||||
|
# Validate URL
|
||||||
|
validate = URLValidator()
|
||||||
|
try:
|
||||||
|
validate(self.url)
|
||||||
|
except ValidationError:
|
||||||
|
raise ValidationError({"url": "Enter a valid URL."})
|
||||||
|
|
|
@ -5,6 +5,7 @@
|
||||||
<meta charset="UTF-8">
|
<meta charset="UTF-8">
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||||
<title>Servala - The Cloud Native Services Hub</title>
|
<title>Servala - The Cloud Native Services Hub</title>
|
||||||
|
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap-icons@1.7.2/font/bootstrap-icons.css">
|
||||||
<link rel="stylesheet" type="text/css" href='{% static "css/bootstrap.min.css" %}'>
|
<link rel="stylesheet" type="text/css" href='{% static "css/bootstrap.min.css" %}'>
|
||||||
<style>
|
<style>
|
||||||
.rich-text-content {
|
.rich-text-content {
|
||||||
|
|
|
@ -32,6 +32,18 @@
|
||||||
|
|
||||||
<h5>Features</h5>
|
<h5>Features</h5>
|
||||||
<p>{{ service.features|safe }}</p>
|
<p>{{ service.features|safe }}</p>
|
||||||
|
|
||||||
|
{% if service.external_links.exists %}
|
||||||
|
<h5>External Resources</h5>
|
||||||
|
{% for link in service.external_links.all %}
|
||||||
|
<a href="{{ link.url }}" target="_blank" rel="noopener noreferrer"
|
||||||
|
class="list-group-item list-group-item-action d-flex justify-content-between align-items-center">
|
||||||
|
{{ link.description }}
|
||||||
|
<i class="bi bi-box-arrow-up-right"></i>
|
||||||
|
</a>
|
||||||
|
{% endfor %}
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue