コード例 #1
0
ファイル: models.py プロジェクト: Hermotimos/rpg_hub
class Demand(Model):
    author = FK(to=Profile, related_name='authored_demands', on_delete=CASCADE)
    addressee = FK(to=Profile,
                   related_name='received_demands',
                   on_delete=CASCADE)
    text = TextField()
    date_created = DateTimeField(auto_now_add=True)
    image = ImageField(upload_to='contact_pics', blank=True, null=True)
    is_done = BooleanField(default=False)

    class Meta:
        ordering = ['-date_created']

    def __str__(self):
        text = self.text
        return f'{text[0:50] + "..." if len(str(text)) > 50 else text}'

    def save(self, *args, **kwargs):
        first_save = True if not self.pk else False
        super().save(*args, **kwargs)

        if first_save and self.image:
            img = Image.open(self.image.path)
            if img.height > 700 or img.width > 700:
                output_size = (700, 700)
                img.thumbnail(output_size)
                img.save(self.image.path)
コード例 #2
0
ファイル: models.py プロジェクト: Hermotimos/rpg_hub
class Statement(Model):
    text = TextField()
    thread = FK(to=Thread, related_name='statements', on_delete=CASCADE)
    author = FK(to=Profile, related_name='statements', on_delete=PROTECT)
    image = ImageField(upload_to='post_pics', blank=True, null=True)
    seen_by = M2M(to=Profile, related_name='statements_seen', blank=True)
    created_at = DateTimeField(auto_now_add=True)
    # Announcement
    options = M2M(to=Option, related_name='threads', blank=True)

    class Meta:
        ordering = ['created_at']

    def __str__(self):
        text = self.text
        return f'{text[:100]}...' if len(str(text)) > 100 else text
    
    def save(self, *args, **kwargs):
        first_save = True if not self.pk else False
        super().save(*args, **kwargs)
        if first_save and self.image:
            img = Image.open(self.image.path)
            if img.height > 700 or img.width > 700:
                output_size = (700, 700)
                img.thumbnail(output_size)
                img.save(self.image.path)
コード例 #3
0
class NewsAnswer(Model):
    text = TextField()
    news = FK(to=News, related_name='news_answers', on_delete=CASCADE)
    author = FK(to=Profile, related_name='news_answers', on_delete=CASCADE)
    image = ImageField(blank=True, null=True, upload_to='news_pics')
    seen_by = M2M(to=Profile, related_name='news_answers_seen', blank=True)
    created_at = DateTimeField(
        # auto_now_add=True
    )

    survey_options = M2M(to=SurveyOption, related_name='threads', blank=True)

    class Meta:
        ordering = ['created_at']

    def __str__(self):
        return self.text[:100] + '...' if len(str(self.text)) > 100 else self.text

    def save(self, *args, **kwargs):
        first_save = True if not self.pk else False
        super().save(*args, **kwargs)
        if first_save and self.image:
            img = Image.open(self.image.path)
            if img.height > 700 or img.width > 700:
                output_size = (700, 700)
                img.thumbnail(output_size)
                img.save(self.image.path)
コード例 #4
0
class Character(Model):
    objects = CharacterManager()

    profile = OneToOne(to=Profile, on_delete=CASCADE)
    first_name = FK(to=FirstName,
                    related_name='characters',
                    on_delete=PROTECT,
                    blank=True,
                    null=True)
    family_name = FK(to=FamilyName,
                     related_name='characters',
                     on_delete=PROTECT,
                     blank=True,
                     null=True)
    cognomen = CharField(max_length=250, blank=True, null=True)
    description = TextField(blank=True, null=True)
    frequented_locations = M2M(to=Location,
                               related_name='frequented_by_characters',
                               blank=True)
    biography_packets = M2M(to=BiographyPacket,
                            related_name='characters',
                            blank=True)
    dialogue_packets = M2M(to=DialoguePacket,
                           related_name='characters',
                           blank=True)

    # USE: profile.characters_known_directly.all()
    # for characters that the profile knows directly
    known_directly = M2M(to=Profile,
                         related_name='characters_known_directly',
                         blank=True)
    known_indirectly = M2M(to=Profile,
                           related_name='characters_known_indirectly',
                           blank=True)
    sorting_name = CharField(max_length=250, blank=True, null=True)

    class Meta:
        ordering = ['sorting_name']
        verbose_name = '* CHARACTER'
        verbose_name_plural = '* CHARACTERS'

    def __str__(self):
        name = f"{self.first_name} " if self.first_name else ""
        family_name = f"{self.family_name} " if self.family_name else ""
        cognomen = f"{self.cognomen} " if self.cognomen else ""
        return f"{name}{family_name}{cognomen}".strip()

    def save(self, *args, **kwargs):
        self.sorting_name = create_sorting_name(self.__str__())
        super().save(*args, **kwargs)

    def all_known(self):
        return self.known_directly.all() | self.known_indirectly.all()

    def informables(self):
        qs = Profile.active_players.all()
        qs = qs.exclude(id__in=self.all_known())
        qs = qs.exclude(character__id=self.pk)
        return qs
