class ISModel(models.Model): related_things = RelatedSetField(ISOther) related_list = RelatedListField(ISOther, related_name="ismodel_list") limted_related = RelatedSetField(RelationWithoutReverse, limit_choices_to={'name': 'banana'}, related_name="+") children = RelatedSetField("self", related_name="+") class Meta: app_label = "djangae"
class ISStringReferenceModel(models.Model): related_things = RelatedSetField('ISOther') related_list = RelatedListField('ISOther', related_name="ismodel_list_string") limted_related = RelatedSetField('RelationWithoutReverse', limit_choices_to={'name': 'banana'}, related_name="+") children = RelatedSetField("self", related_name="+") class Meta: app_label = "djangae"
class User(BaseModel ): # TODO: subclass Django/Djangae user base model, or something """ A public user who is registered on the site. """ constituency = CharField(choices=CONSTITUENCIES.choices) # The MP can be calculated from constituency, but shortcut field for speed and convenience: mp = models.ForeignKey(MP, related_name="constituents") follows_mps = RelatedSetField( MP, help_text= "MPs which this user wants to get/see info/updates/notifications about", blank=True, related_name="followers", ) follows_keywords = SetField( CharField(), help_text= "Keywords which this user wants to know about when an MP says them", blank=True, ) def save(self, *args, **kwargs): # Make the user follow their own MP. # TODO: maybe don't be so forceful! self.follows_mps_ids.add(self.mp_id) return super(User, self).save(*args, **kwargs)
class Video(ThumbnailAbstract): """A video""" subscription = models.ForeignKey(Subscription) user = models.ForeignKey(settings.AUTH_USER_MODEL) viewed = models.BooleanField(default=False) buckets = RelatedSetField(Bucket) # from video endpoint youtube_id = models.CharField(max_length=200) # id published_at = models.DateTimeField() # calculate id based on user ID + video ID so we can get by keys later id = ComputedCharField( lambda self: create_composite_key(str(self.user_id), self.youtube_id), primary_key=True, max_length=200) ordering_key = ComputedCharField(lambda self: create_composite_key( self.published_at.isoformat(" "), self.youtube_id), max_length=200) objects = VideoQuerySet.as_manager() class Meta: ordering = ["ordering_key"] @property def html_snippet(self): tmpl = get_template("subscribae/includes/videos.html") return tmpl.render({"video": self}) def add_titles(self): """Fetches titles and descriptions for Video""" from subscribae.utils import video_add_titles return list(video_add_titles([self]))[0]
class UniqueAction(models.Model): action_type = models.CharField(choices=ACTION_TYPES, max_length=100) model = models.CharField(max_length=100) status = models.CharField(choices=ACTION_STATUSES, default=ACTION_STATUSES[0][0], editable=False, max_length=100) logs = RelatedSetField(ActionLog, editable=False)
class Ticket(TimeStampedModel): title = models.CharField(max_length=200) description = models.TextField(blank=True) project = models.ForeignKey(Project, related_name="tickets") created_by = models.ForeignKey(settings.AUTH_USER_MODEL, null=True, related_name="created_tickets") assignees = RelatedSetField(settings.AUTH_USER_MODEL, related_name="tickets") def __str__(self): return self.title
class Bucket(UniquenessMixin, models.Model): """A "bucket" that a user can put a subscription in A subscription can be in more than one bucket """ subs = RelatedSetField(Subscription) user = models.ForeignKey(settings.AUTH_USER_MODEL) title = models.CharField(max_length=100) last_update = models.DateTimeField() last_viewed = models.DateTimeField(null=True, blank=True) last_watched_video = models.CharField(max_length=200) class Meta: unique_together = ["user", "title"] ordering = ["title"] @property def latest_videos(self): qs = self.video_set.all() if self.last_watched_video: qs = qs.filter(ordering_key__gt=self.last_watched_video) return qs
class Ticket(TimeStampedModel): SHORT_DESCRIPTION_MAX_LENGTH = 200 title = models.CharField(max_length=200) description = models.TextField(blank=True) project = models.ForeignKey(Project, related_name="tickets") created_by = models.ForeignKey(settings.AUTH_USER_MODEL, null=True, related_name="created_tickets") assignees = RelatedSetField(settings.AUTH_USER_MODEL, related_name="tickets") def __str__(self): return self.title @property def short_description(self): """A shorterned version of description.""" trunc = '...' real_max_length = self.SHORT_DESCRIPTION_MAX_LENGTH - len(trunc) if len(self.description) < real_max_length: return self.description return self.description[0:real_max_length] + trunc
class PermissionsMixin(models.Model): """ A mixin class that adds the fields and methods necessary to support Django's Group and Permission model using the ModelBackend. """ is_superuser = models.BooleanField( _('superuser status'), default=False, help_text=_('Designates that this user has all permissions without ' 'explicitly assigning them.')) groups = RelatedSetField( Group, verbose_name=_('groups'), blank=True, help_text=_('The groups this user belongs to. A user will ' 'get all permissions granted to each of ' 'his/her group.')) user_permissions = ListField( models.CharField(max_length=500), verbose_name=_('user permissions'), blank=True, help_text='Specific permissions for this user.') class Meta: abstract = True def __init__(self, *args, **kwargs): """We need to override this to make the choices lazy and prevent import madness""" super(PermissionsMixin, self).__init__(*args, **kwargs) self._meta.get_field('user_permissions')._choices = lazy( get_permission_choices, list)() def get_group_permissions(self, obj=None): """ Returns a list of permission strings that this user has through his/her groups. This method queries all available auth backends. If an object is passed in, only permissions matching this object are returned. """ permissions = set() for backend in auth.get_backends(): if hasattr(backend, "get_group_permissions"): if obj is not None: permissions.update(backend.get_group_permissions( self, obj)) else: permissions.update(backend.get_group_permissions(self)) return permissions def get_all_permissions(self, obj=None): return _user_get_all_permissions(self, obj) def has_perm(self, perm, obj=None): """ Returns True if the user has the specified permission. This method queries all available auth backends, but returns immediately if any backend returns True. Thus, a user who has permission from a single auth backend is assumed to have permission in general. If an object is provided, permissions for this specific object are checked. """ # Active superusers have all permissions. if self.is_active and self.is_superuser: return True # Otherwise we need to check the backends. return _user_has_perm(self, perm, obj) def has_perms(self, perm_list, obj=None): """ Returns True if the user has each of the specified permissions. If object is passed, it checks if the user has all required perms for this object. """ for perm in perm_list: if not self.has_perm(perm, obj): return False return True def has_module_perms(self, app_label): """ Returns True if the user has any permissions in the given app label. Uses pretty much the same logic as has_perm, above. """ # Active superusers have all permissions. if self.is_active and self.is_superuser: return True return _user_has_module_perms(self, app_label)
class MasterTranslation(models.Model): id = models.CharField(max_length=64, primary_key=True) text = models.TextField() text_for_ordering = ComputedCharField(lambda instance: instance.text[:500], max_length=500) plural_text = models.TextField(blank=True) hint = models.CharField(max_length=500, default="", blank=True) language_code = models.CharField( max_length=8, choices=settings.LANGUAGES, default=settings.LANGUAGE_CODE ) translations_by_language_code = JSONField() translations = RelatedSetField(Translation) translated_into_languages = SetField(models.CharField(max_length=8), editable=False) # Was this master translation updated or created by make messages? used_in_code_or_templates = models.BooleanField(default=False, blank=True, editable=False) # Were any groups specified in the trans tags? used_by_groups_in_code_or_templates = SetField(models.CharField(max_length=64), blank=True) # Record the ID of the last scan which updated this instance (if any) last_updated_by_scan_uuid = models.CharField(max_length=64, blank=True, default="") first_letter = models.CharField(max_length=1, editable=False) @property def is_plural(self): return bool(self.plural_text) def __unicode__(self): return u"{} ({}{})".format(self.text, self.language_code, ' plural' if self.is_plural else '') def __repr__(self): """ Define an ASCII string safe representation of the master translation. """ return str("{}".format(self.id)) def get_display(self): from fluent.trans import _get_trans result = _get_trans(self.text, self.hint) return result def text_for_language_code(self, lang_code): new_code = find_closest_supported_language(lang_code) if new_code not in self.translations_by_language_code.keys(): # we don't have a translation for this language return self.text translation_id = self.translations_by_language_code[new_code] translation = Translation.objects.get(id=translation_id) return translation.text @classmethod def find_by_groups(cls, groups): from .fields import find_installed_translatable_fields translatable_fields_by_model = find_installed_translatable_fields(with_groups=groups) # Go through all Translatable(Char|Text)Fields or TextFields marked with the specified group and get # all the master translation IDs which are set to them master_translation_ids = [] for model, fields in translatable_fields_by_model.items(): master_translation_ids.extend(chain(*model.objects.values_list(*[field.attname for field in fields]))) master_translation_ids = list(set(master_translation_ids)) # Now get all the master translations with a group specified in the templates master_translation_ids.extend( list(MasterTranslation.objects.filter(used_by_groups_in_code_or_templates__overlap=groups) .values_list("pk", flat=True)) ) # Make sure master translation ids don't include None values or duplicates master_translation_ids = set(master_translation_ids) master_translation_ids = master_translation_ids - {None} # Return them all! return MasterTranslation.objects.filter(pk__in=master_translation_ids) @classmethod def find_by_group(cls, group_name): return cls.find_by_groups([group_name]) @staticmethod def generate_key(text, hint, language_code): assert text assert hint is not None assert language_code result = md5() for x in (text.encode("utf-8"), hint.encode("utf-8"), language_code): result.update(x) return result.hexdigest() def save(self, *args, **kwargs): assert self.text assert self.language_code # Always store the first letter for querying self.first_letter = self.text.strip()[:1] # Generate the appropriate key on creation if self._state.adding: self.pk = MasterTranslation.generate_key( self.text, self.hint, self.language_code ) # If we are adding for the first time, then create a counterpart # translation for the master language. # Note that this Translation will be complete and correct only for the languages that # only require 2 plural forms - for others this language needs to be explicitly translated # or updated later. if self._state.adding: with transaction.atomic(xg=True): singular_form = get_plural_index(self.language_code, 1) plural_form = get_plural_index(self.language_code, 2) plurals = {singular_form: self.text} if self.is_plural: plurals[plural_form] = self.plural_text # if len(LANGUAGE_LOOKUPS[self.language_code].plurals_needed) > len(plurals): # FIXME: We can detect that we're dealing with a language that needs more plurals # What should we do? mark the translation as incomplete? # Don't create the translation object at all? new_trans = Translation.objects.create( master_translation=self, language_code=self.language_code, plural_texts=plurals, denorm_master_text=self.text, denorm_master_hint=self.hint ) self.translations_by_language_code[self.language_code] = new_trans.pk self.translations.add(new_trans) self.translated_into_languages = set(self.translations_by_language_code.keys()) return super(MasterTranslation, self).save(*args, **kwargs) else: # Otherwise just do a normal save self.translated_into_languages = set(self.translations_by_language_code.keys()) return super(MasterTranslation, self).save(*args, **kwargs) def create_or_update_translation(self, language_code, singular_text=None, plural_texts=None, validate=False): if language_code not in dict(settings.LANGUAGES).keys(): return ["'{}' is not included as a language in your settings file".format(language_code)] with transaction.atomic(xg=True): trans = None if language_code in self.translations_by_language_code: # We already have a translation for this language, update it! try: trans = Translation.objects.get(pk=self.translations_by_language_code[language_code]) created = False except Translation.DoesNotExist: trans = None if not trans: # OK, create the translation object and add it to the respective fields trans = Translation( master_translation_id=self.pk, language_code=language_code, denorm_master_hint=self.hint, denorm_master_text=self.text ) created = True if plural_texts: trans.plural_texts = plural_texts else: trans.text = singular_text if validate: errors = validate_translation_texts(trans, self) if errors: return errors trans.master_translation = self trans.save() if created: self.refresh_from_db() self.translations_by_language_code[language_code] = trans.pk self.translations.add(trans) self.save() class Meta: app_label = "fluent"
class Post(models.Model): content = models.TextField() tags = RelatedSetField('Tag', related_name='posts') ordered_tags = RelatedListField('Tag')
class Post(BaseModel): class Meta: ordering = ("-created", ) subtitle = models.CharField( verbose_name="Subtitle", max_length=100, ) text = RichTextField() image = models.ImageField( upload_to="post_images", validators=[ImageSize(min_w=1900, max_w=1900, min_h=100, max_h=500)], help_text="Must be 1900px X 100-500px", blank=True) created = models.DateTimeField(auto_now_add=True) modified = models.DateTimeField(auto_now=True) tags = RelatedSetField(Tag, related_name="posts", blank=True) @models.permalink def get_absolute_url(self): return ("post", [ self.slug, ]) @models.permalink def get_edit_url(self): return ("post-edit", [ self.slug, ]) @models.permalink def get_delete_url(self): return ("post-delete", [ self.slug, ]) def index_text(self): """ Text indexed for fulltext search """ elems = [ self.title, self.subtitle, self.text, ] tags = [unicode(t.title) for t in self.tags.all()] elems.extend(tags) return unicode(" ".join(elems)) def index_tags(self, sep="\t"): """ Returns a string representing all the post tsgs separated by the sep val. Needed to index the tags as listid in whoosh and have facets """ return unicode(sep.join([t.slug for t in self.tags.all()])) def index(self): """ Returns a dictionary representing the whoosh entry for the current object in the index """ return dict( pk=unicode(self.pk), text=self.index_text(), tags=self.index_tags(), )
class IterableFieldsWithValidatorsModel(models.Model): set_field = SetField(models.CharField(max_length=100), min_length=2, max_length=3, blank=False) list_field = ListField(models.CharField(max_length=100), min_length=2, max_length=3, blank=False) related_set = RelatedSetField(ISOther, min_length=2, max_length=3, blank=False) related_list = RelatedListField(ISOther, related_name="iterable_list", min_length=2, max_length=3, blank=False)
class PFAuthor(models.Model): name = models.CharField(max_length=32) awards = RelatedSetField('PFAwards') class Meta: app_label = "djangae"
class PFPost(models.Model): content = models.TextField() authors = RelatedSetField('PFAuthor', related_name='posts') class Meta: app_label = "djangae"