feat: changes for citation ad dynamic

This commit is contained in:
mohamad
2026-05-17 18:51:26 +03:30
parent f0a9d5832b
commit b8ab67049f
22 changed files with 1170 additions and 287 deletions
+19 -8
View File
@@ -1,6 +1,13 @@
from django.contrib import admin
from .models import Article, ArticleSection, MainProduct, SubProduct, SubProductVersion
from .models import Article, ArticleCitation, ArticleSection, MainProduct, SubProduct, SubProductVersion
class ArticleCitationInline(admin.TabularInline):
model = ArticleCitation
extra = 1
fields = ("text", "url", "order")
ordering = ("order",)
class ArticleSectionInline(admin.TabularInline):
@@ -13,7 +20,7 @@ class ArticleSectionInline(admin.TabularInline):
class ArticleInline(admin.StackedInline):
model = Article
extra = 0
fields = ("title", "description", "order")
fields = ("badge", "title", "description", "order")
ordering = ("order",)
show_change_link = True
@@ -39,7 +46,7 @@ class SubProductVersionInline(admin.TabularInline):
class SubProductInline(admin.StackedInline):
model = SubProduct
extra = 0
fields = ("name", "slug", "distribution", "short_description", "image", "order", "is_active")
fields = ("name", "slug", "distribution", "short_description", "image", "logo", "show_on_homepage", "homepage_order", "order", "is_active")
ordering = ("order",)
show_change_link = True
prepopulated_fields = {"slug": ("name",)}
@@ -67,20 +74,23 @@ class SubProductAdmin(admin.ModelAdmin):
"name",
"main_product",
"distribution",
"show_on_homepage",
"homepage_order",
"order",
"is_active",
"created_at",
)
list_filter = ("is_active", "distribution", "main_product")
list_filter = ("is_active", "distribution", "main_product", "show_on_homepage")
search_fields = ("name", "description", "main_product__name")
prepopulated_fields = {"slug": ("name",)}
list_editable = ("order", "is_active")
list_editable = ("order", "is_active", "show_on_homepage", "homepage_order")
raw_id_fields = ("main_product",)
inlines = [ArticleInline, SubProductVersionInline]
fieldsets = (
(None, {"fields": ("main_product", "name", "slug", "distribution", "short_description")}),
("Description", {"fields": ("description_format", "description")}),
("Media", {"fields": ("image",)}),
("Media", {"fields": ("image", "logo")}),
("Homepage", {"fields": ("show_on_homepage", "homepage_order")}),
("Settings", {"fields": ("order", "is_active")}),
)
@@ -92,10 +102,11 @@ class ArticleAdmin(admin.ModelAdmin):
search_fields = ("title", "description")
list_editable = ("order",)
raw_id_fields = ("sub_product",)
inlines = [ArticleSectionInline]
inlines = [ArticleSectionInline, ArticleCitationInline]
fieldsets = (
(None, {"fields": ("sub_product", "title")}),
(None, {"fields": ("sub_product", "badge", "title")}),
("Description", {"fields": ("description_format", "description")}),
("Citation Badge", {"fields": ("citation_count_display",), "description": "Set a number to show the dashed citation circle badge at the bottom-right of the article card. Leave blank to hide it."}),
("Settings", {"fields": ("order",)}),
)
@@ -0,0 +1,22 @@
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
("products", "0004_distribution_and_versions"),
]
operations = [
migrations.AddField(
model_name="article",
name="badge",
field=models.CharField(
blank=True,
default="",
help_text="Optional label shown above the article title (e.g. 'Overview', 'Note').",
max_length=100,
),
preserve_default=False,
),
]
@@ -0,0 +1,49 @@
# Generated by Django 5.0.2 on 2026-05-17 14:59
import django.db.models.deletion
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('products', '0005_article_badge'),
]
operations = [
migrations.AddField(
model_name='subproduct',
name='homepage_order',
field=models.PositiveIntegerField(default=0, help_text='Order within the homepage Products section.'),
),
migrations.AddField(
model_name='subproduct',
name='logo',
field=models.ImageField(blank=True, help_text='Small logo shown as a corner badge on homepage product cards.', null=True, upload_to='products/sub_logos/'),
),
migrations.AddField(
model_name='subproduct',
name='show_on_homepage',
field=models.BooleanField(default=False, help_text='Display this sub-product in the homepage Products section.'),
),
migrations.AlterField(
model_name='subproductversion',
name='package_resource_url',
field=models.URLField(blank=True, help_text='Shown on the site when set. For Resources it is the main Open link; for Installable it appears under the platform grid.'),
),
migrations.CreateModel(
name='ArticleCitation',
fields=[
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('text', models.TextField(help_text='Full citation text.')),
('url', models.URLField(blank=True, help_text='Optional link to the cited source.')),
('order', models.PositiveIntegerField(default=0)),
('article', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='citations', to='products.article')),
],
options={
'verbose_name': 'Article Citation',
'verbose_name_plural': 'Article Citations',
'ordering': ['order', 'pk'],
},
),
]
@@ -0,0 +1,18 @@
# Generated by Django 5.0.2 on 2026-05-17 15:16
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('products', '0006_subproduct_logo_homepage_citations'),
]
operations = [
migrations.AddField(
model_name='article',
name='citation_count_display',
field=models.PositiveSmallIntegerField(blank=True, help_text='Optional number shown in the dashed citation circle badge at the bottom of the article card. Leave blank to hide the badge.', null=True),
),
]
+32
View File
@@ -69,8 +69,11 @@ class SubProduct(models.Model):
max_length=20, choices=CONTENT_FORMAT_CHOICES, default=FORMAT_PLAIN
)
image = models.ImageField(upload_to="products/sub/", blank=True, null=True)
logo = models.ImageField(upload_to="products/sub_logos/", blank=True, null=True, help_text="Small logo shown as a corner badge on homepage product cards.")
order = models.PositiveIntegerField(default=0)
is_active = models.BooleanField(default=True)
show_on_homepage = models.BooleanField(default=False, help_text="Display this sub-product in the homepage Products section.")
homepage_order = models.PositiveIntegerField(default=0, help_text="Order within the homepage Products section.")
distribution = models.CharField(
max_length=20,
choices=DISTRIBUTION_CHOICES,
@@ -123,11 +126,21 @@ class Article(models.Model):
on_delete=models.CASCADE,
related_name="articles",
)
badge = models.CharField(
max_length=100,
blank=True,
help_text="Optional label shown above the article title (e.g. 'Overview', 'Note').",
)
title = models.CharField(max_length=300)
description = models.TextField()
description_format = models.CharField(
max_length=20, choices=CONTENT_FORMAT_CHOICES, default=FORMAT_PLAIN
)
citation_count_display = models.PositiveSmallIntegerField(
null=True,
blank=True,
help_text="Optional number shown in the dashed citation circle badge at the bottom of the article card. Leave blank to hide the badge.",
)
order = models.PositiveIntegerField(default=0)
created_at = models.DateTimeField(auto_now_add=True)
updated_at = models.DateTimeField(auto_now=True)
@@ -219,3 +232,22 @@ class ArticleSection(models.Model):
def __str__(self):
return f"{self.article.title} {self.title}"
class ArticleCitation(models.Model):
article = models.ForeignKey(
Article,
on_delete=models.CASCADE,
related_name="citations",
)
text = models.TextField(help_text="Full citation text.")
url = models.URLField(blank=True, help_text="Optional link to the cited source.")
order = models.PositiveIntegerField(default=0)
class Meta:
ordering = ["order", "pk"]
verbose_name = "Article Citation"
verbose_name_plural = "Article Citations"
def __str__(self):
return f"{self.article.title} — citation {self.order or self.pk}"