Esempio n. 1
0
    def clean(self, value, single=False):
        """
        Clean the form value

        If optional argument ``single`` is True, the returned value will be a
        string containing the tag name.

        If ``single`` is False (default), the returned value will be a list of
        strings containing tag names.
        """
        value = super(BaseTagField, self).clean(value)

        if self.tag_options.force_lowercase:
            value = value.lower()

        if single:
            return value

        try:
            return parse_tags(
                value, self.tag_options.max_count,
                self.tag_options.space_delimiter,
            )
        except ValueError as e:
            raise forms.ValidationError(_('%s' % e))
Esempio n. 2
0
 def test_quotes_comma_delim_spaces_ignored(self):
     tags = tag_utils.parse_tags(
         '"adam, one"  ,  "brian, two"  ,  "chris, three"')
     self.assertEqual(len(tags), 3)
     self.assertEqual(tags[0], "adam, one")
     self.assertEqual(tags[1], "brian, two")
     self.assertEqual(tags[2], "chris, three")
Esempio n. 3
0
    def clean(self, value, single=False):
        """
        Clean the form value

        If optional argument ``single`` is True, the returned value will be a
        string containing the tag name.

        If ``single`` is False (default), the returned value will be a list of
        strings containing tag names.
        """
        value = super(BaseTagField, self).clean(value)

        if self.tag_options.force_lowercase:
            value = value.lower()

        if single:
            return value

        try:
            return parse_tags(
                value, self.tag_options.max_count,
                self.tag_options.space_delimiter,
            )
        except ValueError as e:
            raise forms.ValidationError(_('%s' % e))
Esempio n. 4
0
 def test_quotes_dont_close(self):
     tags = tag_utils.parse_tags('"adam,one","brian,two","chris, dave')
     self.assertEqual(len(tags), 3)
     # Will be sorted, " comes first
     self.assertEqual(tags[0], '"chris, dave')
     self.assertEqual(tags[1], "adam,one")
     self.assertEqual(tags[2], "brian,two")
Esempio n. 5
0
 def test_quotes_escaped_late(self):
     """
     Tests quotes when delimiter switches to comma
     """
     tags = tag_utils.parse_tags('""adam"" brian"", chris')
     self.assertEqual(len(tags), 2)
     self.assertEqual(tags[0], '"adam" brian"')
     self.assertEqual(tags[1], "chris")
Esempio n. 6
0
 def test_parse_renders_tags(self):
     tagstr = "adam, brian, chris"
     tags = tag_utils.parse_tags(tagstr)
     tagstr2 = tag_utils.render_tags(tags)
     self.assertEqual(len(tags), 3)
     self.assertEqual(tags[0], "adam")
     self.assertEqual(tags[1], "brian")
     self.assertEqual(tags[2], "chris")
     self.assertEqual(tagstr, tagstr2)
Esempio n. 7
0
 def test_parse_renders_tags_complex(self):
     tagstr = '"""adam brian"", ""chris, dave", "ed, frank", gary'
     tags = tag_utils.parse_tags(tagstr)
     tagstr2 = tag_utils.render_tags(tags)
     self.assertEqual(len(tags), 3)
     self.assertEqual(tags[0], '"adam brian", "chris, dave')
     self.assertEqual(tags[1], "ed, frank")
     self.assertEqual(tags[2], "gary")
     self.assertEqual(tagstr, tagstr2)
Esempio n. 8
0
 def test_quotes_escaped(self):
     """
     Tests quotes when delimiter is already comma
     """
     tags = tag_utils.parse_tags('adam, br""ian, ""chris, dave""')
     self.assertEqual(len(tags), 4)
     self.assertEqual(tags[0], '"chris')
     self.assertEqual(tags[1], "adam")
     self.assertEqual(tags[2], 'br"ian')
     self.assertEqual(tags[3], 'dave"')
    def set_tag_string(self, tag_string):
        """
        Sets the tags for this instance, given a tag edit string
        """
        # Get all tag names
        tag_names = parse_tags(
            tag_string, space_delimiter=self.tag_options.space_delimiter)

        # Pass on to set_tag_list
        return self.set_tag_list(tag_names)
Esempio n. 10
0
 def set_tag_string(self, tag_string):
     """
     Sets the tags for this instance, given a tag edit string
     """
     # Get all tag names
     tag_names = parse_tags(
         tag_string, space_delimiter=self.tag_options.space_delimiter,
     )
     
     # Pass on to set_tag_list
     return self.set_tag_list(tag_names)