コード例 #5
0
ファイル: models.py プロジェクト: Hermotimos/rpg_hub
class ProfileKlass(Model):
    profile = FK(to=Profile, related_name='profile_klasses', on_delete=PROTECT)
    klass = FK(to=Klass, related_name='profile_klasses', on_delete=PROTECT)
    title = CharField(max_length=200, blank=True, null=True)
    experience = PositiveSmallIntegerField()

    def __str__(self):
        return f'{self.profile}: {self.klass.name}'

    class Meta:
        ordering = ['profile__character__first_name']
        verbose_name = 'Profile Klass'
        verbose_name_plural = 'Profile Klasses'
コード例 #6
0
class Skill(Model):
    name = CharField(max_length=100, unique=True)
    tested_trait = CharField(max_length=50, blank=True, null=True)
    image = ImageField(upload_to='site_features_pics', blank=True, null=True)
    allowed_profiles = M2M(
        to=Profile,
        limit_choices_to=Q(status='player'),
        related_name='allowed_skills',
        blank=True,
    )
    group = FK(to=SkillGroup,
               related_name='skills',
               on_delete=PROTECT,
               blank=True,
               null=True)
    types = M2M(to=SkillType, related_name='skills', blank=True)
    sorting_name = CharField(max_length=101, blank=True, null=True)

    def __str__(self):
        return str(self.name)

    def save(self, *args, **kwargs):
        if self.name:
            self.sorting_name = create_sorting_name(self.name)
        super().save(*args, **kwargs)

    def short_name(self):
        return rid_of_special_chars(self.name)

    class Meta:
        ordering = ['sorting_name']
コード例 #7
0
class Modifier(Model):
    """Ex. factor and value combine into: +2 KP, -1 TRAF, +2 OBR, etc."""
    sign = CharField(max_length=5, choices=SIGN_CHOICES, blank=True, null=True)
    value_number = DecimalField(max_digits=10,
                                decimal_places=2,
                                blank=True,
                                null=True)
    value_percent = DecimalField(max_digits=3,
                                 decimal_places=2,
                                 validators=PERCENTAGE_VALIDATOR,
                                 blank=True,
                                 null=True)
    factor = FK(to=Factor, related_name='modifiers', on_delete=PROTECT)
    condition = CharField(max_length=200, blank=True, null=True)

    def __str__(self):
        sign = ""
        if self.sign:
            sign = "+" if self.sign == "plus" else "-"
        if self.value_number:
            value = str(self.value_number).rstrip('0').rstrip('.')
        else:
            value = str(
                float(self.value_percent) * 100).rstrip('0').rstrip('.') + "%"
        condition = f" [{self.condition}]" if self.condition else ""
        return f"{sign}{value} {self.factor.name}{condition}"

    class Meta:
        ordering = [
            'sign', 'value_number', 'value_percent', 'factor', 'condition'
        ]
コード例 #8
0
ファイル: models.py プロジェクト: Hermotimos/rpg_hub
class Achievement(Model):
    name = CharField(max_length=100)
    description = TextField()
    profile = FK(to=Profile, related_name='achievements', on_delete=PROTECT)

    def __str__(self):
        return self.name
