class Problem(models.Model): underlying_problems = models.ManyToManyField('Problem', blank=True) affected_locations = GM2MField() #TODO: Restrict to place derivatives affected_resources = GM2MField() #TODO: Restrict to resource derivatives associated_trouble_tickets = models.ManyToManyField( TroubleTicket, blank=True) originating_system = models.CharField(max_length=100) # impactImportanceFactor # priority description = models.TextField() # firstAlert # category # responsibleParty # problemEscalation # comments time_raised = models.DateTimeField(auto_now_add=True) time_changed = models.DateTimeField(auto_now=True) reason = models.CharField(max_length=200) # ackStatus # clearStatus # activityStatus # impactPattterns def __str__(self): return "{}:{} at {}".format(self.originating_system, self.reason, self.time_raised)
class Usage(models.Model): usage_date = models.DateTimeField() usage_status = models.CharField(max_length=100) party_roles = GM2MField(related_name="usage_party_roles") usage_specification = GM2MField(related_name="usage_usage_specification") product_prices = models.ManyToManyField(ProductPrice, blank=True) #TODO: place class Meta: abstract = True
class AlarmEvent(models.Model): # Alarm types USER = '******' DEVICE = 'DV' NO_DEVICE = 'ND' ALARM_CHOICES = ( (USER, 'User'), (DEVICE, 'Device'), (NO_DEVICE, 'No-Device') ) alarm = models.ForeignKey(Alarm, on_delete=models.CASCADE, null=True) alarm_type = models.CharField(max_length=2, choices=ALARM_CHOICES, default=USER) created = models.DateTimeField(auto_now_add=True) finished = models.DateTimeField(null=True) device = models.ForeignKey(settings.DEVICE_MODEL, on_delete=models.CASCADE, null=True) variables = models.ForeignKey(settings.VAR_MODEL, on_delete=models.CASCADE, null=True) content_type = GM2MField(blank=True) description = models.CharField(max_length=255, default='description', null=True) def get_contents_type(self): return "\n".join(obj.__str__() + '|' for obj in self.content_type.all()) def __str__(self): return self.alarm_type + '-' + str(self.pk)
class Thesis(ScienceElement): GRADE = ( ('S', 'Superior'), ('MSc', 'Master'), ('Dr', 'Doctorado'), ) content_type = models.ForeignKey(ContentType, on_delete=models.CASCADE) object_id = models.PositiveIntegerField() grade = models.CharField(max_length=10, choices=GRADE) field = models.ForeignKey(Field, on_delete=models.DO_NOTHING) study_center = models.ForeignKey(StudyCenter, on_delete=models.DO_NOTHING) start_date = models.DateField(default=django.utils.timezone.now) end_date = models.DateField(null=True, blank=True) end_date_tutor = models.DateField(null=True, blank=True) student = GenericForeignKey('content_type', 'object_id') tutors = GM2MField(Worker, ExternalPerson, related_name='thesis_tutoradas') @property def type(self): return 'Tesis' @property def in_process(self): return True if not self.end_date_tutor else False @property def degree_title(self): return self.grade + ' en ' + self.field.name
class Service(models.Model): TIPO = ( ('EST', 'Estatal'), ('COM', 'Comercial'), ('EXP', 'Exportación'), ) content_type = models.ForeignKey(ContentType, on_delete=models.CASCADE) object_id = models.PositiveIntegerField() start_date = models.DateField(default=django.utils.timezone.now()) end_date = models.DateField() name = models.CharField(max_length=50, blank=True, null=True) type_of = models.CharField(max_length=20, choices=TIPO, blank=True, null=True) dim = models.CharField(max_length=50, blank=True, null=True) cost_center = models.ForeignKey(CostCenter, on_delete=models.DO_NOTHING) participants = GM2MField(Worker, ExternalPerson, related_name='services') responsible = GenericForeignKey('content_type', 'object_id') client = models.ForeignKey(Client, on_delete=models.CASCADE, blank=True, null=True) mont = models.FloatField(default=0.0) entity = models.ForeignKey(Entity, on_delete=models.CASCADE, null=True, blank=True) results = models.ManyToManyField(Result, null=True, blank=True) tasks = models.ManyToManyField(Task, null=True, blank=True) def __str__(self): return self.name @property def type(self): return 'Service'
class MachineTag(models.Model): namespace = models.CharField(max_length=100, blank=True, default='') namespace_slug = models.SlugField(max_length=100, editable=False, default='') predicate = models.CharField(max_length=100, blank=True, default='') predicate_slug = models.SlugField(max_length=100, editable=False, default='') value = models.CharField(max_length=300, blank=True, default='') value_slug = models.SlugField(max_length=100, editable=False, default='') label = models.CharField( max_length=600, editable=False, blank=True, default='') tagged = GM2MField(Link, Feed) objects = models.Manager() class Meta: verbose_name = 'Machine tag' verbose_name_plural = 'Machine tags' unique_together = ( ('namespace', 'predicate', 'value') ) def __str__(self): return '{0.namespace}:{0.predicate}={0.value}'.format(self) def save(self, *args, **kwargs): if not self.namespace_slug: self.namespace_slug = slugify(self.namespace) if not self.predicate_slug: self.predicate_slug = slugify(self.predicate) if not self.value_slug: self.value_slug = slugify(self.value) if not self.label: self.label = '{0.namespace_slug}:{0.predicate_slug}={0.value_slug}'.format( self) return super().save(*args, **kwargs)
class Tribunal(models.Model): date = models.DateField() thesis = models.ForeignKey(Thesis, on_delete=models.CASCADE) members = GM2MField(Worker, ExternalPerson, related_name='tribunals') def __str__(self): return self.thesis.title
class Comision(models.Model): creation_date = models.DateField() integrants = GM2MField(Worker, ExternalPerson, related_name='comisiones') @property def type(self): return 'Comision' def __str__(self): return 'Comision ' + str(self.pk)
class Ponency(models.Model): title = models.CharField(max_length=100) authors = GM2MField(Worker, ExternalPerson, related_name='ponencys') def __str__(self): return self.title @property def type(self): return 'Ponencia'
class Oponency(models.Model): content_type = models.ForeignKey(ContentType, on_delete=models.CASCADE) object_id = models.PositiveIntegerField() date = models.DateField() element = GenericForeignKey('content_type', 'object_id') # Articulo, Tesis, Resultado, Proyecto opponents = GM2MField(Worker, ExternalPerson, related_name='oponencys') def __str__(self): return self.element.title
class TestModel(models.Model): name = models.CharField(max_length=200) test = GM2MField() for_inline = models.ForeignKey('self', null=True, blank=True, related_name='inline_test_models') def __str__(self): return self.name
class Book(ScienceElement): isbn = models.CharField(max_length=50) authors = GM2MField(Worker, ExternalPerson, related_name='books') data_base = models.CharField(max_length=100, null=True, blank=True) # que es esto? pages = models.CharField(max_length=50) # cant de pages? pub_date = models.DateField(default=django.utils.timezone.now) web_url = models.URLField(null=True, blank=True) editorial = models.CharField(max_length=50) country = models.CharField(max_length=50) chapter = models.CharField(max_length=50) # cant de capitulos? total_pages = models.CharField(max_length=50) # no deberia ser entero? gray_literature = models.BooleanField(default=False) @property def type(self): return 'Libro'
class Result(ScienceElement): LEVEL = ( ('1', 'Primer Nivel'), ('2', 'Segundo Nivel'), ('3', 'Tercer Nivel'), ) date = models.DateField(default=django.utils.timezone.now) manager_by_cfa = models.BooleanField(default=True) approved_by_cc = models.BooleanField(default=False) prize = models.ManyToManyField(Prize, null=True, blank=True) level = models.CharField(max_length=40, choices=LEVEL) integrants = GM2MField(Worker, ExternalPerson, related_name='results') @property def type(self): return 'Resultado'
class Project(ScienceElement): LEVEL = ( ('PP', 'Programa Priorizado'), ('PE', 'Proyecto Empresarial'), ('INF', 'Institucional ft'), ('IN', 'Institucional'), ) TYPE = ( ('N', 'Nacional'), ('I', 'Internacional'), ) content_type = models.ForeignKey(ContentType, on_delete=models.CASCADE) object_id = models.PositiveIntegerField() cost_center = models.ForeignKey(CostCenter, on_delete=models.DO_NOTHING) program = models.ForeignKey(Program, on_delete=models.DO_NOTHING, null=True, blank=True) boss = GenericForeignKey('content_type', 'object_id') participants = GM2MField(Worker, ExternalPerson, related_name='projects') manager_by_cfa = models.BooleanField(default=False) type = models.CharField(max_length=40, choices=TYPE) level = models.CharField(max_length=40, choices=LEVEL, blank=True, null=True) aproved_date = models.DateField(default=datetime.datetime.now()) start_date = models.DateField(default=datetime.datetime.now()) end_plan_date = models.DateField() end_date = models.DateField(null=True, blank=True) executor_entity = models.ForeignKey(Entity, on_delete=models.DO_NOTHING, null=True, blank=True) description = models.CharField(max_length=500, null=True, blank=True) results = models.ManyToManyField(Result, null=True, blank=True) entity = models.ManyToManyField(Entity, related_name="entities", null=True, blank=True) #manager = ProyectoManager() @property def type(self): return 'Proyecto' @property def en_desarrollo(self): return True if not self.end_date else False @property def en_atraso(self): return True if not self.end_date and self.end_date > datetime.date.now() else False def for_next_year(self): return True if self.aproved_date.year > datetime.date.now().year else False
class Group(ExchangeProperty): manager = models.ForeignKey(User, related_name='groups') username = models.CharField(max_length=255) members = models.ManyToManyField(User, related_name='+') delivery_members = GM2MField() senders_out = models.BooleanField( default=False, help_text='Delivery management for senders outside organizational unit' ) tracker = FieldTracker() @property def email(self): return '{}@{}'.format(self.username, self.tenant.domain) def get_log_fields(self): return super(Group, self).get_log_fields() + ('username', 'email')
class PhysicalResource(Resource): power_state = models.CharField(max_length=100, null=True, blank=True, choices=POWER_STATES) physcial_objects = GM2MField( related_name="objects") #TODO: Restrict to physical_object derivatives place_content_type = models.ForeignKey( ContentType, null=True, blank=True, related_name="%(app_label)s_%(class)s_ownership") place_object_id = models.PositiveIntegerField(null=True, blank=True) place = GenericForeignKey('place_content_type', 'place_object_id') def __str__(self): return "%s at %s" % (self.name, self.place)
class PartyRole(models.Model): valid_from = models.DateTimeField(auto_now_add=True) valid_to = models.DateTimeField(null=True, blank=True) name = models.CharField(max_length=200) party_content_type = models.ForeignKey( ContentType, related_name="%(app_label)s_%(class)s_ownership") party_object_id = models.PositiveIntegerField() party = GenericForeignKey('party_content_type', 'party_object_id') contact_mediums = GM2MField() class Meta: abstract = True @property def individual(self): if type(self.party) is Individual: return self.party @individual.setter def individual(self, value): if type(value) is Individual or value == None: self.party = value else: raise Exception( "Invalid type of party provided as individual to PartyRole: %s" % type(value)) @property def organisation(self): if type(self.party) is Organisation: return self.party @organisation.setter def organisation(self, value): if type(value) is Organisation or value == None: self.party = value else: raise Exception( "Invalid type of party provided as organisation to PartyRole: %s" % type(value)) def __str__(self): return "%s as a %s" % (self.party, self.name)
class Reserva(models.Model): ESTADO_CHOICES = ( ('P', 'Pendiente'), ('A', 'Aceptada'), ('R', 'Rechazada'), ) TIPO_CHOICES = ( ('A', 'Artículo'), ('E', 'Espacio'), ) profile = models.ForeignKey(Profile, on_delete=models.CASCADE, null=True) fh_reserva = models.DateTimeField() fh_ini_reserva = models.DateTimeField() fh_fin_reserva = models.DateTimeField() estado_reserva = models.CharField(max_length=50, choices=ESTADO_CHOICES, default='P') tipo = models.CharField(max_length=50, choices=TIPO_CHOICES) related = GM2MField()
class Prestamo(models.Model): ESTADO_CHOICES = ( ('V', 'Vigente'), ('C', 'Caducado'), ('P', 'Perdido'), ('R', 'Recibido'), ) TIPO_CHOICES = ( ('A', 'Artículo'), ('E', 'Espacio'), ) profile = models.ForeignKey(Profile, on_delete=models.CASCADE, null=True) fh_ini_prestamo = models.DateTimeField() fh_fin_prestamo = models.DateTimeField() estado_prestamo = models.CharField(max_length=50, choices=ESTADO_CHOICES, default='V') tipo = models.CharField(max_length=50, choices=TIPO_CHOICES) related = GM2MField()
def test_deconstruct(self): # this test will run on *all* testcases having no subclasses if self.__class__.__subclasses__(): return skip('not an end test class') try: field = self.links.__class__._meta.get_field('related_objects') except AttributeError: return __, __, args, kwargs = field.deconstruct() new_field = GM2MField(*args, **kwargs) # just checking the strings output, as for an attr to attr comparison # we would need to run contribute_to_class self.assertSetEqual(set(['%s.%s' % (r.model._meta.app_label, r.model._meta.object_name) for r in field.remote_field.rels if not getattr(r, '_added', False)]), set(args))
class UserProfile(models.Model): user = models.OneToOneField(User) sex = models.CharField(null=True, max_length=1, default=None, choices=SEX, verbose_name=u'Are you male or female?') city = models.CharField(null=True, default=None, max_length=100) timezone = models.CharField(null=True, default=None, max_length=100) avatar = models.ImageField( upload_to='imagesandvideos/imageorvideos/avatars', default='avatars/no_avatar.jpg', blank=True, null=True) saved_items = GM2MField() private_saved_items = models.BooleanField(default=False) follows = models.ManyToManyField('self', related_name='followers', symmetrical=False) def __unicode__(self): return u'%s' % self.user
class Article(ScienceElement): LEVEL = ( ('I', 'Grupo I'), ('II', 'Grupo II'), ('III', 'Grupo III'), ('IV', 'Grupo IV'), ) PARTICIPATION = ( ('AP', 'Autor Principal'), ('OA', 'Otro Autor'), ) STATUS = ( ('1', 'Enviado'), ('2', 'En revision'), ('3', 'Aceptado'), ('4', 'Publicado'), ) doi = models.CharField(max_length=50, unique=True) authors = GM2MField(Worker, ExternalPerson, related_name='articles') database = models.CharField(max_length=100, null=True, blank=True) pages = models.CharField(max_length=50) pub_date = models.DateField(default=django.utils.timezone.now, null=True) web_url = models.URLField(null=True, blank=True) magazine = models.CharField(max_length=200, null=True, blank=True) issn = models.CharField(max_length=50, unique=True, null=True, blank=True) volume = models.PositiveSmallIntegerField(null=True, blank=True) number = models.PositiveSmallIntegerField(null=True, blank=True) impact_level = models.CharField(max_length=50, choices=LEVEL, null=True, blank=True) participation = models.CharField(max_length=50, choices=PARTICIPATION) indexed = models.BooleanField(default=False) refereed = models.BooleanField(default=False) gray_literature = models.BooleanField(default=False) @property def type(self): return 'Artículo'
class QuickBlock(SmartModel): """ A QuickBlock is just a block of content, organized by type and priority. All fields are optional letting you use them for different things. """ quickblock_type = models.ForeignKey( QuickBlockType, verbose_name="Content Type", help_text="The category, or type for this content block") title = models.CharField( max_length=255, blank=True, null=True, help_text="The title for this block of content, optional") summary = models.TextField( blank=True, null=True, help_text="The summary for this item, should be short") content = models.TextField( blank=True, null=True, help_text="The body of text for this content block, optional") image = models.ImageField( blank=True, null=True, upload_to='quickblocks', help_text= "Any image that should be displayed with this content block, optional") color = models.CharField( blank=True, null=True, max_length=16, help_text= "A background color to use for the image, in the format: #rrggbb") link = models.CharField( blank=True, null=True, max_length=255, help_text= "Any link that should be associated with this content block, optional") video_id = models.CharField( blank=True, null=True, max_length=255, help_text= "The id of the YouTube video that should be linked to this item") tags = models.CharField( blank=True, null=True, max_length=255, help_text= "Any tags for this content block, separated by spaces, can be used to do more advanced filtering, optional" ) priority = models.IntegerField( default=0, help_text= "The priority for this block, higher priority blocks come first") items = GM2MField(related_name='stories', help_text="The items this story is all about") def space_tags(self): """ If we have tags set, then adds spaces before and after to allow for SQL querying for them. """ if self.tags and self.tags.strip(): self.tags = " " + self.tags.strip().lower() + " " def sorted_images(self): return self.images.filter(is_active=True).order_by('-priority') def __unicode__(self): return self.title
class Export(AbstractExport): STATUS_PENDING = 'PENDING' STATUS_PROCESSING = 'PROCESSING' STATUS_FAILED = 'FAILED' STATUS_FINISHED = 'FINISHED' STATUSES = [(STATUS_PENDING, _('pending')), (STATUS_PROCESSING, _('processing')), (STATUS_FAILED, _('failed')), (STATUS_FINISHED, _('finished'))] status = models.CharField(_('status'), choices=STATUSES, max_length=10, default=STATUS_PENDING) items = GM2MField(*related_models, related_name='exports_where_item') total = models.PositiveIntegerField(_('total items'), default=0) emails = ArrayField( verbose_name=_('emails'), base_field=models.EmailField(), default=list, ) objects = ExportQuerySet.as_manager() history = AuditlogHistoryField() class Meta: verbose_name = _('export') verbose_name_plural = _('exports') ordering = ('created', ) default_permissions = settings.DEFAULT_PERMISSIONS def __str__(self): model = self.content_type.model_class() name = model._meta.verbose_name_plural if model else self.content_type.model return '{} #{} ({})'.format(_('Export'), self.pk, name) def _get_base_url(self): app_label = self.get_app_label() url = reverse(f'{app_label}:{self.content_type.model}_list') return url def get_items_url(self): return f'{self._get_base_url()}?export={self.pk}' def get_absolute_url(self): return f'{self._get_base_url()}?{self.query_string}' def get_app_label(self): if self.context in [self.CONTEXT_LIST, self.CONTEXT_DETAIL]: app_label = self.content_type.app_label if self.content_type.app_label != 'invoicing' else 'billing' else: module = exporters_module_mapping[self.model_class._meta.label][ self.context] app_label = module.split('.')[-2] return app_label def send_mail(self, language, filename=None): export_class_name = f'{self.__class__.__module__}.{self.__class__.__name__}' jobs.mail_export.delay(self.pk, export_class_name, language, filename) @property def object_list(self): ids = list(self.items.all().values_list('gm2m_pk', flat=True)) # ids = list(map(int, ids)) model = self.content_type.model_class() return model.objects.filter(id__in=ids) @property def exporter_params(self): return { 'params': self.params, 'items': self. object_list, # this is required as we want to send identically same export (not currently available filtered data) 'user': self.creator, 'recipients': self.recipients.all(), 'selected_fields': self.fields }
class Character(models.Model): """ This is the information for a character. ***NOTE: This is the specific model a Member will be interacting with the most.*** """ username = models.ForeignKey('accounts.Member', related_name='characters', editable=False) accessed = models.DateTimeField(auto_now=True,) # Flair char_name = models.CharField(max_length=1024, blank=True, null=True,) description = models.TextField(blank=True, null=True,) portrait = models.ImageField(blank=True, null=True,) char_age = models.SmallIntegerField(blank=True, null=True,) char_height = models.SmallIntegerField(blank=True, null=True,) char_weight = models.SmallIntegerField(blank=True, null=True,) char_skin_color = models.CharField(max_length=128, blank=True, null=True,) char_hair_color = models.CharField(max_length=128, blank=True, null=True,) char_eye_color = models.CharField(max_length=128, blank=True, null=True,) personality = models.TextField(blank=True, null=True,) ideals = models.TextField(blank=True, null=True,) bonds = models.TextField(blank=True, null=True,) flaws = models.TextField(blank=True, null=True,) allies = models.CharField(max_length=512, blank=True, null=True,) organizations = models.CharField(max_length=512, blank=True, null=True,) # General traits such as languages. char_traits = GM2MField() # Basics char_classes = models.ManyToManyField('rules.Class', related_name='character_classes', through='ClassLevel', blank=True,) char_prestige_classes = models.ManyToManyField('rules.PrestigeClass', related_name='character_prestiges', blank=True,) char_race = models.ForeignKey('rules.Race', related_name='character_races', blank=True, null=True,) char_subrace = models.ForeignKey('rules.Subrace', related_name='character_subraces', blank=True, null=True) char_background = models.ForeignKey('rules.Background', related_name='character_backgrounds', blank=True, null=True) alignment = models.ForeignKey('rules.Alignment', related_name='character_alignments', blank=True, null=True,) char_xp = models.IntegerField(default=0, blank=True, null=True,) # Ability Scores STR_score = IntegerMinMaxField(min_value=1, max_value=20, blank=True, null=True,) DEX_score = IntegerMinMaxField(min_value=1, max_value=20, blank=True, null=True,) CON_score = IntegerMinMaxField(min_value=1, max_value=20, blank=True, null=True,) INT_score = IntegerMinMaxField(min_value=1, max_value=20, blank=True, null=True,) WIS_score = IntegerMinMaxField(min_value=1, max_value=20, blank=True, null=True,) CHA_score = IntegerMinMaxField(min_value=1, max_value=20, blank=True, null=True,) # Saving Throws STR_saving_throw = models.BooleanField(default=False) DEX_saving_throw = models.BooleanField(default=False) CON_saving_throw = models.BooleanField(default=False) INT_saving_throw = models.BooleanField(default=False) WIS_saving_throw = models.BooleanField(default=False) CHA_saving_throw = models.BooleanField(default=False) # Actions >> May not need to use if just pulling through races and etc. features = models.ManyToManyField('rules.Feature', related_name='character_features', blank=True,) # Combat conditions = models.ManyToManyField('rules.Condition', related_name='character_conditions', blank=True,) death_fails = models.SmallIntegerField(default=0) death_successes = models.SmallIntegerField(default=0) max_health = models.SmallIntegerField(default=0) current_health = models.SmallIntegerField(default=0) temp_addtl_hp = models.SmallIntegerField(default=0) hit_dice_current = models.SmallIntegerField(default=1) speed = models.SmallIntegerField(default=30) inspiration = models.SmallIntegerField(blank=True, null=True,) # Spells spell_casting = models.BooleanField(default=False) spell_book = models.ManyToManyField('spells.Spell', related_name='character_spells', through='SpellsReady', blank=True,) spell_slots_1_current = models.SmallIntegerField(blank=True, null=True,) spell_slots_2_current = models.SmallIntegerField(blank=True, null=True,) spell_slots_3_current = models.SmallIntegerField(blank=True, null=True,) spell_slots_4_current = models.SmallIntegerField(blank=True, null=True,) spell_slots_5_current = models.SmallIntegerField(blank=True, null=True,) spell_slots_6_current = models.SmallIntegerField(blank=True, null=True,) spell_slots_7_current = models.SmallIntegerField(blank=True, null=True,) spell_slots_8_current = models.SmallIntegerField(blank=True, null=True,) spell_slots_9_current = models.SmallIntegerField(blank=True, null=True,) spell_slots_1_maximum = models.SmallIntegerField(blank=True, null=True, ) spell_slots_2_maximum = models.SmallIntegerField(blank=True, null=True, ) spell_slots_3_maximum = models.SmallIntegerField(blank=True, null=True, ) spell_slots_4_maximum = models.SmallIntegerField(blank=True, null=True, ) spell_slots_5_maximum = models.SmallIntegerField(blank=True, null=True, ) spell_slots_6_maximum = models.SmallIntegerField(blank=True, null=True, ) spell_slots_7_maximum = models.SmallIntegerField(blank=True, null=True, ) spell_slots_8_maximum = models.SmallIntegerField(blank=True, null=True, ) spell_slots_9_maximum = models.SmallIntegerField(blank=True, null=True, ) # Special Point Tracking (Rage, Inspiration, Etc.): # TODO: Add field to check which feature they have for points and base tracking off of that. has_point_tracking = models.BooleanField(default=False) max_points = models.SmallIntegerField(blank=True, null=True) current_points = models.SmallIntegerField(blank=True, null=True) # Inventory tools_inv = models.ManyToManyField('equipment.Tool', related_name='character_tools_inv', blank=True,) items_inv = models.ManyToManyField('equipment.Item', related_name='character_items_inv', blank=True,) armor_inv = models.ManyToManyField('equipment.Armor', related_name='character_armor_inv', blank=True,) weapons_inv = models.ManyToManyField('equipment.Weapon', related_name='character_weapons_inv', blank=True,) char_copper = models.IntegerField(blank=True, null=True) char_silver = models.IntegerField(blank=True, null=True) char_gold = models.IntegerField(blank=True, null=True) char_platinum = models.IntegerField(blank=True, null=True) slug = models.SlugField(editable=False, blank=True, null=False) def save(self, *args, **kwargs): if not self.slug: self.slug = slugify(self.char_name) super().save(*args, **kwargs) def get_prof_bonus(self): """ Gets the proficiency bonus for a character based on their character level. :return: int() """ return int(math.ceil(self.get_char_level() / 4) + 1) def get_ability_bonus(self, ability): """ Gets the bonus for a given ability score. :return: int() """ score_conversion = { 'STR': self.STR_score, 'DEX': self.DEX_score, 'CON': self.CON_score, 'INT': self.INT_score, 'WIS': self.WIS_score, 'CHA': self.CHA_score, } return (score_conversion[ability] - 10) // 2 def get_passive_score(self, ability): """ Gets the passive check for a given ability score. :return: int() """ return self.get_ability_bonus(ability) + 10 def get_char_level(self): """ Adds all class levels to get the character level. :return: an int() """ class_levels = self.classlevels.all() level = 0 for class_level in class_levels: level += class_level.class_level return level def get_saving_throw_bonus(self, ability): """ Checks if character is proficient in saving throw and returns amount of bonus either way. :return: int() """ bonus = 0 score_conversion = { 'STR': self.STR_saving_throw, 'DEX': self.DEX_saving_throw, 'CON': self.CON_saving_throw, 'INT': self.INT_saving_throw, 'WIS': self.WIS_saving_throw, 'CHA': self.CHA_saving_throw, } if score_conversion[ability]: bonus += self.get_prof_bonus() bonus += self.get_ability_bonus(ability) else: bonus += self.get_ability_bonus(ability) return bonus def get_initiative_bonus(self): """ Returns the total initiative bonus for a character. :return: int() """ from rules.models import Feature initiative = 0 alert = Feature.objects.get(name__iexact='Alert') if alert in self.features.all(): initiative += 4 + self.get_ability_bonus('DEX') else: initiative += self.get_ability_bonus('DEX') return initiative def get_armor_class(self): """ Returns the total armor class for a character. :return: int() """ armors = self.armor_inv.all() armor_class = 0 if len(armors) > 0: for armor in armors: armor_class += armor.base_armor_class if armor.dexterity_modifier is True and armor.dexterity_modifier_max == -1: armor_class += self.get_ability_bonus('DEX') elif armor.dexterity_modifier == True: if self.get_ability_bonus('DEX') >= 2: armor_class += 2 else: armor_class += self.get_ability_bonus('DEX') else: armor_class += 10 + self.get_ability_bonus('DEX') return armor_class def __str__(self): return self.char_name
class Group(models.Model): class Meta: app_label = 'multiple_m2m_mig' people = GM2MField()
class Action(models.Model): """ An action initiated by an actor and described by a verb. An action may have: - target objects (affected by the action) - related objects (related to the action) """ actor_ct = models.ForeignKey(ContentType, on_delete=models.CASCADE, null=True) actor_pk = models.CharField(max_length=255, null=True) #: The actor, can be anything actor = GenericForeignKey('actor_ct', 'actor_pk') # using hidden relations so that the related objects' model classes are # not cluttered. The reverse relations are available through the # RelatedModel's ``actions`` attribute (as a manager) and its methods #: The target objects, can contain several objects of different types targets = GM2MField(pk_maxlength=PK_MAXLENGTH, related_name='actions_as_target+') #: The related objects, can also contain several objects of different types related = GM2MField(pk_maxlength=PK_MAXLENGTH, related_name='actions_as_related+') #: The action's verb or identifier verb = models.CharField(max_length=255) #: The action's level level = models.PositiveSmallIntegerField(default=DEFAULT_LEVEL) #: Data associated to the action (stored in a JSON field) data = JSONField(default={}) #: The timestamp of the action, from which actions are ordered timestamp = models.DateTimeField(default=now) # default manager objects = DefaultActionManager() class Meta: ordering = ('-timestamp', ) def __init__(self, *args, **kwargs): super(Action, self).__init__(*args, **kwargs) self._unread_in_cache = {} self.handler = ActionHandlerMetaclass.create_handler(self) def _render(self, context=None): """ Renders the action from a template """ return self.handler.render(context) def is_unread_for(self, user): """ Returns True if the action is unread for that user """ if self in user.unread_actions.all(): return True return False def mark_read_for(self, user, force=False): """ Attempts to mark the action as read using the tracker's mark_read method. Returns True if the action was unread before To mark several actions as read, prefer the classmethod bulk_mark_read_for """ return user.unread_actions.mark_read(self, force=force) def render(self, user=None, context=None): """ Renders the action, attempting to mark it as read if user is not None Returns a rendered string """ if not context: context = {} if user: context['user'] = user else: user = context.get('user', None) if user and 'unread' not in context: context['unread'] = self.mark_read_for(user) return self._render(context) @classmethod def bulk_is_unread_for(cls, user, actions): """ Does not bring any performance gains over Action.is_read method, exists for the sake of consistency with bulk_mark_read_for and bulk_render """ unread = [] for a in actions: if a.level >= READABLE_LEVEL: unread.append(a.is_unread_for(user)) return unread @classmethod def bulk_mark_read_for(cls, user, actions, force=False): """ Marks an iterable of actions as read for the given user It is more efficient than calling the mark_read method on each action, especially if many actions belong to only a few followers Returns a list ``l`` of booleans. If ``actions[i]`` was unread before the call to bulk_mark_read_for, ``l[i]`` is True """ unread_actions = user.unread_actions.all() unread = [] to_mark_read = [] for a in actions: is_unread = a in unread_actions unread.append(is_unread) if is_unread: to_mark_read.append(a) user.unread_actions.bulk_mark_read(to_mark_read, force) return unread @classmethod def bulk_render(cls, actions=(), user=None, context=None): """ Renders an iterable actions, returning a list of rendered strings in the same order as ``actions`` If ``user`` is provided, the class method will attempt to mark the actions as read for the user using Action.mark_read above """ if not context: context = {} if user: context['user'] = user else: user = context.get('user', None) unread = context.pop('unread', None) if unread is None and user: unread = cls.bulk_mark_read_for(user, actions) else: # no need to attempt using count(), if actions is a queryset it # needs to be evaluated next anyway unread = [unread] * len(actions) rendered = [] for a, urd in zip(actions, unread): rendered.append(a._render(dict(context, unread=urd))) return rendered