Esempio n. 11
0
    def __eq__(self, other):
        """
        Compare a tag string or iterable of tags to the tags on this manager
        """
        # If not case sensitive, or lowercase forced, compare on lowercase
        lower = False
        if self.tag_options.force_lowercase or not self.tag_options.case_sensitive:
            lower = True

        # Prep other argument we're comparing against
        if isinstance(other, BaseTagRelatedManager):
            other = other.tags
        if isinstance(other, six.string_types):
            other_str = six.text_type(other)

            # Enforce case non-sensitivity or lowercase
            if lower:
                other_str = other_str.lower()

            # Parse other_str into list of tags
            other_tags = parse_tags(
                other_str,
                space_delimiter=self.tag_options.space_delimiter,
            )

        else:
            # Assume it's an iterable
            other_tags = other
            if lower:
                other_tags = [six.text_type(tag).lower() for tag in other]

        # Get list of set tags
        self_tags = self.get_tag_list()

        # Compare tag count
        if len(other_tags) != len(self_tags):
            return False

        # Compare tags
        for tag in self_tags:
            # If lowercase or not case sensitive, lower for comparison
            if lower:
                tag = tag.lower()

            # Check tag in other tags
            if tag not in other_tags:
                return False

        # Same number of tags, and all self tags present in other tags
        # It's a match
        return True
Esempio n. 12
0
 def __eq__(self, other):
     """
     Compare a tag string or iterable of tags to the tags on this manager
     """
     # If not case sensitive, or lowercase forced, compare on lowercase
     lower = False
     if self.tag_options.force_lowercase or not self.tag_options.case_sensitive:
         lower = True
         
     # Prep other argument we're comparing against
     if isinstance(other, BaseTagRelatedManager):
         other = other.tags
     if isinstance(other, six.string_types):
         other_str = six.text_type(other)
         
         # Enforce case non-sensitivity or lowercase
         if lower:
             other_str = other_str.lower()
         
         # Parse other_str into list of tags
         other_tags = parse_tags(
             other_str, space_delimiter=self.tag_options.space_delimiter,
         )
         
     else:
         # Assume it's an iterable
         other_tags = other
         if lower:
             other_tags = [six.text_type(tag).lower() for tag in other]
     
     # Get list of set tags
     self_tags = self.get_tag_list()
     
     # Compare tag count
     if len(other_tags) != len(self_tags):
         return False
     
     # Compare tags
     for tag in self_tags:
         # If lowercase or not case sensitive, lower for comparison
         if lower:
             tag = tag.lower()
         
         # Check tag in other tags
         if tag not in other_tags:
             return False
     
     # Same number of tags, and all self tags present in other tags
     # It's a match
     return True
Esempio n. 13
0
    def _prep_merge_tags(self, tags):
        """
        Ensure tags argument for merge_tags is an iterable of tag objects,
        excluding self
        """
        # Ensure tags is a list of tag instances
        if isinstance(tags, six.string_types):
            tags = utils.parse_tags(
                tags, space_delimiter=self.tag_options.space_delimiter)
        if not isinstance(tags, models.query.QuerySet):
            tags = self.tag_model.objects.filter(name__in=tags)

        # Make sure self isn't in tags
        return tags.exclude(pk=self.pk)
Esempio n. 14
0
    def _prep_merge_tags(self, tags):
        """
        Ensure tags argument for merge_tags is an iterable of tag objects,
        excluding self
        """
        # Ensure tags is a list of tag instances
        if isinstance(tags, six.string_types):
            tags = utils.parse_tags(
                tags, space_delimiter=self.tag_options.space_delimiter,
            )
        if not isinstance(tags, models.query.QuerySet):
            tags = self.tag_model.objects.filter(name__in=tags)

        # Make sure self isn't in tags
        return tags.exclude(pk=self.pk)
Esempio n. 15
0
    def __setattr__(self, name, value):
        """
        Only allow an option to be set if it's valid
        """
        if name == 'initial':
            # Store as a list of strings, with the tag string available on
            # initial_string for migrations
            if value is None:
                self.__dict__['initial_string'] = ''
                self.__dict__['initial'] = []
            elif isinstance(value, six.string_types):
                self.__dict__['initial_string'] = value
                self.__dict__['initial'] = parse_tags(value)
            else:
                self.__dict__['initial_string'] = render_tags(value)
                self.__dict__['initial'] = value

        elif name in constants.OPTION_DEFAULTS:
            self.__dict__[name] = value
        else:
            raise AttributeError(name)