コード例 #9
0
class AuxiliaryNameGroup(Model):
    """A class for storing info about social or local specifics of a name.
    This may serve to differentiate names within a "big" location indicated in
    name.affix_group.name_group, ex.
        1)
        name_group ~ Fehzan,
        auxiliary_name_group ~ social_group='Royal names' or location='Ketra'
        2)
        name_group ~ Altankara | Nowa Altankara | Bastos | Skadia,
        auxiliary_name_group ~ location='Skadia'
    The 'color' attribute is intended to help distinguish these visually within
    a NameGroup on site.
    """
    objects = AuxiliaryNameGroupManager()

    color = CharField(max_length=100, blank=True, null=True)
    location = FK(to=Location, blank=True, null=True, on_delete=PROTECT)
    social_info = TextField(help_text='Social group indication if no location',
                            blank=True,
                            null=True)

    class Meta:
        ordering = ['social_info', 'location']

    def __str__(self):
        return f"{self.location or self.social_info}"
コード例 #10
0
class CharacterGroup(Model):
    """A mnodel for storing default knowledge packet sets for groups of
     characters. These should be automatically added to the knowlege packets of
     a newly created Character that belongs to a CharacterGroup (by signals).
    """
    name = CharField(max_length=250)
    author = FK(
        to=Profile,
        related_name='character_groups_authored',
        on_delete=SET_NULL,
        blank=True,
        null=True,
    )
    characters = M2M(to=Character, related_name='character_groups')
    default_knowledge_packets = M2M(
        to=KnowledgePacket,
        related_name='character_group_defaults',
        blank=True,
    )
    default_skills = M2M(to=Skill,
                         related_name='character_group_defaults',
                         blank=True)
    order_no = SmallIntegerField(default=1)

    class Meta:
        ordering = ['order_no', 'name']
        unique_together = ('name', 'author')
        verbose_name = '* CHARACTER GROUP'
        verbose_name_plural = '* CHARACTER GROUPS'

    def __str__(self):
        return f"{self.name} [{self.author}]"
コード例 #11
0
class EliteKlass(Model):
    name = CharField(max_length=100, unique=True)
    elite_profession = FK(
        to=EliteProfession,
        related_name='elite_klasses',
        on_delete=PROTECT,
    )
    description = TextField(max_length=4000, blank=True, null=True)
    start_perks = TextField(max_length=4000, blank=True, null=True)
    allowed_profiles = M2M(
        to=Profile,
        limit_choices_to=Q(status='player'),
        related_name='allowed_elite_klasses',
        blank=True,
    )
    sorting_name = CharField(max_length=250, blank=True, null=True)

    def __str__(self):
        return self.name

    def save(self, *args, **kwargs):
        if self.name:
            self.sorting_name = create_sorting_name(self.name)
        super().save(*args, **kwargs)

    def short_name(self):
        return rid_of_special_chars(self.name)

    class Meta:
        ordering = ['sorting_name']
        verbose_name = 'Elite klass'
        verbose_name_plural = 'Elite klasses'
コード例 #12
0
class Weapon(Model):
    weapon_type = FK(to=WeaponType, related_name='weapons', on_delete=PROTECT)
    name = CharField(max_length=100, unique=True)
    description = TextField(max_length=4000, blank=True, null=True)
    picture_sets = M2M(to=PictureSet, related_name='weapons', blank=True)

    # -------------------# TODO marked for removal [in 2023]-------------------
    delay = PositiveSmallIntegerField()
    damage_big_dices = CharField(max_length=10, blank=True, null=True)
    damage_big_add = PositiveSmallIntegerField(blank=True, null=True)
    # -------------------------------------------------------------------------

    damage_small_dices = CharField(max_length=10, blank=True, null=True)
    damage_small_add = PositiveSmallIntegerField(blank=True, null=True)
    damage_type = CharField(max_length=10, choices=DAMAGE_TYPES)
    special = TextField(max_length=4000, blank=True, null=True)
    range = CharField(max_length=100, blank=True, null=True)
    size = CharField(max_length=5, choices=SIZES)
    trait = CharField(max_length=10, choices=TRAITS)
    avg_price_value = PositiveSmallIntegerField(blank=True, null=True)
    avg_price_currency = CharField(max_length=5,
                                   choices=CURRENCIES,
                                   blank=True,
                                   null=True)
    avg_weight = DecimalField(max_digits=10, decimal_places=1)
    allowed_profiles = M2M(
        to=Profile,
        limit_choices_to=Q(status='player'),
        related_name='allowed_weapons',
        blank=True,
    )
    sorting_name = CharField(max_length=250, blank=True, null=True)

    def __str__(self):
        return self.name

    def save(self, *args, **kwargs):
        if self.name:
            self.sorting_name = create_sorting_name(self.name)
        super().save(*args, **kwargs)

    def short_name(self):
        return rid_of_special_chars(self.name)

    def damage_summary(self):
        damage_small = str(self.damage_small_dices)
        # if self.damage_small_add:
        #     damage_small += ('+' + str(self.damage_small_add))
        # damage_big = str(self.damage_big_dices)
        # if self.damage_big_add:
        #     damage_big += ('+' + str(self.damage_big_add))
        damage_small_add = ""
        if self.damage_small_add:
            damage_small_add += ("+" + str(self.damage_small_add))
        return f"{self.damage_small_dices}{damage_small_add}"

    class Meta:
        ordering = ['sorting_name']
