138 lines
4.1 KiB
Python
138 lines
4.1 KiB
Python
from __future__ import unicode_literals
|
|
|
|
from django import VERSION
|
|
from django.utils import six
|
|
from django.utils.encoding import force_text
|
|
from django.utils.functional import wraps
|
|
|
|
|
|
def _get_field(model, name):
|
|
if VERSION < (1, 8):
|
|
return model._meta.get_field_by_name(name)[0]
|
|
else:
|
|
return model._meta.get_field(name)
|
|
|
|
|
|
def parse_tags(tagstring):
|
|
"""
|
|
Parses tag input, with multiple word input being activated and
|
|
delineated by commas and double quotes. Quotes take precedence, so
|
|
they may contain commas.
|
|
|
|
Returns a sorted list of unique tag names.
|
|
|
|
Ported from Jonathan Buchanan's `django-tagging
|
|
<http://django-tagging.googlecode.com/>`_
|
|
"""
|
|
if not tagstring:
|
|
return []
|
|
|
|
tagstring = force_text(tagstring)
|
|
|
|
# Special case - if there are no commas or double quotes in the
|
|
# input, we don't *do* a recall... I mean, we know we only need to
|
|
# split on spaces.
|
|
if ',' not in tagstring and '"' not in tagstring:
|
|
words = list(set(split_strip(tagstring, ' ')))
|
|
words.sort()
|
|
return words
|
|
|
|
words = []
|
|
buffer = []
|
|
# Defer splitting of non-quoted sections until we know if there are
|
|
# any unquoted commas.
|
|
to_be_split = []
|
|
saw_loose_comma = False
|
|
open_quote = False
|
|
i = iter(tagstring)
|
|
try:
|
|
while True:
|
|
c = six.next(i)
|
|
if c == '"':
|
|
if buffer:
|
|
to_be_split.append(''.join(buffer))
|
|
buffer = []
|
|
# Find the matching quote
|
|
open_quote = True
|
|
c = six.next(i)
|
|
while c != '"':
|
|
buffer.append(c)
|
|
c = six.next(i)
|
|
if buffer:
|
|
word = ''.join(buffer).strip()
|
|
if word:
|
|
words.append(word)
|
|
buffer = []
|
|
open_quote = False
|
|
else:
|
|
if not saw_loose_comma and c == ',':
|
|
saw_loose_comma = True
|
|
buffer.append(c)
|
|
except StopIteration:
|
|
# If we were parsing an open quote which was never closed treat
|
|
# the buffer as unquoted.
|
|
if buffer:
|
|
if open_quote and ',' in buffer:
|
|
saw_loose_comma = True
|
|
to_be_split.append(''.join(buffer))
|
|
if to_be_split:
|
|
if saw_loose_comma:
|
|
delimiter = ','
|
|
else:
|
|
delimiter = ' '
|
|
for chunk in to_be_split:
|
|
words.extend(split_strip(chunk, delimiter))
|
|
words = list(set(words))
|
|
words.sort()
|
|
return words
|
|
|
|
|
|
def split_strip(string, delimiter=','):
|
|
"""
|
|
Splits ``string`` on ``delimiter``, stripping each resulting string
|
|
and returning a list of non-empty strings.
|
|
|
|
Ported from Jonathan Buchanan's `django-tagging
|
|
<http://django-tagging.googlecode.com/>`_
|
|
"""
|
|
if not string:
|
|
return []
|
|
|
|
words = [w.strip() for w in string.split(delimiter)]
|
|
return [w for w in words if w]
|
|
|
|
|
|
def edit_string_for_tags(tags):
|
|
"""
|
|
Given list of ``Tag`` instances, creates a string representation of
|
|
the list suitable for editing by the user, such that submitting the
|
|
given string representation back without changing it will give the
|
|
same list of tags.
|
|
|
|
Tag names which contain commas will be double quoted.
|
|
|
|
If any tag name which isn't being quoted contains whitespace, the
|
|
resulting string of tag names will be comma-delimited, otherwise
|
|
it will be space-delimited.
|
|
|
|
Ported from Jonathan Buchanan's `django-tagging
|
|
<http://django-tagging.googlecode.com/>`_
|
|
"""
|
|
names = []
|
|
for tag in tags:
|
|
name = tag.name
|
|
if ',' in name or ' ' in name:
|
|
names.append('"%s"' % name)
|
|
else:
|
|
names.append(name)
|
|
return ', '.join(sorted(names))
|
|
|
|
|
|
def require_instance_manager(func):
|
|
@wraps(func)
|
|
def inner(self, *args, **kwargs):
|
|
if self.instance is None:
|
|
raise TypeError("Can't call %s with a non-instance manager" % func.__name__)
|
|
return func(self, *args, **kwargs)
|
|
return inner
|