Esempio n. 16
0
    def __setattr__(self, name, value):
        """
        Only allow an option to be set if it's valid
        """
        if name == 'initial':
            # Store as a list of strings, with the tag string available on
            # initial_string for migrations
            if value is None:
                self.__dict__['initial_string'] = ''
                self.__dict__['initial'] = []
            elif isinstance(value, six.string_types):
                self.__dict__['initial_string'] = value
                self.__dict__['initial'] = parse_tags(value)
            else:
                self.__dict__['initial_string'] = render_tags(value)
                self.__dict__['initial'] = value

        elif name in constants.OPTION_DEFAULTS:
            self.__dict__[name] = value
        else:
            raise AttributeError(name)
Esempio n. 17
0
 def test_spaces_false_mixed(self):
     tags = tag_utils.parse_tags("adam,brian chris", space_delimiter=False)
     self.assertEqual(len(tags), 2)
     self.assertEqual(tags[0], "adam")
     self.assertEqual(tags[1], "brian chris")
Esempio n. 18
0
 def test_spaces_false_spaces(self):
     tags = tag_utils.parse_tags("adam brian chris", space_delimiter=False)
     self.assertEqual(len(tags), 1)
     self.assertEqual(tags[0], "adam brian chris")
Esempio n. 19
0
 def test_spaces_false_commas(self):
     tags = tag_utils.parse_tags("adam,brian,chris", space_delimiter=False)
     self.assertEqual(len(tags), 3)
     self.assertEqual(tags[0], "adam")
     self.assertEqual(tags[1], "brian")
     self.assertEqual(tags[2], "chris")
Esempio n. 20
0
 def _filter_or_exclude(self, negate, *args, **kwargs):
     """
     Custom lookups for tag fields
     """
     # TODO: When minimum supported Django 1.7+, this can be replaced with
     # custom lookups, which would work much better anyway.
     safe_fields, singletag_fields, tag_fields, field_lookup = _split_kwargs(
         self.model, kwargs, lookups=True, with_fields=True
     )
     
     # Look up string values for SingleTagFields by name
     for field_name, val in singletag_fields.items():
         query_field_name = field_name
         if isinstance(val, six.string_types):
             query_field_name += '__name'
             if not field_lookup[field_name].tag_options.case_sensitive:
                 query_field_name += '__iexact'
         safe_fields[query_field_name] = val
     
     # Query as normal
     qs = super(TaggedQuerySet, self)._filter_or_exclude(
         negate, *args, **safe_fields
     )
     
     # Look up TagFields by string name
     #
     # Each of these comparisons will be done with a subquery; for
     # A filter can chain, ie .filter(tags__name=..).filter(tags__name=..),
     # but exclude won't work that way; has to be done with a subquery
     for field_name, val in tag_fields.items():
         val, lookup = val
         tag_options = field_lookup[field_name].tag_options
         
         # Only perform custom lookup if value is a string
         if not isinstance(val, six.string_types):
             qs = super(TaggedQuerySet, self)._filter_or_exclude(
                 negate, **{field_name: val}
             )
             continue
         
         # Parse the tag string
         tags = utils.parse_tags(
             val, space_delimiter=tag_options.space_delimiter,
         )
         
         # Prep the subquery
         subqs = qs
         if negate:
             subqs = self.__class__(model=self.model, using=self._db)
         
         # To get an exact match, filter this queryset to only include
         # items with a tag count that matches the number of specified tags
         if lookup == 'exact':
             count_name = '_tagulous_count_%s' % field_name
             subqs = subqs.annotate(
                 **{count_name: models.Count(field_name)}
             ).filter(**{count_name: len(tags)})
         
         # Prep the field name
         query_field_name = field_name + '__name'
         if not tag_options.case_sensitive:
             query_field_name += '__iexact'
         
         # Now chain the filters for each tag
         #
         # Have to do it this way to create new inner joins for each tag;
         # ANDing Q objects will do it all on a single inner join, which
         # will match nothing
         for tag in tags:
             subqs = subqs.filter(**{query_field_name: tag})
         
         # Fold subquery back into main query
         if negate:
             # Exclude on matched ID
             qs = qs.exclude(pk__in=subqs.values('pk'))
         else:
             # A filter op can just replace the main query
             qs = subqs
     
     return qs