コード例 #13
0
class SkillGroup(Model):
    """A loose grouping category for Skills."""
    name = CharField(max_length=100, unique=True)
    type = FK(to=SkillType, related_name='skill_groups', on_delete=PROTECT)

    def __str__(self):
        return self.name

    class Meta:
        ordering = ['name']
コード例 #14
0
class AudioSet(Model):
    title = CharField(max_length=200)
    description = TextField(max_length=500, blank=True, null=True)
    main_audio = FK(to=Audio, on_delete=PROTECT)
    audios = M2M(to=Audio, related_name='audio_sets', blank=True)

    class Meta:
        ordering = ['title']

    def __str__(self):
        return self.title
コード例 #15
0
class FamilyName(Model):
    form = CharField(max_length=250, unique=True)
    info = TextField(blank=True, null=True)
    locations = M2M(to=Location, related_name="family_names", blank=True)
    group = FK(to=FamilyNameGroup, on_delete=PROTECT, blank=True, null=True)

    class Meta:
        ordering = ['group', 'form']

    def __str__(self):
        return self.form
コード例 #16
0
class Item(Model):
    name = CharField(max_length=250)
    description = TextField()
    amount = PositiveSmallIntegerField(default=1)
    weight = DecimalField(max_digits=10, decimal_places=2, default=0)
    storage = FK(to=ItemStorage, related_name='items', on_delete=CASCADE)

    def __str__(self):
        return f'{self.name} [{self.storage.name}]'

    class Meta:
        ordering = ['name']
コード例 #17
0
ファイル: models.py プロジェクト: Hermotimos/rpg_hub
class Option(Model):
    author = FK(to=Profile, related_name='options', on_delete=CASCADE)
    text = CharField(max_length=50)
    voters_yes = M2M(to=Profile, related_name='options_votes_yes', blank=True)
    voters_no = M2M(to=Profile, related_name='options_votes_no', blank=True)
    
    class Meta:
        ordering = ['text']
    
    def __str__(self):
        text = self.text
        return f'{text[:100]}...' if len(str(text)) > 100 else text
コード例 #18
0
ファイル: models.py プロジェクト: Hermotimos/rpg_hub
class ThreadTag(Model):
    title = CharField(max_length=20)
    author = FK(to=Profile, related_name='thread_tags', on_delete=CASCADE)
    color = CharField(max_length=7, default='#000000')
    kind = CharField(max_length=15, choices=THREAD_KINDS)

    class Meta:
        ordering = ['kind', 'author', 'title']
        unique_together = ['title', 'author', 'kind']

    def __str__(self):
        return f"#{self.title}"
コード例 #19
0
ファイル: models.py プロジェクト: Hermotimos/rpg_hub
class Level(Model):
    profile_klass = FK(to=ProfileKlass,
                       related_name='levels',
                       on_delete=CASCADE)
    achievements = M2M(to=Achievement, related_name='levels', blank=True)
    level_number = PositiveSmallIntegerField()
    level_mods = TextField()

    def __str__(self):
        return f'{self.profile_klass} [{self.level_number}]'

    class Meta:
        ordering = ['profile_klass', 'level_number']
コード例 #20
0
class FirstName(Model):
    objects = FirstNameManager()

    form = CharField(max_length=250, unique=True)
    form_2 = CharField(max_length=250, blank=True, null=True)
    info = TextField(blank=True, null=True)
    is_ancient = BooleanField(default=False)
    # FK fields nullable to allow creation of Character via registration form
    affix_group = FK(to=AffixGroup,
                     related_name='first_names',
                     on_delete=PROTECT,
                     blank=True,
                     null=True)
    auxiliary_group = FK(to=AuxiliaryNameGroup,
                         on_delete=PROTECT,
                         blank=True,
                         null=True)

    class Meta:
        ordering = ['auxiliary_group', 'form']

    def __str__(self):
        return self.form
