diff --git a/data/db.sqlite3 b/data/db.sqlite3 index 60f3aa4..a6f7eda 100644 Binary files a/data/db.sqlite3 and b/data/db.sqlite3 differ diff --git a/links/forms.py b/links/forms.py index eb71ceb..80b42f1 100644 --- a/links/forms.py +++ b/links/forms.py @@ -2,6 +2,8 @@ from django import forms from .models import Link from simplemde.fields import SimpleMDEField from django.utils.translation import gettext_lazy as _ +from django.core.validators import URLValidator +import re class LinkForm(forms.ModelForm): text = SimpleMDEField() @@ -14,6 +16,28 @@ class LinkForm(forms.ModelForm): 'description': forms.Textarea(attrs={'rows': 3}), } + def clean_original_url(self): + url = self.cleaned_data.get('original_url') + if not url: + return url + + # Extract template parameters + template_params = re.findall(r'\{([^{}]*)\}', url) + + # Temporarily replace template parameters with placeholder + temp_url = url + for param in template_params: + param_full = '{' + param + '}' + temp_url = temp_url.replace(param_full, 'template-param') + + # Validate the URL with placeholders + try: + URLValidator()(temp_url) + except forms.ValidationError: + raise forms.ValidationError(_("Please enter a valid URL. Template parameters are allowed in the format {param_name,default=value}.")) + + return url + def clean(self): cleaned_data = super().clean() link_type = cleaned_data.get('link_type') diff --git a/links/migrations/0008_alter_link_original_url.py b/links/migrations/0008_alter_link_original_url.py new file mode 100644 index 0000000..3941461 --- /dev/null +++ b/links/migrations/0008_alter_link_original_url.py @@ -0,0 +1,18 @@ +# Generated by Django 5.0.8 on 2024-11-02 11:04 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('links', '0007_link_description'), + ] + + operations = [ + migrations.AlterField( + model_name='link', + name='original_url', + field=models.TextField(blank=True, null=True), + ), + ] diff --git a/links/models.py b/links/models.py index 54d9f20..b9b88ea 100644 --- a/links/models.py +++ b/links/models.py @@ -2,6 +2,7 @@ from django.db import models from django.utils.translation import gettext_lazy as _ from django.urls import reverse import logging +import re logger = logging.getLogger(__name__) @@ -11,8 +12,8 @@ class Link(models.Model): CUSTOM = 'CUSTOM', _('Custom') alias = models.SlugField(max_length=100, unique=True) - original_url = models.URLField(blank=True, null=True) - text = models.TextField(blank=True, null=True) # 改为 TextField + original_url = models.TextField(blank=True, null=True) + text = models.TextField(blank=True, null=True) link_type = models.CharField( max_length=10, choices=LinkType.choices, @@ -23,6 +24,53 @@ class Link(models.Model): updated_at = models.DateTimeField(auto_now=True) description = models.TextField(blank=True, null=True, verbose_name=_("Description")) + def get_template_parameters(self): + """Extract template parameters and their default values from original_url""" + pattern = r'\{([^{}]*)\}' + matches = re.finditer(pattern, self.original_url) + params = {} + + for match in matches: + param_str = match.group(1) + if ',' in param_str: + param_name, default_value = param_str.split(',', 1) + default_value = default_value.strip() + if default_value.startswith('default='): + default_value = default_value[8:].strip('"\'') + params[param_name.strip()] = default_value + else: + params[param_str.strip()] = None + + return params + + def get_processed_url(self, **kwargs): + """Process template URL with provided parameters""" + if not self.original_url: + return None + + processed_url = self.original_url + pattern = r'\{([^{}]*)\}' + matches = re.finditer(pattern, self.original_url) + + for match in matches: + param_str = match.group(1) + if ',' in param_str: + param_name, default_value = param_str.split(',', 1) + default_value = default_value.strip() + if default_value.startswith('default='): + default_value = default_value[8:].strip('"\'') + else: + param_name = param_str.strip() + default_value = None + + value = kwargs.get(param_name, default_value) + if value is None: + raise ValueError(f"No value provided for parameter {param_name}") + + processed_url = processed_url.replace(f"{{{param_str}}}", str(value)) + + return processed_url + def __str__(self): return self.alias diff --git a/links/templates/links/link_form.html b/links/templates/links/link_form.html index d9d204b..75421ab 100644 --- a/links/templates/links/link_form.html +++ b/links/templates/links/link_form.html @@ -45,6 +45,14 @@ {% trans "Custom type allows you to create a link with custom HTML content. Use this when you want to display a message or custom content instead of redirecting." %}
++ {% trans "Template type allows you to create dynamic URLs with parameters. Use {query, default=value} syntax in the URL." %} +
++ {% trans "Example: https://google.com/search?q={query, default=hello}" %} +
+