Esempio n. 21
0
 def test_order(self):
     tags = tag_utils.parse_tags("chris, adam, brian")
     self.assertEqual(len(tags), 3)
     self.assertEqual(tags[0], "adam")
     self.assertEqual(tags[1], "brian")
     self.assertEqual(tags[2], "chris")
Esempio n. 22
0
 def test_commas_and_spaces(self):
     tags = tag_utils.parse_tags("adam, brian chris")
     self.assertEqual(len(tags), 2)
     self.assertEqual(tags[0], "adam")
     self.assertEqual(tags[1], "brian chris")
Esempio n. 23
0
 def test_spaces(self):
     tags = tag_utils.parse_tags("adam brian chris")
     self.assertEqual(len(tags), 3)
     self.assertEqual(tags[0], "adam")
     self.assertEqual(tags[1], "brian")
     self.assertEqual(tags[2], "chris")
Esempio n. 24
0
 def test_quotes_and_unquoted(self):
     tags = tag_utils.parse_tags('adam , "brian, chris" , dave')
     self.assertEqual(len(tags), 3)
     self.assertEqual(tags[0], "adam")
     self.assertEqual(tags[1], "brian, chris")
     self.assertEqual(tags[2], "dave")
Esempio n. 25
0
    def _filter_or_exclude(self, negate, *args, **kwargs):
        """
        Custom lookups for tag fields
        """
        # TODO: When minimum supported Django 1.7+, this can be replaced with
        # custom lookups, which would work much better anyway.
        safe_fields, singletag_fields, tag_fields, field_lookup = _split_kwargs(
            self.model, kwargs, lookups=True, with_fields=True)

        # Look up string values for SingleTagFields by name
        for field_name, val in singletag_fields.items():
            query_field_name = field_name
            if isinstance(val, six.string_types):
                query_field_name += "__name"
                if not field_lookup[field_name].tag_options.case_sensitive:
                    query_field_name += "__iexact"
            safe_fields[query_field_name] = val

        # Query as normal
        qs = super(TaggedQuerySet,
                   self)._filter_or_exclude(negate, *args, **safe_fields)

        # Look up TagFields by string name
        #
        # Each of these comparisons will be done with a subquery; for
        # A filter can chain, ie .filter(tags__name=..).filter(tags__name=..),
        # but exclude won't work that way; has to be done with a subquery
        for field_name, val in tag_fields.items():
            val, lookup = val
            tag_options = field_lookup[field_name].tag_options

            # Only perform custom lookup if value is a string
            if not isinstance(val, six.string_types):
                qs = super(TaggedQuerySet,
                           self)._filter_or_exclude(negate,
                                                    **{field_name: val})
                continue

            # Parse the tag string
            tags = utils.parse_tags(
                val, space_delimiter=tag_options.space_delimiter)

            # Prep the subquery
            subqs = qs
            if negate:
                subqs = self.__class__(model=self.model, using=self._db)

            # To get an exact match, filter this queryset to only include
            # items with a tag count that matches the number of specified tags
            if lookup == "exact":
                count_name = "_tagulous_count_%s" % field_name
                subqs = subqs.annotate(**{
                    count_name: models.Count(field_name)
                }).filter(**{count_name: len(tags)})

            # Prep the field name
            query_field_name = field_name + "__name"
            if not tag_options.case_sensitive:
                query_field_name += "__iexact"

            # Now chain the filters for each tag
            #
            # Have to do it this way to create new inner joins for each tag;
            # ANDing Q objects will do it all on a single inner join, which
            # will match nothing
            for tag in tags:
                subqs = subqs.filter(**{query_field_name: tag})

            # Fold subquery back into main query
            if negate:
                # Exclude on matched ID
                qs = qs.exclude(pk__in=subqs.values("pk"))
            else:
                # A filter op can just replace the main query
                qs = subqs

        return qs
Esempio n. 26
0
 def test_quotes_dont_delimit(self):
     tags = tag_utils.parse_tags('adam"brian,chris dave')
     self.assertEqual(len(tags), 2)
     self.assertEqual(tags[0], 'adam"brian')
     self.assertEqual(tags[1], "chris dave")
Esempio n. 27
0
 def test_quotes_comma_delim_late_wins_unescaped_quotes(self):
     "When delimiter changes, return insignificant unescaped quotes"
     tags = tag_utils.parse_tags('adam "one", brian two')
     self.assertEqual(len(tags), 2)
     self.assertEqual(tags[0], 'adam "one"')
     self.assertEqual(tags[1], "brian two")