コード例 #21
0
class News(Model):
    objects = NewsManager()
    
    title = CharField(max_length=100, unique=True)
    topic = FK(to=Topic, related_name='news', on_delete=CASCADE)
    allowed_profiles = M2M(to=Profile, related_name='allowed_news')
    created_at = DateTimeField(auto_now_add=True)
    followers = M2M(to=Profile, related_name='followed_news', blank=True)

    def __str__(self):
        return self.title[:50] + '...' if len(str(self.title)) > 100 else self.title

    class Meta:
        verbose_name = 'News'
        verbose_name_plural = 'News'
コード例 #22
0
class SurveyOption(Model):
    objects = SurveyOptionManager()
    
    author = FK(to=Profile, related_name='survey_options_authored',
                on_delete=CASCADE)
    option_text = CharField(max_length=50)
    yes_voters = M2M(to=Profile, related_name='survey_yes_votes', blank=True)
    no_voters = M2M(to=Profile, related_name='survey_no_votes', blank=True)
    
    class Meta:
        ordering = ['option_text']
    
    def __str__(self):
        return self.option_text[:100] + '...' if len(
            str(self.option_text)) > 100 else self.option_text
コード例 #23
0
class AffixGroup(Model):
    objects = AffixGroupManager()

    affix = CharField(max_length=100)
    type = CharField(max_length=20, choices=NAME_TYPES, default='MALE')
    name_group = FK(to=NameGroup,
                    related_name='affix_groups',
                    on_delete=PROTECT)

    class Meta:
        ordering = ['name_group', 'type', 'affix']
        unique_together = ('affix', 'type', 'name_group')

    def __str__(self):
        return f"[{self.name_group}] | {self.type} | {self.affix}"
コード例 #24
0
ファイル: models.py プロジェクト: Hermotimos/rpg_hub
class DemandAnswer(Model):
    demand = FK(to=Demand, related_name='demand_answers', on_delete=CASCADE)
    author = FK(to=Profile, related_name='demand_answers', on_delete=CASCADE)
    text = TextField()
    date_posted = DateTimeField(auto_now_add=True)
    image = ImageField(upload_to='contact_pics', blank=True, null=True)

    class Meta:
        ordering = ['date_posted']

    def save(self, *args, **kwargs):
        first_save = True if not self.pk else False
        super().save(*args, **kwargs)

        if first_save and self.image:
            img = Image.open(self.image.path)
            if img.height > 700 or img.width > 700:
                output_size = (700, 700)
                img.thumbnail(output_size)
                img.save(self.image.path)

    def __str__(self):
        text = self.text
        return f'{text[0:100] + "..." if len(str(text)) > 100 else text}'
コード例 #25
0
class Klass(Model):
    name = CharField(max_length=100, unique=True)
    profession = FK(to=Profession, related_name='klasses', on_delete=PROTECT)
    description = TextField(max_length=4000, blank=True, null=True)
    start_perks = TextField(max_length=4000, blank=True, null=True)
    lvl_1 = CharField(max_length=500, blank=True, null=True)
    lvl_2 = CharField(max_length=500, blank=True, null=True)
    lvl_3 = CharField(max_length=500, blank=True, null=True)
    lvl_4 = CharField(max_length=500, blank=True, null=True)
    lvl_5 = CharField(max_length=500, blank=True, null=True)
    lvl_6 = CharField(max_length=500, blank=True, null=True)
    lvl_7 = CharField(max_length=500, blank=True, null=True)
    lvl_8 = CharField(max_length=500, blank=True, null=True)
    lvl_9 = CharField(max_length=500, blank=True, null=True)
    lvl_10 = CharField(max_length=500, blank=True, null=True)
    lvl_11 = CharField(max_length=500, blank=True, null=True)
    lvl_12 = CharField(max_length=500, blank=True, null=True)
    lvl_13 = CharField(max_length=500, blank=True, null=True)
    lvl_14 = CharField(max_length=500, blank=True, null=True)
    lvl_15 = CharField(max_length=500, blank=True, null=True)
    lvl_16 = CharField(max_length=500, blank=True, null=True)
    lvl_17 = CharField(max_length=500, blank=True, null=True)
    lvl_18 = CharField(max_length=500, blank=True, null=True)
    lvl_19 = CharField(max_length=500, blank=True, null=True)
    lvl_20 = CharField(max_length=500, blank=True, null=True)
    allowed_profiles = M2M(
        to=Profile,
        limit_choices_to=Q(status='player'),
        related_name='allowed_klasses',
        blank=True,
    )
    sorting_name = CharField(max_length=250, blank=True, null=True)

    def __str__(self):
        return self.name

    def save(self, *args, **kwargs):
        if self.name:
            self.sorting_name = create_sorting_name(self.name)
        super().save(*args, **kwargs)

    def short_name(self):
        return rid_of_special_chars(self.name)

    class Meta:
        ordering = ['sorting_name']
        verbose_name = 'Klass'
        verbose_name_plural = 'Klasses'
