def post_through_setup(self, cls): self.use_gfk = self.through is None or issubclass(self.through, GenericTaggedItemBase) self.rel.to = self.through._meta.get_field("tag").rel.to self.related = RelatedObject(self.through, cls, self) if self.use_gfk: tagged_items = GenericRelation(self.through) tagged_items.contribute_to_class(cls, "tagged_items")
def post_through_setup(self, cls): self.use_gfk = ( self.through is None or issubclass(self.through, GenericTaggedItemBase) ) self.rel.to = self.through._meta.get_field("tag").rel.to if self.use_gfk: tagged_items = GenericRelation(self.through) tagged_items.contribute_to_class(cls, "%s_tagged_items" % cls.__name__.lower())
def post_through_setup(self, cls): self.use_gfk = ( self.through is None or issubclass(self.through, GenericChoiceBase) ) self.rel.to = self.through._meta.get_field("poll").rel.to if self.use_gfk: poll_choices = GenericRelation(self.through) poll_choices.contribute_to_class(cls, "poll_choices")
def contribute_to_class(self, cls, name): self.name = self.column = name self.model = cls cls._meta.add_field(self) setattr(cls, name, self) if self.use_gfk: tagged_items = GenericRelation(self.through) tagged_items.contribute_to_class(cls, "tagged_items")
def post_through_setup(self, cls): self.use_gfk = ( self.through is None ) self.rel.to = self.through._meta.get_field("group").rel.to if RelatedObject is not None: self.related = RelatedObject(self.through, cls, self) if self.use_gfk: groups = GenericRelation(self.through) groups.contribute_to_class(cls, "groups")
def post_through_setup(self, cls): self.related = RelatedObject(cls, self.model, self) self.use_gfk = ( self.through is None or issubclass(self.through, GenericTaggedItemBase) ) self.rel.to = self.through._meta.get_field("tag").rel.to self.related = RelatedObject(self.through, cls, self) if self.use_gfk: self.__class__._related_name_counter += 1 related_name = '+%d' % self.__class__._related_name_counter tagged_items = GenericRelation(self.through, related_name=related_name) tagged_items.contribute_to_class(cls, 'tagged_items')
def post_through_setup(self, cls): self.related = RelatedObject(cls, self.model, self) self.use_gfk = ( self.through is None or issubclass(self.through, GenericTaggedItemBase) ) self.rel.to = self.through._meta.get_field("tag").rel.to self.related = RelatedObject(self.through, cls, self) if self.use_gfk: tagged_items = GenericRelation(self.through) tagged_items.contribute_to_class(cls, 'tagged_items') for rel in cls._meta.local_many_to_many: if isinstance(rel, TaggableManager) and rel.use_gfk and rel != self: raise ValueError('You can only have one TaggableManager per model' ' using generic relations.')
def post_through_setup(self, cls): self.related = RelatedObject(cls, self.model, self) self.use_gfk = ( self.through is None or issubclass(self.through, GenericTaggedItemBase) ) self.rel.to = self.through._meta.get_field("tag").rel.to self.related = RelatedObject(self.through, cls, self) if self.use_gfk: tagged_items = GenericRelation(self.through) tagged_items.contribute_to_class(cls, 'tagged_items') for rel in cls._meta.local_many_to_many: if rel == self or not isinstance(rel, TaggableManager): continue if rel.through == self.through: raise ValueError('You can\'t have two TaggableManagers with the' ' same through model.')
class Event(Generic): class Meta: verbose_name = _("Event") verbose_name_plural = _("Events") STATUS_CHOICES = ( (0, _('Pending')), (1, _('Admitted')), (2, _('Refused')), (3, _('Deleted')), ) status = models.SmallIntegerField(_('Status'), choices=STATUS_CHOICES, null=True, default=0) not_regional_event = models.BooleanField(_('Do not publish in the regional event directory'), default=False) title = models.CharField(_('Title'), max_length=455, blank=False, help_text=_("Enter the full name of the event, as it appears and in the same language. Ex: XIX Congresso Brasileiro de Arritmias Cardiacas. XVII Simposio Nacional do DECS-SBCC")) start_date = models.DateField(_('Start date'), help_text='DD/MM/YYYY') end_date = models.DateField(_('End date'), help_text='DD/MM/YYYY') link = models.URLField(_('Link'), max_length=255, help_text=_("Enter the link of event portal"), blank=True) address = models.CharField(_('Address'), max_length=255, blank=True, help_text=_("Enter full address of the local of the event to present it in a Google map")) city = models.CharField(_('City'), max_length=125, blank=True) country = models.ForeignKey(Country, verbose_name=_('Country'), blank=True, null=True) event_type = models.ManyToManyField(EventType, verbose_name=_("Event type"), blank=False) official_language = models.ManyToManyField('main.SourceLanguage', verbose_name=_("Official languages"), blank=True) contact_email = models.EmailField(_('Contact email'), blank=True) contact_info = models.TextField(_("Information for contact"), blank=True) observations = models.TextField(_("Observations"), help_text=_("Enter information about institutions that organize and/or sponsor the event, deadline for submission of papers, simultaneous translation service, event program, etc."), blank=True) target_groups = models.TextField(_("Target groups"), blank=True) # responsible cooperative center cooperative_center_code = models.CharField(_('Cooperative center'), max_length=55, blank=True) # relations error_reports = GenericRelation(ErrorReport) thematics = GenericRelation(ResourceThematic) def __unicode__(self): return self.title
class TaggedModel(models.Model): tags = GenericRelation(Tag) @denormalized(models.TextField) @depend_on_related(Tag) def tags_string(self): return ', '.join(sorted([t.name for t in self.tags.all()])) class Meta: abstract = True
class Deck(models.Model): #information title = models.CharField(max_length=128) creator = models.ForeignKey(User) tags = models.ManyToManyField(Tag, blank=True, null=True) text = models.TextField(blank=True, null=True) #record date_posted = models.DateField(auto_now_add=True) challenge = models.ForeignKey(Challenge, null=True, blank=True, on_delete=models.SET_NULL) #just one is_public = models.BooleanField(blank=True, default=True) is_removed = models.BooleanField(blank=True, default=False) #data deck_image = models.ImageField(upload_to="img/%Y/%m/%d") comments = GenericRelation(Comment, object_id_field="object_pk") polls = GenericRelation(BinaryPoll, object_id_field="object_id") deck_length_coefficient = models.SmallIntegerField() deck_width_coefficient = models.SmallIntegerField() #managers objects = models.Manager() public = PublicSetManager() class Meta(): get_latest_by = 'date_posted' #methods def clean(self): #needs to check that any attached challenges are not expired if self.is_public == True and self.is_removed == True: raise ValidationError('Removed entries cannot also be public.') super(Deck, self).clean() def __unicode__(self): return self.title def get_absolute_url(self): return reverse('deck:view', kwargs={'pk': str(self.pk)})
class LegislatorDetail(models.Model): objects = LegislatorDetailManager() legislator = models.OneToOneField(Politician) on_bill = models.CharField(max_length=1, choices=ON_BILL_CHOICES, default='U') on_amendment = models.NullBooleanField(default=None) call_goal = models.SmallIntegerField(default=10) calls = GenericRelation(AnswerSet) def __unicode__(self): return u' '.join([ self.legislator.get_title_display(), self.good_fname(), self.legislator.lastname ]) def good_fname(self): return self.legislator.nickname or self.legislator.firstname def is_cosponsor(self): return self.on_bill == 'C' def supports_bill(self): if self.on_bill in ('C', 'S'): return True elif self.on_bill == 'O': return False else: return None def he_or_she(self): if self.legislator.gender == 'F': return 'she' else: return 'he' def his_or_her(self): if self.legislator.gender == 'F': return 'her' else: return 'his' def him_or_her(self): if self.legislator.gender == 'F': return 'her' else: return 'him' def needs_more_calls(self): return self.calls.count() < self.call_goal
class ItemInstance(ActionInstance): """ An instance of a single item """ owner = models.ForeignKey(Player, on_delete=models.CASCADE) itype = models.ForeignKey(Item, on_delete=models.CASCADE) attributes = GenericRelation(Attribute) def transfer(self, newowner): self.owner = newowner self.save() return "You have successfully transfered the item " + self.itype.name
class PurchaseItem(models.Model): invoice = models.ForeignKey(PurchaseInvoice, verbose_name=_(u'Purchase invoice')) material = models.ForeignKey(Material, verbose_name=_(u'Material')) material_cluster = models.OneToOneField( MaterialCluster, verbose_name=_(u'Created material cluster')) movement = GenericRelation('MaterialMovement') quantity = models.PositiveIntegerField(_(u'Quantity')) unit_cost = models.DecimalField(_(u'Unit cost'), max_digits=20, decimal_places=2) @property def total_cost(self): return self.unit_cost * self.quantity class Meta: verbose_name = _(u'Purchase item') verbose_name_plural = _(u'Purchase items') def __unicode__(self): return _( u"%(quantity)s %(measure_unit)s of %(material)s (invoice nr. %(number)s-%(serie)s:)" ) % { 'quantity': self.quantity, 'measure_unit': self.material.measure_unit, 'material': self.material.description, 'number': self.invoice.number, 'serie': self.invoice.serie } def save(self, *args, **kwargs): if self.pk is None: # Create a new MaterialCluster mc = MaterialCluster.objects.create( material=self.material, quantity=self.quantity, unit_cost=self.unit_cost, creation_date=self.invoice.input_date, last_change=self.invoice.input_date) # Links the MaterialCluster with this PurchaseItem self.material_cluster = mc # Call the super.save() method super(PurchaseItem, self).save(*args, **kwargs) # Create a new MaterialMovement mm = MaterialMovement.objects.create( material_cluster=mc, type='E', qty_before_mov=0, quantity=self.quantity, mov_date=self.invoice.input_date, unit_cost=self.unit_cost, origin=self)
class AbstractGeneric(models.Model): name = models.CharField(max_length=255) description = models.TextField() staff = GenericRelation( "Staff", content_type_field="content_type", object_id_field="object_id", ) class Meta: abstract = True
class Company(models.Model): """Company model.""" name = models.CharField(_('name'), max_length=200) nickname = models.CharField(_('nickname'), max_length=50, blank=True, null=True) slug = models.SlugField(_('slug'), max_length=50, unique=True) about = models.TextField(_('about'), blank=True, null=True) logo = models.ImageField(_('photo'), upload_to='contacts/companies/', blank=True) phone_number = GenericRelation('PhoneNumber') email_address = GenericRelation('EmailAddress') instant_messenger = GenericRelation('InstantMessenger') web_site = GenericRelation('WebSite') street_address = GenericRelation('StreetAddress') special_date = GenericRelation('SpecialDate') note = GenericRelation(Comment, object_id_field='object_pk') date_added = models.DateTimeField(_('date added'), auto_now_add=True) date_modified = models.DateTimeField(_('date modified'), auto_now=True) class Meta: db_table = 'contacts_companies' ordering = ('name', ) verbose_name = _('company') verbose_name_plural = _('companies') def __unicode__(self): return u"%s" % self.name @permalink def get_absolute_url(self): return ('contacts_company_detail', None, { 'pk': self.pk, 'slug': self.slug, }) @permalink def get_update_url(self): return ('contacts_company_update', None, { 'pk': self.pk, 'slug': self.slug, }) @permalink def get_delete_url(self): return ('contacts_company_delete', None, { 'pk': self.pk, 'slug': self.slug, })
class InstalledMeasure(models.Model): measure = models.ForeignKey(Measure) cost = models.IntegerField(null=True, blank=True) disruption = models.IntegerField(null=True, blank=True) house = models.ForeignKey(House, null=True, blank=True, related_name='measures') report_text = models.TextField(null=True, blank=True) supplier = models.CharField(max_length=1024, null=True, blank=True) supplier_urls = GenericRelation(RelatedTrackableURL, null=True, blank=True, related_name='supplier_urls') product = models.CharField(max_length=1024, null=True, blank=True) product_urls = GenericRelation(RelatedTrackableURL, null=True, blank=True, related_name='product_urls') def __unicode__(self): return u'%s' % (self.measure.short, )
class Game(models.Model): """ Defines a game within the website """ name = models.CharField(max_length=200, default="Game", unique=True) items = models.ManyToManyField(Item, blank=True) abilities = models.ManyToManyField(Ability, blank=True) rules = models.CharField(max_length=2047, blank=True) attributes = GenericRelation('Attribute') active = models.BooleanField(default=False) def __str__(self): return self.name
class ChildModel(ParentModel): child_name = models.CharField(max_length=255) file = models.FileField(upload_to="test", blank=True) genericrelatedmodel_set = GenericRelation("test_app.GenericRelatedModel") def __str__(self): return "%s > %s" % (self.parent_name, self.child_name) class Meta: verbose_name = _("child model") verbose_name_plural = _("child models")
class TracTicketMetric(models.Model): name = models.CharField(max_length=300) slug = models.SlugField() query = models.TextField() data = GenericRelation('Datum') def __unicode__(self): return self.name def fetch(self): s = xmlrpclib.ServerProxy(settings.TRAC_RPC_URL) return len(s.ticket.query(self.query + "&max=0")) def link(self): return "%squery?%s" % (settings.TRAC_URL, self.query)
class Post(models.Model): title = models.CharField(max_length=150) text = models.TextField() author = models.ForeignKey(User) post_image = models.ImageField(blank=True, upload_to="postimages") created_on = models.DateTimeField(auto_now_add=True) # to get sub comments from the parent comments = GenericRelation('Comment') def __unicode__(self): return u"%s" % self.id #to order comments by date reverse class Meta: ordering = ['-created_on']
class FileStorageMixin(models.Model): file_set = GenericRelation(RelativeFileStorage) class Meta: abstract = True def get_documents(self): return self.file_set \ .exclude(document__extension__in=ImageThumbnailMixin.IMAGE_EXTENSIONS) \ .filter(languages__contains=translation.get_language()) def get_images(self): return self.file_set \ .filter(document__extension__in=ImageThumbnailMixin.IMAGE_EXTENSIONS) \ .filter(languages__contains=translation.get_language())
class NewProject(CodelistsModel): title = models.CharField(max_length=500, blank=True) number = models.CharField(verbose_name=_('N. ID DGCS'), blank=True, max_length=100) description = models.TextField(verbose_name=_('Abstract'), blank=True) year = models.PositiveSmallIntegerField(null=True, blank=True) commitment = models.FloatField(help_text=_('Migliaia di euro'), blank=True, null=True) disbursement = models.FloatField(help_text=_('Migliaia di euro'), blank=True, null=True) photo_set = GenericRelation('attachments.Photo') def get_absolute_url(self): return reverse('projects:newproject-detail', kwargs={'pk': self.pk})
class Event (OrderedModelMixin, ModelWithSlugMixin, CloneableModelMixin, models.Model): label = models.TextField(help_text=_("The time label for the event, e.g. \"January 15th, 2015\", \"Spring 2015 Phase\", \"Phase II, Summer 2015\", etc.")) slug = models.CharField(max_length=64, blank=True) description = models.TextField(help_text=_("A summary description of the timeline item"), default='', blank=True) index = models.PositiveIntegerField(help_text=_("Leave this field blank; it will be filled in automatically")) project = models.ForeignKey(Project, related_name='events') details = JSONField(blank=True, default=dict) datetime_label = models.TextField(blank=True, help_text=_("A description of this event's date and time, preferably in a parsable format.")) start_datetime = models.DateTimeField(null=True, blank=True) end_datetime = models.DateTimeField(null=True, blank=True) attachments = GenericRelation('Attachment', object_id_field='attached_to_id', content_type_field='attached_to_type') objects = EventManager() class Meta: ordering = ('project', 'index',) unique_together = [('project', 'slug')] def __str__(self): if self.index is not None: return '%s. %s' % (self.index + 1, self.label) else: return self.label def natural_key(self): return self.project.natural_key() + (self.index,) def get_slug_basis(self): return self.label def get_all_slugs(self): return [e.slug for e in self.project.events.all()] def slug_exists(self, slug): return self.project.events.filter(slug__iexact=slug).exists() def get_siblings(self): return self.project.events.all() def clone_related(self, onto): kwargs = dict(attached_to=onto) for a in self.attachments.all(): a.clone(overrides=kwargs)
class Discussion(models.Model): """ A new topic of discussion. """ title = models.CharField(max_length=255, default='Untitled Discussion') tags = models.CharField(max_length=255, blank=True) description = models.TextField(blank=True) created = models.DateTimeField(auto_now_add=True) hacker = models.ForeignKey('Hacker', related_name='discussions') comments = GenericRelation('Comment') class Meta: ordering = ['-created'] def __unicode__(self): return self.title
class TabBlock(ContentBlock): name = _("Tabbed block") code = 'tabbed-block' group = _("Layout") context_object_name = "block" template_name = "fancypages/blocks/tabbedblockblock.html" tabs = GenericRelation('fancypages.OrderedContainer') def save(self, *args, **kwargs): super(TabBlock, self).save(*args, **kwargs) if not self.tabs.count(): OrderedContainer.objects.create(page_object=self, display_order=0, title=_("New Tab")) class Meta: app_label = 'fancypages'
class Page(Resource): show_title = models.BooleanField(default=True) meta_summary = models.TextField(blank=True) text = RichTextField(blank=True) template = models.CharField(max_length=100, blank=True, choices=template_choices(), default=template_default(), help_text=_("Inherit if empty")) related_links = GenericRelation(RelatedLink) class Meta: verbose_name = _(u'Page') verbose_name_plural = _(u'Page') def get_template(self): if self.template == "": try: return self.parent.get_object().get_template() except AttributeError: # no parent return template_default() or template_choices()[0][0] return self.template def get_response(self, request): return render(request, self.get_template(), {'page': self}) def resolve(self): return self.get_absolute_url() def subpages(self): return render_to_string("resources/subpages.html", { 'page': self, 'start': 2 }) def subnav(self): return render_to_string("resources/subnav.html", { 'page': self, 'start': 2 }) def get_related_links(self): return self.related_links.all().select_subclasses()
class Comment(models.Model): text = models.TextField() author = models.ForeignKey(User) entity = models.ForeignKey(Post) created_on = models.DateTimeField(auto_now_add=True) # GenericForeignKey Usage content_type = models.ForeignKey(ContentType) object_id = models.PositiveIntegerField() content_object = generic.GenericForeignKey('content_type', 'object_id') # to get sub comments from the parent comments = GenericRelation('Comment') is_verified = models.BooleanField(default=False) email = models.EmailField() def __unicode__(self): return u"%s" % self.id #to order comments by date reverse class Meta: ordering = ['created_on']
class Votable(models.Model): votes = GenericRelation(Vote) class Meta: abstract = True def vote_count(self): aggregate = self.votes.aggregate(Sum('value')) if aggregate['value__sum'] == None: return 0 else: return aggregate['value__sum'] def set_vote(self, user, value): if (user.is_authenticated): v = self.votes.filter(user=user) if v.count() == 0: new_vote = self.votes.create(user=user, value=value) new_vote.save() else: v.update(value=value)
class Proposal(models.Model): """ A proposal for idea / hack / talk. """ # TODO: Add voting. TYPES = ( ('HACK', 'Hack'), ('TALK', 'Talk'), ) title = models.CharField(max_length=255) slug = models.SlugField(blank=True, unique=True, max_length=150) type = models.CharField(max_length=4, choices=TYPES) tags = models.CharField(max_length=255, blank=True) description = models.TextField(blank=True) completed = models.BooleanField(default=False) url = models.CharField(max_length=128, blank=True) repo_url = models.CharField(max_length=128, blank=True) upvotes = models.ManyToManyField(Hacker, related_name='upvoters', blank=True) comments = GenericRelation('Comment') proposer = models.ForeignKey(Hacker, related_name='proposals') created = models.DateTimeField(auto_now_add=True) modified = models.DateTimeField(auto_now=True) class Meta: ordering = ['-created'] def __unicode__(self): return self.title def save(self, *args, **kwargs): super(Proposal, self).save(*args, **kwargs) self.slug = '%i-%s' % (self.id, slugify(self.title[:150])) super(Proposal, self).save(*args, **kwargs)
class MyBaseModel (models.Model): # fields hash = models.CharField ( max_length = 256, # we don't expect using a hash more than 256-bit long! null = True, blank = True, default = '', verbose_name = u'MD5 hash' ) # basic value fields name = models.CharField( default = None, max_length = 128, verbose_name = u'名称' ) description = models.TextField ( null=True, blank=True, verbose_name = u'描述' ) # help text help_text = models.CharField ( max_length = 64, null = True, blank = True, verbose_name = u'帮助提示' ) # attachments attachments = GenericRelation('Attachment') # this is an Abstract model class Meta: abstract=True def __unicode__(self): return self.name
class Organisation(models.Model): class Meta: verbose_name = _('organisation') verbose_name_plural = _('organisations') name = models.CharField(_('name'), max_length=200,) strategy = models.TextField(_('strategy'), blank=True) middlemen = models.ManyToManyField('Member', related_name="middleman_organisations", blank=True,null=True, verbose_name=_("middle men")) representatives = models.CharField(_('Representative'), max_length=30, blank=True) found_via = models.CharField(_('Found via'), max_length=30, blank=True) contact = models.TextField(_('contact info'), blank=True) comment = models.TextField(_('comment'), blank=True) working_with = models.TextField(_('Also working with'), blank=True) types = models.ManyToManyField('OrganisationType', related_name="organisations", blank=True, verbose_name=_("Type of organisation")) updates = GenericRelation(Update, verbose_name=_("Updates"), blank=True) partnered_project = models.ForeignKey('Project', related_name="partners", blank=True, null=True, verbose_name=_("partnered project")) provided_help = models.TextField(_('Provided help'), blank=True) def __unicode__(self): return self.name
class AbstractRegistry(models.Model): asset = models.ForeignKey(Asset, verbose_name=_(u"Asset")) registry_date = models.DateTimeField(_(u"Registry date"), auto_now_add=True, editable=False) annotation = models.TextField(_(u"Additional annotation")) related_movement = GenericRelation('AssetMovement') class Meta: abstract = True ordering = ('asset', '-registry_date',) def pre_save(self, asset): """ Hook for doing any pre save model changes has been called before any data saves """ pass def post_save(self, asset): """ Hook for doing any post save model actions has been called afetr model saves and before AssetMovement creation """ pass @commit_on_success def save(self, *args, **kwargs): asset = self.asset self.pre_save(asset) super(AbstractRegistry, self).save(*args, **kwargs) self.post_save(asset) if not self.related_movement.exists(): mov = AssetMovement(asset=asset, mov_date=self.registry_date, origin=self) else: mov = self.related_movement.get() mov.asset = asset mov.mov_date = self.registry_date mov.save()
class Resource(Generic, AuditLog): class Meta: verbose_name = _("Resource") verbose_name_plural = _("Resources") STATUS_CHOICES = ( (0, _('Pending')), (1, _('Admitted')), (2, _('Refused')), (3, _('Deleted')), ) # status (399) status = models.SmallIntegerField(_('Status'), choices=STATUS_CHOICES, null=True, default=0) # title (311) title = models.CharField( _('Title'), max_length=510, blank=False, help_text= _("Transcribe as it appears on the internet resource. If there is no title, provide a brief, simple but explanatory title" )) # link (351) link = models.TextField(_('Link'), blank=False) # originator (313) originator = models.TextField( _('Originator'), blank=False, help_text= _("Institutional or personnel name of the responsible for the existence of the internet resource. Ex. Brazilian Society for Dental Research" )) # originator_location (314) originator_location = models.ManyToManyField( Country, verbose_name=_('Originator location'), blank=False) # author (315) author = models.TextField( _('Authors'), blank=True, help_text= _("Enter one per line. Only filled if different from the originator of the resource" )) # language of resource (317) source_language = models.ManyToManyField(SourceLanguage, verbose_name=_("Source language"), blank=False) # source type (318) source_type = models.ManyToManyField(SourceType, verbose_name=_("Source type"), blank=False) # abstract (319) abstract = models.TextField( _("Abstract"), blank=False, help_text= _("Include information on the content and operation of the internet resource" )) # time period (341) time_period_textual = models.CharField(_('Temporal range'), max_length=255, blank=True) # objective (361) objective = models.TextField(_('Objective'), blank=True) # responsible cooperative center cooperative_center_code = models.CharField(_('Cooperative center'), max_length=55, blank=True) # relations error_reports = GenericRelation(ErrorReport) thematics = GenericRelation(ResourceThematic) descriptors = GenericRelation(Descriptor) def get_fields(self): return [(field.verbose_name, field.value_to_string(self)) for field in Resource._meta.fields] def __unicode__(self): return unicode(self.title)
class TaggableBase(db.Model): """Provides the `tags` generic relation to prettify the API.""" tags = GenericRelation("Tag") def tag(self, name, language, author): """Tags this object using a `name` in a specific `language`. The tag will be marked as authored by `author`. The `name` can be a list of comma-separated tags. Double quotes can be used to escape values with spaces or commas. One special case: if there are no commas in the input, spaces are treated as tag delimiters.""" author = _tag_get_user(author) language = _tag_get_language(language) tags = parse_tag_input(name) for tag_name in tags: tag = Tag(name=tag_name, language=language, author=author, content_object=self) tag.save() def untag(self, name, language, author): """Untags this object from tags in a specific `language`, authored by `author`. The `name` can be a list of comma-separated tags. Double quotes can be used to escape values with spaces or commas. One special case: if there are no commas in the input, spaces are treated as tag delimiters.""" author = _tag_get_user(author) language = _tag_get_language(language) ct = ContentType.objects.get_for_model(self.__class__) tags = parse_tag_input(name) for tag_name in tags: try: tag = Tag.objects.get(name=tag_name, language=language, author=author, content_type=ct, object_id=self.id) tag.delete() except Tag.DoesNotExist: pass # okay, successfully "untagged". def untag_all(self, name=None, language=None, author=None): """untag_all([name], [language], [author]) Untags this object from all tags in a specific `language` or authored by `author`.""" author = _tag_get_user(author, default=None) language = _tag_get_language(language, default=None) ct = ContentType.objects.get_for_model(self.__class__) kwargs = dict(content_type=ct, object_id=self.id) if name is not None: kwargs['name__in'] = parse_tag_input(name) if language is not None: kwargs['language'] = language if author is not None: kwargs['author'] = author tags = Tag.objects.filter(**kwargs) tags.delete() def similar_objects(self, same_type=False, official=False): """similar_objects([same_type, official]) -> [(obj, distance), (obj, distance), ...] Returns a sorted list of similar objects in tuples (the object itself, the distance to the `self` object). If there are no similar objects, the list returned is empty. Searching for similar objects can be constrained to the objects of the same type (if `same_type` is True). Objects are similar when they share the same tags. Distance is the number of tags that are not shared by the two objects (specifically, the object has distance 0 to itself). Distance calculation by default uses all tags present on the object. If `official` is True, only the official tags are taken into account. """ kwargs = {"official": official} if same_type: kwargs['model'] = self.__class__ stems = TagStem.objects.get_dictionary(**kwargs) distance = [] if self in stems: self_stems = stems[self] del stems[self] else: # may happen if this object is not available through Model.objects, # e.g. the model has a custom manager which filters it out self_stems = set((i[0] for i in TagStem.objects.get_queryset_for_model(self.__class__, self).values_list('name'))) for obj, s in stems.iteritems(): if not s & self_stems: # things without a single common tag are not similar at all continue distance.append((obj, len(s ^ self_stems))) distance.sort(key=lambda elem: elem[1]) return distance def get_tags(self, official=True, author=None, language=None): """get_tags([official, author, language]) -> [TagStem, TagStem, ...] A convenience getter for tags on the current taggable. By default gets the `official` tags by no specific `author` and in any `language`.""" return TagStem.objects.get_queryset_for_model(self.__class__, self, official=official, author=author, language=language).extra( select={'lname': 'lower(tags_tagstem.name)'}).order_by('lname') class Meta: abstract = True
class Trip(AdminURLMixin, models.Model): PLANNED = u'planned' APPROVED = u'approved' COMPLETED = u'completed' CANCELLED = u'cancelled' TRIP_STATUS = ( (PLANNED, u"Planned"), (APPROVED, u"Approved"), (COMPLETED, u"Completed"), (CANCELLED, u"Cancelled"), ) DUTY_TRAVEL = u'duty_travel' HOME_LEAVE = u'home_leave' FAMILY_VISIT = u'family_visit' EDUCATION_GRANT = u'education_grant' STAFF_DEVELOPMENT = u'staff_development' TRAVEL_TYPE = ( (DUTY_TRAVEL, u"DUTY TRAVEL"), (HOME_LEAVE, u"HOME LEAVE"), (FAMILY_VISIT, u"FAMILY VISIT"), (EDUCATION_GRANT, u"EDUCATION GRANT"), (STAFF_DEVELOPMENT, u"STAFF DEVELOPMENT"), ) status = models.CharField( max_length=32L, choices=TRIP_STATUS, default=PLANNED, ) purpose_of_travel = models.CharField(max_length=254) travel_type = models.CharField(max_length=32L, choices=TRAVEL_TYPE, default=DUTY_TRAVEL) international_travel = models.BooleanField( default=False, help_text= 'International travel will require approval from the representative') from_date = models.DateField() to_date = models.DateField() monitoring_supply_delivery = models.BooleanField(default=False) activities_undertaken = models.CharField(max_length=254, verbose_name='Activities') no_pca = models.BooleanField( default=False, verbose_name=u'Not related to a PCA', help_text='Tick this if this trip is not related to partner monitoring' ) pcas = models.ManyToManyField(u'partners.PCA', blank=True, null=True, verbose_name=u"Related PCAs") partners = models.ManyToManyField(u'partners.PartnerOrganization', blank=True, null=True) main_observations = models.TextField(blank=True, null=True) ta_required = models.BooleanField( default=False, help_text='Is a Travel Authorisation (TA) is required?') programme_assistant = models.ForeignKey( User, blank=True, null=True, verbose_name='Assistant Responsible for TA', help_text='Needed if a Travel Authorisation (TA) is required', related_name='managed_trips') wbs = models.ForeignKey( WBS, blank=True, null=True, help_text='Needed if trip is over 10 hours and requires overnight stay' ) grant = models.ForeignKey(Grant, blank=True, null=True) ta_approved = models.BooleanField( default=False, help_text='Has the TA been approved in vision?') ta_approved_date = models.DateField(blank=True, null=True) ta_reference = models.CharField(max_length=254, blank=True, null=True) locations = GenericRelation(LinkedLocation) owner = models.ForeignKey(User, verbose_name='Traveller') section = models.ForeignKey('reports.Sector', blank=True, null=True) travel_assistant = models.ForeignKey(User, blank=True, null=True, related_name='organised_trips') transport_booked = models.BooleanField(default=False) security_clearance = models.BooleanField(default=False) supervisor = models.ForeignKey(User, related_name='supervised_trips') approved_by_supervisor = models.BooleanField(default=False) budget_owner = models.ForeignKey(User, related_name='budgeted_trips') approved_by_budget_owner = models.BooleanField(default=False) approved_by_human_resources = models.BooleanField(default=False) representative_approval = models.BooleanField(default=False) approved_date = models.DateField(blank=True, null=True) created_date = models.DateTimeField(auto_now_add=True) class Meta: ordering = ['-from_date', '-to_date'] def __unicode__(self): return u'{} - {}: {}'.format(self.from_date, self.to_date, self.purpose_of_travel) def reference(self): return '{}/{}'.format(self.created_date.year, self.id) if self.id else None reference.short_description = 'Reference' def outstanding_actions(self): return self.actionpoint_set.filter(completed_date__isnull=True).count() @property def requires_hr_approval(self): return self.travel_type in [ Trip.HOME_LEAVE, Trip.FAMILY_VISIT, Trip.EDUCATION_GRANT, Trip.STAFF_DEVELOPMENT ] @property def requires_rep_approval(self): return self.international_travel @property def can_be_approved(self): if not self.approved_by_supervisor\ or not self.approved_by_budget_owner: return False if self.requires_hr_approval\ and not self.approved_by_human_resources: return False if self.requires_rep_approval\ and not self.representative_approval: return False return True @classmethod def get_email_template_or_default(cls, name, instance): try: template = EmailTemplate.objects.get(name=name) except EmailTemplate.DoesNotExist: template = EmailTemplate(subject='Trip {}: {}'.format( instance.status, instance.reference)) return template @classmethod def send_trip_request(cls, sender, instance, created, **kwargs): current_site = Site.objects.get_current() if created: email_name = 'trips/trip/created' try: template = EmailTemplate.objects.get(name=email_name) except EmailTemplate.DoesNotExist: template = EmailTemplate.objects.create( name=email_name, description= 'The email that is send to the supervisor once a new trip has been created', subject="New Trip Created for {{owner_name}}", content="Dear {{supervisor_name}}," "\r\n\r\nA new trip has been created by {{owner_name}} and awaits your approval here:" "\r\n\r\n{{url}}" "\r\n\r\nThank you.") send_mail( instance.owner.email, template, { 'owner_name': instance.owner.get_full_name(), 'supervisor_name': instance.supervisor.get_full_name(), 'url': 'http://{}{}'.format(current_site.domain, instance.get_admin_url()) }, instance.supervisor.email) if instance.status == Trip.APPROVED: email_name = 'trips/trip/approved' try: template = EmailTemplate.objects.get(name=email_name) except EmailTemplate.DoesNotExist: template = EmailTemplate.objects.create( name=email_name, description= 'The email that is sent to the traveller if a trip has been approved', subject="Trip Approved: {{trip_reference}}", content= "The following trip has been approved: {{trip_reference}}" "\r\n\r\n{{url}}" "\r\n\r\nThank you.") send_mail( instance.owner.email, template, { 'trip_reference': instance.trip.reference(), 'url': 'http://{}{}'.format(current_site.domain, instance.get_admin_url()) }, instance.owner.email, ) if instance.status == Trip.CANCELLED: email_name = 'trips/trip/cancelled' try: template = EmailTemplate.objects.get(name=email_name) except EmailTemplate.DoesNotExist: template = EmailTemplate.objects.create( name=email_name, description= 'The email that is sent to everyone if a trip has been cancelled', subject="Trip Cancelled: {{trip_reference}}", content= "The following trip has been cancelled: {{trip_reference}}" "\r\n\r\n{{url}}" "\r\n\r\nThank you.") send_mail( instance.owner.email, template, { 'trip_reference': instance.trip.reference(), 'url': 'http://{}{}'.format(current_site.domain, instance.get_admin_url()) }, instance.owner.email, instance.supervisor.email, instance.budget_owner.email, instance.travel_assistant.email, ) if instance.approved_by_supervisor: if instance.travel_assistant and not instance.transport_booked: email_name = "travel/trip/travel_or_admin_assistant" try: template = EmailTemplate.objects.get(name=email_name) except EmailTemplate.DoesNotExist: template = EmailTemplate.objects.create( name=email_name, description= "This e-mail will be sent when the trip is approved by the supervisor. " "It will go to the travel assistant to prompt them to organise the travel " "(vehicles, flights etc.) and request security clearance.", subject="Travel for {{owner_name}}", content="Dear {{travel_assistant}}," "\r\n\r\nPlease organise the travel and security clearance (if needed) for the following trip:" "\r\n\r\n{{url}}" "\r\n\r\nThanks," "\r\n{{owner_name}}") send_mail( instance.owner.email, template, { 'owner_name': instance.owner.get_full_name(), 'travel_assistant': instance.travel_assistant.get_full_name(), 'url': 'http://{}{}'.format(current_site.domain, instance.get_admin_url()) }, instance.travel_assistant.email, ) if instance.ta_required and instance.programme_assistant and not instance.ta_approved: email_name = 'trips/trip/TA_request' try: template = EmailTemplate.objects.get(name=email_name) except EmailTemplate.DoesNotExist: template = EmailTemplate.objects.create( name=email_name, description= "This email is sent to the relevant programme assistant to create " "the TA for the staff in concern after the approval of the supervisor.", subject= "Travel Authorization request for {{owner_name}}", content="Dear {{pa_assistant}}," "\r\n\r\nKindly draft my Travel Authorization in Vision based on the approved trip:" "\r\n\r\n{{url}}" "\r\n\r\nThanks," "\r\n{{owner_name}}") send_mail( instance.owner.email, template, { 'owner_name': instance.owner.get_full_name(), 'pa_assistant': instance.programme_assistant.get_full_name(), 'url': 'http://{}{}'.format(current_site.domain, instance.get_admin_url()) }, instance.programme_assistant.email, )
class Page(models.Model): objects = models.Manager() uniques = UniquePageManager() title = models.CharField(_("title"), max_length=255, unique=True) tags = models.ManyToManyField("tags.Tag", blank=True, related_name="pages") redirect_to = models.OneToOneField("Page", blank=True, null=True) #wiki_votes = GenericRelation("utils.Vote") #wiki_rates = GenericRelation("utils.Rate") wiki_views = GenericRelation("utils.View") view_count = models.IntegerField(default=0) wiki_bookmark = GenericRelation("utils.Bookmark") image_attachment = GenericRelation("utils.ImageAttachment") # count of things bookmark_count = models.IntegerField(default=0) # number of comment count, used for sorting. open_comment_count = models.IntegerField(default=0) pending_comment_count = models.IntegerField(default=0) current_revision = models.OneToOneField('PageRevision', blank=True, null=True, verbose_name=_('current revision'), related_name="revision_page") OPEN, PROTECTED = range(2) STATUS_CHOICE = [(OPEN, "open"), (PROTECTED, "protected")] status = models.IntegerField(choices=STATUS_CHOICE, default=OPEN) # redirect url def __unicode__(self): return self.title def get_title(self): return self.title.replace(" ", "_") def get_lead_section(self): #(\[TOC\])?\r\n#(.|\n)*$ pattern = re.compile(u'^\s*?((.|\n)*?)\s*?(\n#(.|\n)*)?$') match = re.search(pattern, self.current_revision.content) lead_raw = match.group(1) toc = re.compile(u'\[TOC\]') lead = re.sub(toc, '', lead_raw) mkd_content = markdown.markdown( lead, extensions=[ 'extra', 'wikilinks(base_url=/wiki/, end_url=/)', ], safe_mode='escape') pattern = re.compile(u'(<a[^>]*?wikilink)(.*?)(>(.*?)</a>)') mkd_content_wikilink = re.sub(pattern, replace_wikilinks, mkd_content) return mkd_content_wikilink def get_rate_average(self): rate_count = self.wiki_rates.count() rate_sum = 0 for rate in self.wiki_rates.all(): rate_sum += rate.rating if rate_count > 0: return float(rate_sum) / rate_count else: return rate_sum def get_open_comment(self): return self.comments.filter(status=0) def get_pending_comment(self): return self.comments.filter(status=1) def get_closed_comment(self): return self.comments.filter(status=2) @staticmethod def update_wiki_views(wiki, request, hours=24): "Views are updated per user session" # Extract the IP number from the request. ip1 = request.META.get('REMOTE_ADDR', '') ip2 = request.META.get('HTTP_X_FORWARDED_FOR', '').split(",")[0].strip() # 'localhost' is not a valid ip address. ip1 = '' if ip1.lower() == 'localhost' else ip1 ip2 = '' if ip2.lower() == 'localhost' else ip2 ip = ip2 or ip1 or '0.0.0.0' now = timezone.now() since = now - timezone.timedelta(hours=hours) obj_type = ContentType.objects.get_for_model(wiki) obj_id = wiki.id # One view per time interval from each IP address. if not wiki.wiki_views.filter(ip=ip, date__gt=since): new_view = View(ip=ip, content_object=wiki, date=now) new_view.save() Page.objects.filter(id=wiki.id).update(view_count=F('view_count') + 1) return wiki @staticmethod def reset_comment_count(): for wiki in Page.objects.all(): wiki.open_comment_count = wiki.get_open_comment().count() wiki.pending_comment_count = wiki.get_pending_comment().count() wiki.save() @staticmethod def update_comment_count(sender, instance, **kwargs): page = instance.page page.open_comment_count = page.get_open_comment().count() page.pending_comment_count = page.get_pending_comment().count() page.save() def get_absolute_url(self): return reverse('wiki:wiki-detail', kwargs={'title': self.get_title()})
def negotiable(cls): # EXTEND NEGOTIABLE CLASS # add the default for mandatory method 'freeze' if not hasattr(cls, 'freeze') or not callable(getattr(cls, 'freeze')): setattr(cls, 'freeze', freeze) # add the mandatory 'creator' property if not hasattr(cls, 'creator'): setattr(cls, 'creator', creator) # add the generic relation field to negotiable class negotiations = GenericRelation(Negotiation, object_id_field='content_pk', content_type_field='content_type') negotiations.contribute_to_class(cls, 'negotiations') # add the negotiation property setattr(cls, 'negotiation', negotiation) # add the negotiate method setattr(cls, 'negotiate', negotiate) # add the status_for method setattr(cls, 'status_for', status_for) # add the accept method setattr(cls, 'accept', accept) # add the cancel method setattr(cls, 'cancel', cancel) # add the counter_proposal method setattr(cls, 'counter_proposal', counter_proposal) # add the modify_proposal method setattr(cls, 'modify_proposal', modify_proposal) # add the is_negotiating property setattr(cls, 'is_negotiating', is_negotiating) # add the is_accepted property setattr(cls, 'is_accepted', is_accepted) # add the is_cancelled property setattr(cls, 'is_cancelled', is_cancelled) # add the is_seller method setattr(cls, 'is_seller', is_seller) # add the is_client method setattr(cls, 'is_client', is_client) # add the last_proposal_from method setattr(cls, 'last_proposal_from', last_proposal_from) # add the last_counterpart_proposal_for method setattr(cls, 'last_counterpart_proposal_for', last_counterpart_proposal_for) # add the last_client_proposal property setattr(cls, 'last_client_proposal', last_client_proposal) # add the last_seller_proposal property setattr(cls, 'last_seller_proposal', last_seller_proposal) # add the initiator property setattr(cls, 'initiator', initiator) # add the last_updater property setattr(cls, 'last_updater', last_updater) # add the is_last_updater method setattr(cls, 'is_last_updater', is_last_updater) # add the history method setattr(cls, 'history', history) # add the negotiation_options method setattr(cls, 'negotiation_options', negotiation_options) # EXTEND NEGOTIABLE CLASS'S MANAGERS AND QUERYSETS cls._meta.concrete_managers.sort() managers = [(mgr_name, manager) for _, mgr_name, manager in cls._meta.concrete_managers] setattr(cls, '_default_manager', None) # clean the default manager setattr(cls._meta, 'concrete_managers', []) # clean the managers for mgr_name, manager in managers: class ExtendedNegotiableManager(ExtendedNegotiableManagerMixin, manager.__class__): class ExtendedNegotiableQueryset(ExtendedNegotiableQuerysetMixin, manager.get_queryset().__class__): pass def get_queryset(self): return self.ExtendedNegotiableQueryset(self.model, using=self._db) cls.add_to_class(mgr_name, ExtendedNegotiableManager()) return cls
class Metric(models.Model): name = models.CharField(max_length=300) slug = models.SlugField() data = GenericRelation('Datum') show_on_dashboard = models.BooleanField(default=True) show_sparkline = models.BooleanField(default=True) period = models.CharField(max_length=15, choices=METRIC_PERIOD_CHOICES, default=METRIC_PERIOD_INSTANT) unit = models.CharField(max_length=100) unit_plural = models.CharField(max_length=100) class Meta: abstract = True def __unicode__(self): return self.name @models.permalink def get_absolute_url(self): return ("metric-detail", [self.slug]) def gather_data(self, since): """ Gather all the data from this metric since a given date. Returns a list of (timestamp, value) tuples. The timestamp is a Unix timestamp, coverted from localtime to UTC. """ if self.period == METRIC_PERIOD_INSTANT: return self._gather_data_instant(since) elif self.period == METRIC_PERIOD_DAILY: return self._gather_data_periodic(since, 'day') elif self.period == METRIC_PERIOD_WEEKLY: return self._gather_data_periodic(since, 'week') else: raise ValueError("Unknown period: %s", self.period) def _gather_data_instant(self, since): """ Gather data from an "instant" metric. Instant metrics change every time we measure them, so they're easy: just return every single measurement. """ data = self.data.filter(timestamp__gt=since) \ .order_by('timestamp') \ .values_list('timestamp', 'measurement') return [(calendar.timegm(t.timetuple()), m) for (t, m) in data] def _gather_data_periodic(self, since, period): """ Gather data from "periodic" merics. Period metrics are reset every day/week/month and count up as the period goes on. Think "commits today" or "new tickets this week". XXX I'm not completely sure how to deal with this since time zones wreak havoc, so there's right now a hard-coded offset which doesn't really scale but works for now. """ OFFSET = "2 hours" # HACK! ctid = ContentType.objects.get_for_model(self).id c = connections['default'].cursor() c.execute( '''SELECT DATE_TRUNC(%s, timestamp - INTERVAL %s), MAX(measurement) FROM dashboard_datum WHERE content_type_id = %s AND object_id = %s AND timestamp >= %s GROUP BY 1;''', [period, OFFSET, ctid, self.id, since]) return [(calendar.timegm(t.timetuple()), float(m)) for (t, m) in c.fetchall()]