Simple app to add configuration options to a Django project.
0
fork

Configure Feed

Select the types of activity you want to include in your feed.

at main 98 lines 3.3 kB view raw
1from typing import Sequence, Union 2 3from django.conf import settings 4from django.core.exceptions import ValidationError 5from django.db import models 6from django.utils.translation import gettext_lazy as _ 7 8from options.constants import CONVERTER, FILE, STR, TYPE_CHOICES 9from options.helpers import UploadToDir, convert_value 10from options.managers import OptionManager, UserOptionManager 11 12 13class BaseOption(models.Model): 14 """Base model for system options and configurations.""" 15 16 name = models.CharField( 17 verbose_name=_("parameter name"), max_length=255, unique=True, db_index=True 18 ) 19 public_name = models.CharField( 20 verbose_name=_("public name of the parameter"), 21 max_length=255, 22 unique=False, 23 blank=True, 24 db_index=True, 25 ) 26 help_text = models.TextField(verbose_name=_("help text"), blank=True, null=True) 27 type = models.PositiveIntegerField(choices=TYPE_CHOICES, default=STR) 28 value = models.CharField( 29 null=True, blank=True, default=None, max_length=256, verbose_name=_("value") 30 ) 31 file = models.FileField( 32 upload_to=UploadToDir("options", random_name=True), null=True, blank=True 33 ) 34 is_list = models.BooleanField(default=False) 35 is_public = models.BooleanField(default=False) 36 37 class Meta: 38 abstract = True 39 40 def __str__(self) -> str: 41 return f"{self.public_name}" 42 43 def get_value(self) -> Union[int, str, float, Sequence]: 44 """Gets the value with the proper type. If the type is not 45 valid it would return the default value for the field, to avoid 46 problems with manual database modifications. 47 """ 48 # If the option is a file, returns the URL of the file 49 if self.type == FILE and self.file is not None: 50 return self.file.url 51 if not self.is_list: 52 return convert_value(self.value, self.type) 53 else: 54 values = self.value.split(",") 55 return [convert_value(value, self.type) for value in values] 56 57 def clean(self) -> None: 58 """Calls to the converter to check the type conversion. Added exception 59 for lists, to check all values. 60 """ 61 try: 62 values = [self.value] if not self.is_list else self.value.split(",") 63 [CONVERTER.get(self.type, str)(value) for value in values] 64 except ValueError: 65 raise ValidationError(_("Invalid value for this type.")) 66 # Default public name 67 if not self.public_name: 68 self.public_name = self.name 69 70 def save(self, *args, **kwargs): 71 self.clean() 72 super().save(*args, **kwargs) 73 74 75class Option(BaseOption): 76 """System options and configurations.""" 77 78 objects = OptionManager() 79 80 class Meta: 81 ordering = ["public_name"] 82 swappable = "SIMPLE_OPTIONS_OPTION_MODEL" 83 84 85class UserOption(BaseOption): 86 """Custom option for a user.""" 87 88 user = models.ForeignKey( 89 settings.AUTH_USER_MODEL, related_name="options", on_delete=models.CASCADE 90 ) 91 name = models.CharField(_("parameter name"), max_length=255) 92 93 objects = UserOptionManager() 94 95 class Meta: 96 unique_together = ["user", "name"] 97 ordering = ["public_name"] 98 swappable = "SIMPLE_OPTIONS_USER_OPTION_MODEL"