コード例 #26
0
class SynergyLevel(Model):
    synergy = FK(to=Synergy, related_name='synergy_levels', on_delete=PROTECT)
    level = CharField(max_length=10, choices=S_LEVELS[1:])
    description = TextField(max_length=4000, blank=True, null=True)
    perks = M2M(to=Perk, related_name='synergy_levels', blank=True)
    acquired_by = M2M(to=Profile, related_name='synergy_levels', blank=True)
    sorting_name = CharField(max_length=250, blank=True, null=True)

    def __str__(self):
        return f'{str(self.synergy.name)} [{self.level}]'

    def save(self, *args, **kwargs):
        self.sorting_name = create_sorting_name(self.__str__())
        super().save(*args, **kwargs)

    class Meta:
        ordering = ['sorting_name']
コード例 #27
0
class ItemStorage(Model):
    name = CharField(max_length=250)
    description = TextField()
    owners = M2M(to=Profile, related_name='item_storages')
    location = FK(
        to=SecondaryLocation,
        related_name='item_storages',
        on_delete=PROTECT,
        blank=True,
        null=True,
    )

    def __str__(self):
        return f'{self.name}: {", ".join([o for o in self.owners.all()])}'

    class Meta:
        ordering = ['name']
コード例 #28
0
ファイル: models.py プロジェクト: Hermotimos/rpg_hub
class GameSession(Model):
    game_no = IntegerField(null=True)
    title = CharField(max_length=200)
    chapter = FK(
        to=Chapter,
        related_name='game_sessions',
        on_delete=PROTECT,
        blank=True,
        null=True,
    )
    date = DateField(blank=True, null=True)

    class Meta:
        ordering = ['game_no']
        verbose_name = 'II. Game session'

    def __str__(self):
        return self.title
コード例 #29
0
class KnowledgePacket(InfoPacket):
    """A class for info packets that might be shared among multiple Skills."""
    author = FK(
        to=Profile,
        related_name='authored_kn_packets',
        on_delete=PROTECT,
        null=True,
        blank=True,
    )
    acquired_by = M2M(to=Profile, related_name='knowledge_packets', blank=True)
    skills = M2M(to=Skill, related_name='knowledge_packets')
    picture_sets = M2M(to=PictureSet,
                       related_name='knowledge_packets',
                       blank=True)

    def informables(self):
        qs = Profile.active_players.all()
        qs = qs.exclude(id__in=self.acquired_by.all())
        return qs
コード例 #30
0
class Picture(Model):
    """An overlay model to create contextual descriptions for Image objects.
    One Image object may have multiple descriptions depending on the context
    in which it was seen and to whom it is known. This allows to create
    multiple overlays for one image with varying descriptions and types.
    """
    image = FK(to=PictureImage, related_name='used_in_pics', on_delete=CASCADE)
    type = CharField(max_length=20, choices=IMG_TYPES)
    description = CharField(max_length=200, blank=True, null=True)
    sorting_name = CharField(max_length=250, blank=True, null=True)

    class Meta:
        ordering = ['type', 'sorting_name']

    def __str__(self):
        return f"[{self.type.upper()}] {self.description}"

    def save(self, *args, **kwargs):
        self.sorting_name = create_sorting_name(self.description)
        super().save(*args, **kwargs)