Esempio n. 28
0
 def test_quotes_comma_delim_late_wins(self):
     tags = tag_utils.parse_tags('"adam one" "brian two","chris three"')
     self.assertEqual(len(tags), 2)
     self.assertEqual(tags[0], 'adam one" "brian two')
     self.assertEqual(tags[1], "chris three")
Esempio n. 29
0
class Thesis(models.Model):
    """
    This class defines the field that a thesis can have.
    The following fields are optional: additional, pdf
    A thesis can be promoted for either BSc, MSc, BEd, MEd, or as being part of a project.
    Each thesis is referenced with the chair that is providing it via a ForeignKey field.
    """
    THESIS_CHOICES = (
        ('BSC', 'Bachelor of Science'),
        ('MSC', 'Master of Science'),
        ('BED', 'Bachelor of Education'),
        ('MED', 'Master of Education'),
        ('PRO', 'Forschungsprojekt'),
        ('ETC', 'nach Absprache')
    )

    title = models.CharField('Titel der Arbeit',
                             blank=False,
                             max_length=200)

    description = models.TextField('Beschreibung',
                                   blank=False)

    date_added = models.DateTimeField('Erstellungsdatum',
                                      default=timezone.now,
                                      editable=False)

    additional = models.TextField('weitere Beschreibung',
                                  blank=True,
                                  max_length=1000)

    contact = models.EmailField('E-Mail der Kontaktperson:',
                                blank=False)

    chair = models.ForeignKey(Chair, on_delete=models.CASCADE,
                              related_name="provided_by",
                              verbose_name='angeboten durch Lehrstuhl')

    start_date = models.DateField('frühester Beginn',
                                  blank=False,
                                  default=timezone.now)

    is_active = models.BooleanField('aktiv',
                                    default=True)

    pdf = models.FileField('PDF mit Ausschreibung',
                           validators=[FileExtensionValidator(allowed_extensions=['pdf'])],
                           blank=True)

    type = MultiSelectField('Art der Arbeit',
                            choices=THESIS_CHOICES,
                            blank=False)

    tags = tagulous.models.TagField(get_absolute_url=lambda tag: reverse(
            'by_tag',
            args=parse_tags(tag.slug)))

    user = models.ForeignKey(AAIUser, null=True,
                             on_delete=models.DO_NOTHING,
                             related_name="uploaded_by",
                             verbose_name="hochgeladen von")

    def __str__(self):
        return self.title

    def get_absolute_url(self):
        return "/%i/" % self.id

    class Meta:
        verbose_name = "Abschlussarbeit"
        verbose_name_plural = "Abschlussarbeiten"
Esempio n. 30
0
 def test_empty_tag(self):
     tags = tag_utils.parse_tags('"adam" , , brian , ')
     self.assertEqual(len(tags), 2)
     self.assertEqual(tags[0], "adam")
     self.assertEqual(tags[1], "brian")
Esempio n. 31
0
 def test_trailing_space(self):
     tags = tag_utils.parse_tags("adam brian ")
     self.assertEqual(len(tags), 2)
     self.assertEqual(tags[0], "adam")
     self.assertEqual(tags[1], "brian")
Esempio n. 32
0
 def test_limit(self):
     with self.assertRaises(ValueError) as cm:
         tag_utils.parse_tags("adam,brian,chris", 1)
     e = cm.exception
     self.assertEqual(str(e), "This field can only have 1 argument")
Esempio n. 33
0
 def test_commas_over_spaces(self):
     tags = tag_utils.parse_tags("adam brian  ,  chris")
     self.assertEqual(len(tags), 2)
     self.assertEqual(tags[0], "adam brian")
     self.assertEqual(tags[1], "chris")
Esempio n. 34
0
 def test_limit_quotes(self):
     with self.assertRaises(ValueError) as cm:
         tag_utils.parse_tags('"adam","brian",chris', 2)
     e = cm.exception
     self.assertEqual(str(e), "This field can only have 2 arguments")
Esempio n. 35
0
 def test_quotes(self):
     tags = tag_utils.parse_tags('"adam, one"')
     self.assertEqual(len(tags), 1)
     self.assertEqual(tags[0], "adam, one")
Esempio n. 36
0
 def test_quotes_space_delim(self):
     tags = tag_utils.parse_tags('"adam one" "brian two" "chris three"')
     self.assertEqual(len(tags), 3)
     self.assertEqual(tags[0], "adam one")
     self.assertEqual(tags[1], "brian two")
     self.assertEqual(tags[2], "chris three")