refactor models into files
This commit is contained in:
parent
c3d20fda7b
commit
f5f4ec8ac9
8 changed files with 716 additions and 687 deletions
169
hub/services/models/services.py
Normal file
169
hub/services/models/services.py
Normal file
|
@ -0,0 +1,169 @@
|
|||
from django.db import models
|
||||
from django.core.exceptions import ValidationError
|
||||
from django.core.validators import URLValidator
|
||||
from django.urls import reverse
|
||||
from django.utils.text import slugify
|
||||
from django_prose_editor.fields import ProseEditorField
|
||||
|
||||
from .base import Category, ReusableText, validate_image_size
|
||||
from .providers import CloudProvider
|
||||
|
||||
|
||||
class Service(models.Model):
|
||||
name = models.CharField(max_length=200)
|
||||
slug = models.SlugField(max_length=250, unique=True)
|
||||
description = ProseEditorField()
|
||||
tagline = models.TextField(max_length=500, blank=True, null=True)
|
||||
logo = models.ImageField(
|
||||
upload_to="service_logos/",
|
||||
validators=[validate_image_size],
|
||||
null=True,
|
||||
blank=True,
|
||||
)
|
||||
categories = models.ManyToManyField(Category, related_name="services")
|
||||
features = ProseEditorField()
|
||||
is_featured = models.BooleanField(default=False)
|
||||
is_coming_soon = models.BooleanField(default=False)
|
||||
disable_listing = models.BooleanField(default=False)
|
||||
|
||||
created_at = models.DateTimeField(auto_now_add=True)
|
||||
updated_at = models.DateTimeField(auto_now=True)
|
||||
|
||||
def __str__(self):
|
||||
return self.name
|
||||
|
||||
def clean(self):
|
||||
if self.is_featured and self.is_coming_soon:
|
||||
raise ValidationError(
|
||||
"A service cannot be both featured and coming soon simultaneously."
|
||||
)
|
||||
super().clean()
|
||||
|
||||
def save(self, *args, **kwargs):
|
||||
self.clean() # Ensure validation runs on save
|
||||
if not self.slug:
|
||||
self.slug = slugify(self.name)
|
||||
counter = 1
|
||||
while Service.objects.filter(slug=self.slug).exists():
|
||||
self.slug = f"{slugify(self.name)}-{counter}"
|
||||
counter += 1
|
||||
super().save(*args, **kwargs)
|
||||
|
||||
def get_absolute_url(self):
|
||||
return reverse("services:service_detail", kwargs={"slug": self.slug})
|
||||
|
||||
|
||||
class ServiceOffering(models.Model):
|
||||
service = models.ForeignKey(
|
||||
Service, on_delete=models.CASCADE, related_name="offerings"
|
||||
)
|
||||
cloud_provider = models.ForeignKey(
|
||||
CloudProvider, on_delete=models.CASCADE, related_name="offerings"
|
||||
)
|
||||
description = ProseEditorField(blank=True, null=True)
|
||||
offer_description = models.ForeignKey(
|
||||
ReusableText,
|
||||
on_delete=models.PROTECT,
|
||||
related_name="offer_descriptions",
|
||||
blank=True,
|
||||
null=True,
|
||||
)
|
||||
|
||||
disable_listing = models.BooleanField(default=False)
|
||||
|
||||
created_at = models.DateTimeField(auto_now_add=True)
|
||||
updated_at = models.DateTimeField(auto_now=True)
|
||||
|
||||
class Meta:
|
||||
unique_together = ["service", "cloud_provider"]
|
||||
ordering = ["service__name", "cloud_provider__name"]
|
||||
|
||||
def __str__(self):
|
||||
return f"{self.service.name} on {self.cloud_provider.name}"
|
||||
|
||||
def get_absolute_url(self):
|
||||
return reverse(
|
||||
"services:offering_detail",
|
||||
kwargs={
|
||||
"provider_slug": self.cloud_provider.slug,
|
||||
"service_slug": self.service.slug,
|
||||
},
|
||||
)
|
||||
|
||||
|
||||
class Plan(models.Model):
|
||||
name = models.CharField(max_length=100)
|
||||
description = ProseEditorField(blank=True, null=True)
|
||||
pricing = ProseEditorField(blank=True, null=True)
|
||||
plan_description = models.ForeignKey(
|
||||
ReusableText,
|
||||
on_delete=models.PROTECT,
|
||||
related_name="plan_descriptions",
|
||||
blank=True,
|
||||
null=True,
|
||||
)
|
||||
offering = models.ForeignKey(
|
||||
ServiceOffering, on_delete=models.CASCADE, related_name="plans"
|
||||
)
|
||||
|
||||
created_at = models.DateTimeField(auto_now_add=True)
|
||||
updated_at = models.DateTimeField(auto_now=True)
|
||||
|
||||
class Meta:
|
||||
ordering = ["name"]
|
||||
unique_together = [["offering", "name"]]
|
||||
|
||||
def __str__(self):
|
||||
return f"{self.offering} - {self.name}"
|
||||
|
||||
|
||||
class ExternalLinkOffering(models.Model):
|
||||
offering = models.ForeignKey(
|
||||
ServiceOffering, 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):
|
||||
validate = URLValidator()
|
||||
try:
|
||||
validate(self.url)
|
||||
except ValidationError:
|
||||
raise ValidationError({"url": "Enter a valid URL."})
|
||||
|
||||
|
||||
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):
|
||||
validate = URLValidator()
|
||||
try:
|
||||
validate(self.url)
|
||||
except ValidationError:
|
||||
raise ValidationError({"url": "Enter a valid URL."})
|
Loading…
Add table
Add a link
Reference in a new issue