From fa4c8298fddf7bf2ef08fefcb244ab4da312be65 Mon Sep 17 00:00:00 2001 From: Junwei Zhao Date: Fri, 21 Feb 2025 20:57:03 +1100 Subject: [PATCH] add tags to post --- data/db.sqlite3 | Bin 356352 -> 368640 bytes links/forms.py | 7 ++- ...tion_remove_tag_slug_post_tags_and_more.py | 31 +++++++++ links/models.py | 12 +--- links/serializers.py | 6 +- links/templates/links/post_detail.html | 17 +++-- links/templates/links/post_form.html | 59 ++++++++++++++++++ links/templates/links/post_list.html | 16 ++++- links/templates/links/public_post.html | 9 +++ 9 files changed, 137 insertions(+), 20 deletions(-) create mode 100644 links/migrations/0031_remove_tag_description_remove_tag_slug_post_tags_and_more.py diff --git a/data/db.sqlite3 b/data/db.sqlite3 index 344d391af282c53ffeba0a3fcf4613f7af1be9c2..1941eb40df063f1a5f3a58a38d96ee9eeb9821a3 100644 GIT binary patch delta 1705 zcmah}OKcle6rIm|Gakn?6U%Yj&?q&j(k7%aGyc>c5+{=nYD7bUMk?*baqNjRia&|% zl(2xtp-srHm64uWq^d|L8$?wUgf}dZSRfD*V$}t*6P6%VRa&)#f&}kn@>A4+Wow@A zz30Aj-@J3?*PZjP-CuMo*|5 zN#oOgo-AXWmzuut7@AUok7R#U&59iV}G*AUm?p1-KnwrpuRnX7%TR6(;L_d>wAJ0(^2WqT= zZf=kx2z0Rq`ow-nYBX&kuj>=&vl<9m`hgij4{@>7#}c5Xojp5}PG?Zh8t_YljJc(e ziKlb}U0VYoTa@M~yIs??;kbc*Tm$W$90Mqt7FbB*ryz*9~>X zX3a)qPAi@{%9xFo@qgRaysywCVka~D8EtrF9n>piwgxIq$qmw!*lSy=+pJ4ld4aaH z@fl8o%itNvvi(e+>7|#bO)6cUsqc=KgjwG8S|?rVFtSN~?!fKXx|>EamY4{s3BP*! zK>89=t+3(B-UTIBd0%;}``qj9)&rnccYCW@*V<9C6?xYP-o5L&yKgnd{Q{~#G;!LO zJkaUlz*|Gw=nx88p|p?0LDZovwhJ+hK!JDZm`3V9X>3my50CqUKGhqW%^EX1lq}mC zeY-p(I#IR`a-)04vcu?k4gQziDfjMisd;q60+r)$ltyNF*Rf;tf>Df*r*)GA?!LP? zhtw&i0W}IRgd7u09~#Nh61q1%1b=d>B?gP{=-zJ zBzW^p3&X5Xtc6*@?s$tC9}{>g_+pc$ozG?TB9=+YZDfmjUN02!x~L~6v$=FG_3m-^ zWPCEd-vGmrKp^5%JOL#bRzinmLg9)f0XJ>UR;&_6eniR7|kwh)06H`{VDo~WCE9@hv6E1Q5KYuMw6 ztTD*+E}lplTNnBP+tv#_powcS5Ma|1OwLaz`7ilN#kLN9lU?RH zgsgGGMLn3tquPWX#KaimftYyH6G%LHF%Z2d2XRY~m%Nvk_ulutzp1yordFe~dyO~% z;Jl~*Wp=Ldh!%f2@Jt{JExI&pml9SVDlJA%g-{iDTx!p_);wJ7q=5;}S6w|h7Awh=Uc9{MS7*GLG&9lJ|K^`dhf9b3G1D>RZShFup9^tF# z71|F~X*8UN){p0I4A+}C?Xkft_E(h`9kna6>1LDwM L0LuCx`5pQPg6^ug diff --git a/links/forms.py b/links/forms.py index 78d52e8..7c1a640 100644 --- a/links/forms.py +++ b/links/forms.py @@ -65,9 +65,10 @@ class PageForm(forms.ModelForm): class PostForm(forms.ModelForm): class Meta: model = Post - fields = ['title', 'type', 'content'] + fields = ['title', 'type', 'content', 'tags'] widgets = { 'content': forms.Textarea(attrs={'rows': 20}), + 'tags': forms.SelectMultiple(attrs={'class': 'select2'}), } class MultipleFileInput(forms.ClearableFileInput): @@ -110,9 +111,9 @@ class ImageUploadForm(forms.ModelForm): class TagForm(forms.ModelForm): class Meta: model = Tag - fields = ['name', 'description'] + fields = ['name'] widgets = { - 'description': forms.Textarea(attrs={'rows': 3}), + 'name': forms.TextInput(attrs={'class': 'mt-1 block w-full border border-gray-300 rounded-md shadow-sm py-2 px-3 focus:outline-none focus:ring-indigo-500 focus:border-indigo-500 sm:text-sm'}), } class IPTVChannelForm(forms.ModelForm): diff --git a/links/migrations/0031_remove_tag_description_remove_tag_slug_post_tags_and_more.py b/links/migrations/0031_remove_tag_description_remove_tag_slug_post_tags_and_more.py new file mode 100644 index 0000000..7dff827 --- /dev/null +++ b/links/migrations/0031_remove_tag_description_remove_tag_slug_post_tags_and_more.py @@ -0,0 +1,31 @@ +# Generated by Django 5.0.10 on 2025-02-21 07:07 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('links', '0030_rename_newsletter_post_alter_post_options'), + ] + + operations = [ + migrations.RemoveField( + model_name='tag', + name='description', + ), + migrations.RemoveField( + model_name='tag', + name='slug', + ), + migrations.AddField( + model_name='post', + name='tags', + field=models.ManyToManyField(blank=True, related_name='posts', to='links.tag'), + ), + migrations.AlterField( + model_name='tag', + name='name', + field=models.CharField(max_length=50, unique=True, verbose_name='Name'), + ), + ] diff --git a/links/models.py b/links/models.py index 9768967..dfd7d26 100644 --- a/links/models.py +++ b/links/models.py @@ -143,9 +143,7 @@ def generate_random_color(): return random.choice(colors) class Tag(models.Model): - name = models.CharField(_('Name'), max_length=100, unique=True) - slug = models.SlugField(_('Slug'), max_length=100, unique=True) - description = models.TextField(_('Description'), blank=True) + name = models.CharField(_('Name'), max_length=50, unique=True) created_at = models.DateTimeField(_('Created at'), auto_now_add=True) updated_at = models.DateTimeField(_('Updated at'), auto_now=True) @@ -158,12 +156,7 @@ class Tag(models.Model): return self.name def get_absolute_url(self): - return reverse('tag-detail', kwargs={'slug': self.slug}) - - def save(self, *args, **kwargs): - if not self.slug: - self.slug = slugify(self.name) - super().save(*args, **kwargs) + return reverse('tag-detail', kwargs={'pk': self.pk}) class Page(models.Model): class ProcessStatus(models.TextChoices): @@ -260,6 +253,7 @@ class Post(models.Model): content = models.TextField(_('Content')) created_at = models.DateTimeField(_('Created at'), auto_now_add=True) updated_at = models.DateTimeField(_('Updated at'), auto_now=True) + tags = models.ManyToManyField('Tag', blank=True, related_name='posts') class Meta: ordering = ['-created_at'] diff --git a/links/serializers.py b/links/serializers.py index 02bf653..857cd3d 100644 --- a/links/serializers.py +++ b/links/serializers.py @@ -1,5 +1,5 @@ from rest_framework import serializers -from .models import Page, Post, ImageCollection, Image +from .models import Page, Post, ImageCollection, Image, Tag class PageSerializer(serializers.ModelSerializer): class Meta: @@ -10,9 +10,11 @@ class PageSerializer(serializers.ModelSerializer): 'created_at', 'updated_at'] class PostSerializer(serializers.ModelSerializer): + tags = serializers.PrimaryKeyRelatedField(many=True, queryset=Tag.objects.all(), required=False) + class Meta: model = Post - fields = ['id', 'title', 'type', 'content', 'created_at', 'updated_at'] + fields = ['id', 'title', 'type', 'content', 'tags', 'created_at', 'updated_at'] read_only_fields = ['id', 'created_at', 'updated_at'] extra_kwargs = { 'title': {'required': True}, diff --git a/links/templates/links/post_detail.html b/links/templates/links/post_detail.html index 0b3018f..9f888de 100644 --- a/links/templates/links/post_detail.html +++ b/links/templates/links/post_detail.html @@ -158,22 +158,31 @@

{{ post.title }}

-
+
{{ post.get_type_display }} + {% if post.tags.exists %} +
+ {% for tag in post.tags.all %} + + {{ tag.name }} + + {% endfor %} +
+ {% endif %} + + {{ post.created_at|date:"Y-m-d H:i" }} +
- -
-
{% trans "Created" %}: {{ post.created_at|date:"Y-m-d H:i" }}
{% trans "Last updated" %}: {{ post.updated_at|date:"Y-m-d H:i" }}
diff --git a/links/templates/links/post_form.html b/links/templates/links/post_form.html index 2b25233..085016f 100644 --- a/links/templates/links/post_form.html +++ b/links/templates/links/post_form.html @@ -5,6 +5,8 @@ {% block extra_css %} + + {% endblock %} @@ -72,6 +93,28 @@ {% endif %} + +
+ +
+ +
+ {% if form.tags.errors %} +

{{ form.tags.errors.0 }}

+ {% endif %} +

{% trans "Select existing tags or create new ones" %}

+
+