errrr
This commit is contained in:
3
app/apps/servers/__init__.py
Normal file
3
app/apps/servers/__init__.py
Normal file
@@ -0,0 +1,3 @@
|
||||
# empty
|
||||
|
||||
|
||||
29
app/apps/servers/admin.py
Normal file
29
app/apps/servers/admin.py
Normal file
@@ -0,0 +1,29 @@
|
||||
from django.contrib import admin
|
||||
from django.utils.html import format_html
|
||||
from .models import Server
|
||||
|
||||
|
||||
@admin.register(Server)
|
||||
class ServerAdmin(admin.ModelAdmin):
|
||||
list_display = ("avatar", "display_name", "hostname", "ipv4", "ipv6", "created_at")
|
||||
list_display_links = ("display_name",)
|
||||
search_fields = ("display_name", "hostname", "ipv4", "ipv6")
|
||||
list_filter = ("created_at",)
|
||||
readonly_fields = ("created_at", "updated_at")
|
||||
fields = ("display_name", "hostname", "ipv4", "ipv6", "image", "created_at", "updated_at")
|
||||
|
||||
def avatar(self, obj: Server):
|
||||
if obj.image_url:
|
||||
return format_html(
|
||||
'<img src="{}" alt="{}" style="width:28px;height:28px;border-radius:6px;object-fit:cover;" />',
|
||||
obj.image_url,
|
||||
obj.display_name,
|
||||
)
|
||||
initial = obj.initial
|
||||
return format_html(
|
||||
'<div style="width:28px;height:28px;border-radius:6px;background:#7C3AED;color:white;display:flex;align-items:center;justify-content:center;font-weight:600;">{}</div>',
|
||||
initial,
|
||||
)
|
||||
avatar.short_description = ""
|
||||
|
||||
|
||||
9
app/apps/servers/apps.py
Normal file
9
app/apps/servers/apps.py
Normal file
@@ -0,0 +1,9 @@
|
||||
from django.apps import AppConfig
|
||||
|
||||
|
||||
class ServersConfig(AppConfig):
|
||||
default_auto_field = "django.db.models.BigAutoField"
|
||||
name = "apps.servers"
|
||||
verbose_name = "Servers"
|
||||
|
||||
|
||||
45
app/apps/servers/migrations/0001_initial.py
Normal file
45
app/apps/servers/migrations/0001_initial.py
Normal file
@@ -0,0 +1,45 @@
|
||||
from django.db import migrations, models
|
||||
import django.core.validators
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
initial = True
|
||||
|
||||
dependencies = []
|
||||
|
||||
operations = [
|
||||
migrations.CreateModel(
|
||||
name="Server",
|
||||
fields=[
|
||||
("id", models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name="ID")),
|
||||
("display_name", models.CharField(max_length=128)),
|
||||
(
|
||||
"hostname",
|
||||
models.CharField(
|
||||
blank=True,
|
||||
max_length=253,
|
||||
null=True,
|
||||
unique=True,
|
||||
validators=[
|
||||
django.core.validators.RegexValidator(
|
||||
message="Enter a valid hostname.",
|
||||
regex="^(?=.{1,253}$)(?!-)[A-Za-z0-9-]{1,63}(?<!-)(\\.(?!-)[A-Za-z0-9-]{1,63}(?<!-))*\\.?$",
|
||||
)
|
||||
],
|
||||
),
|
||||
),
|
||||
("ipv4", models.GenericIPAddressField(blank=True, null=True, protocol="IPv4", unique=True)),
|
||||
("ipv6", models.GenericIPAddressField(blank=True, null=True, protocol="IPv6", unique=True)),
|
||||
("image", models.ImageField(blank=True, null=True, upload_to="servers/")),
|
||||
("created_at", models.DateTimeField(auto_now_add=True)),
|
||||
("updated_at", models.DateTimeField(auto_now=True)),
|
||||
],
|
||||
options={
|
||||
"verbose_name": "Server",
|
||||
"verbose_name_plural": "Servers",
|
||||
"ordering": ["display_name", "hostname", "ipv4", "ipv6"],
|
||||
},
|
||||
),
|
||||
]
|
||||
|
||||
|
||||
3
app/apps/servers/migrations/__init__.py
Normal file
3
app/apps/servers/migrations/__init__.py
Normal file
@@ -0,0 +1,3 @@
|
||||
# empty
|
||||
|
||||
|
||||
43
app/apps/servers/models.py
Normal file
43
app/apps/servers/models.py
Normal file
@@ -0,0 +1,43 @@
|
||||
from __future__ import annotations
|
||||
|
||||
from django.core.validators import RegexValidator
|
||||
from django.db import models
|
||||
from django.utils.text import slugify
|
||||
|
||||
|
||||
hostname_validator = RegexValidator(
|
||||
regex=r"^(?=.{1,253}$)(?!-)[A-Za-z0-9-]{1,63}(?<!-)(\.(?!-)[A-Za-z0-9-]{1,63}(?<!-))*\.?$",
|
||||
message="Enter a valid hostname.",
|
||||
)
|
||||
|
||||
|
||||
class Server(models.Model):
|
||||
display_name = models.CharField(max_length=128)
|
||||
hostname = models.CharField(max_length=253, null=True, blank=True, unique=True, validators=[hostname_validator])
|
||||
ipv4 = models.GenericIPAddressField(null=True, blank=True, protocol="IPv4", unique=True)
|
||||
ipv6 = models.GenericIPAddressField(null=True, blank=True, protocol="IPv6", unique=True)
|
||||
image = models.ImageField(upload_to="servers/", null=True, blank=True)
|
||||
created_at = models.DateTimeField(auto_now_add=True)
|
||||
updated_at = models.DateTimeField(auto_now=True)
|
||||
|
||||
class Meta:
|
||||
ordering = ["display_name", "hostname", "ipv4", "ipv6"]
|
||||
verbose_name = "Server"
|
||||
verbose_name_plural = "Servers"
|
||||
|
||||
def __str__(self) -> str:
|
||||
primary = self.hostname or self.ipv4 or self.ipv6 or "unassigned"
|
||||
return f"{self.display_name} ({primary})"
|
||||
|
||||
@property
|
||||
def image_url(self) -> str | None:
|
||||
try:
|
||||
return self.image.url if self.image else None
|
||||
except Exception:
|
||||
return None
|
||||
|
||||
@property
|
||||
def initial(self) -> str:
|
||||
return (self.display_name or "?").strip()[:1].upper() or "?"
|
||||
|
||||
|
||||
Reference in New Issue
Block a user