Commit 57e30c5f by Alex Gaynor

Some minor cleanup, renaming.

parent f364ac09
...@@ -7,3 +7,4 @@ fakeempire <adam@fakeempire.com> ...@@ -7,3 +7,4 @@ fakeempire <adam@fakeempire.com>
Ben Firshman <ben@firshman.co.uk> Ben Firshman <ben@firshman.co.uk>
Alex Gaynor <alex.gaynor@gmail.com> Alex Gaynor <alex.gaynor@gmail.com>
Rob Hudson <rob@cogit8.org> Rob Hudson <rob@cogit8.org>
Frank Wiles
...@@ -27,3 +27,5 @@ Then you can use the API like so: ...@@ -27,3 +27,5 @@ Then you can use the API like so:
Tags will show up for you automatically in forms and the admin. Tags will show up for you automatically in forms and the admin.
``django-taggit`` requires Django 1.1 or greater.
taggit.contrib.suggest taggit.contrib.suggest
====================== ======================
...@@ -9,23 +8,28 @@ thing. ...@@ -9,23 +8,28 @@ thing.
For example, if your site is a humor site you might want to collapse all of For example, if your site is a humor site you might want to collapse all of
#fun, #funny, #funnies, #hilarious, #rofl, and #lol into one tag #funny. The #fun, #funny, #funnies, #hilarious, #rofl, and #lol into one tag #funny. The
suggest_tags() function in taggit.contrib.suggest.utils will give you a list ``suggest_tags()`` function in ``taggit.contrib.suggest.utils`` will give you a
of tags that seem appropriate for the text content given to it. list of tags that seem appropriate for the text content given to it.
Unlike the rest of ``django-taggit``, ``suggest`` requires Django 1.2.
Usage Usage
===== =====
Put 'taggit.contrib.suggest' into INSTALLED_APPS and run a syncdb to create Put ``'taggit.contrib.suggest'`` into ``INSTALLED_APPS`` and run a syncdb to
the necessary models. This will add Keywords and Regular Expression inlines create the necessary models. This will add ``Keywords`` and
to the default django-taggit admin. Once you've populated those based on your ``Regular Expression`` inlines to the default ``django-taggit`` admin. Once
site you can do a simple: you've populated those based on your site you can do a simple:
.. sourcecode:: python
from taggit.contrib.suggest.utils import suggest_tags
from taggit.contrib.suggest.utils import suggest_tags tags = suggest_tags(content='Some textual content...')
tags = suggest_tags(content='Some textual content...')
TODO TODO
==== ====
* In a later version I hope to a simple way to help determine keywords for you * In a later version I hope to a simple way to help determine keywords for you
automatically, by learning from your past tags and content. automatically, by learning from your past tags and content.
from django.contrib import admin from django.contrib import admin
from taggit.models import Tag
from taggit.admin import TaggedItemInline from taggit.admin import TaggedItemInline
from taggit.contrib.suggest.models import TagKeyword, TagRegExp from taggit.contrib.suggest.models import TagKeyword, TagRegex
from taggit.models import Tag
class TagKeywordInline(admin.StackedInline): class TagKeywordInline(admin.StackedInline):
model = TagKeyword model = TagKeyword
class TagRegExpInline(admin.StackedInline):
model = TagRegExp class TagRegxInline(admin.StackedInline):
model = TagRegex
class TagSuggestAdmin(admin.ModelAdmin): class TagSuggestAdmin(admin.ModelAdmin):
inlines = [ inlines = [
TaggedItemInline, TaggedItemInline,
TagKeywordInline, TagKeywordInline,
TagRegExpInline, TagRegxInline,
] ]
admin.site.unregister(Tag) admin.site.unregister(Tag)
admin.site.register(Tag, TagSuggestAdmin) admin.site.register(Tag, TagSuggestAdmin)
import re import re
from django.db import models
from django.core.exceptions import ValidationError from django.core.exceptions import ValidationError
from django.db import models
from taggit.models import Tag from taggit.models import Tag
HAS_PYSTEMMER = True
try: try:
import Stemmer import Stemmer
except ImportError: except ImportError:
HAS_PYSTEMMER = False Stemmer = None
class TagKeyword(models.Model): class TagKeyword(models.Model):
""" Model to associate simple keywords to a Tag """ """ Model to associate simple keywords to a Tag """
...@@ -22,25 +23,29 @@ class TagKeyword(models.Model): ...@@ -22,25 +23,29 @@ class TagKeyword(models.Model):
def save(self, *args, **kwargs): def save(self, *args, **kwargs):
""" Stem the keyword on save if they have PyStemmer """ """ Stem the keyword on save if they have PyStemmer """
language = kwargs.pop('stemmer-language', 'english') language = kwargs.pop('stemmer-language', 'english')
if not self.id and not self.stem and HAS_PYSTEMMER: if not self.pk and not self.stem and Stemmer:
stemmer = Stemmer.Stemmer(language) stemmer = Stemmer.Stemmer(language)
self.stem = stemmer.stemWord(self.keyword) self.stem = stemmer.stemWord(self.keyword)
super(TagKeyword,self).save(*args,**kwargs) super(TagKeyword, self).save(*args, **kwargs)
def validate_regexp(value): def validate_regex(value):
""" Make sure we have a valid regular expression """ """ Make sure we have a valid regular expression """
try: try:
re.compile(value) re.compile(value)
except: except Exception:
raise ValidationError('Please enter a valid regular expression') raise ValidationError('Please enter a valid regular expression')
class TagRegExp(models.Model):
class TagRegex(models.Model):
""" Model to associate regular expressions with a Tag """ """ Model to associate regular expressions with a Tag """
tag = models.ForeignKey(Tag, related_name='regexps') tag = models.ForeignKey(Tag, related_name='regexes')
name = models.CharField(max_length=30) name = models.CharField(max_length=30)
regexp = models.CharField(max_length=250, regex = models.CharField(
validators=[validate_regexp], max_length=250,
help_text='Enter a valid Regular Expression. To make it case-insensitive include "(?i)" in your expression.' validators=[validate_regex],
help_text=('Enter a valid Regular Expression. To make it '
'case-insensitive include "(?i)" in your expression.')
) )
def __unicode__(self): def __unicode__(self):
...@@ -49,4 +54,4 @@ class TagRegExp(models.Model): ...@@ -49,4 +54,4 @@ class TagRegExp(models.Model):
def save(self, *args, **kwargs): def save(self, *args, **kwargs):
""" Make sure to validate """ """ Make sure to validate """
self.full_clean() self.full_clean()
super(TagRegExp,self).save(*args,**kwargs) super(TagRegex,self).save(*args, **kwargs)
from taggit.contrib.suggest.tests.tests import SuggestCase from taggit.contrib.suggest.tests.tests import SuggestCase
...@@ -3,5 +3,6 @@ DATABASE_ENGINE = 'sqlite3' ...@@ -3,5 +3,6 @@ DATABASE_ENGINE = 'sqlite3'
INSTALLED_APPS = [ INSTALLED_APPS = [
'django.contrib.contenttypes', 'django.contrib.contenttypes',
'taggit', 'taggit',
'taggit.tests',
'taggit.contrib.suggest', 'taggit.contrib.suggest',
] ]
from django.test import TestCase
from django.core.exceptions import ValidationError from django.core.exceptions import ValidationError
from taggit.models import Tag from django.test import TestCase
from taggit.contrib.suggest.models import TagKeyword, TagRegExp
from taggit.contrib.suggest.models import TagKeyword, TagRegex
from taggit.contrib.suggest.utils import suggest_tags from taggit.contrib.suggest.utils import suggest_tags
from taggit.models import Tag
class SuggestCase(TestCase): class SuggestCase(TestCase):
def test_simple_suggest(self): def test_simple_suggest(self):
ku_tag = Tag.objects.create(name='ku') ku_tag = Tag.objects.create(name='ku')
ku_keyword1 = TagKeyword.objects.create( ku_keyword1 = TagKeyword.objects.create(
tag=ku_tag, tag=ku_tag,
keyword='kansas university') keyword='kansas university'
)
suggested_tags = suggest_tags(content='I used to be a student at kansas university') suggested_tags = suggest_tags('I used to be a student at kansas university')
self.assertTrue(ku_tag in suggested_tags) self.assertTrue(ku_tag in suggested_tags)
def test_regexp_suggest(self): def test_regex_suggest(self):
ku_tag = Tag.objects.create(name='ku') ku_tag = Tag.objects.create(name='ku')
new_regexp = TagRegExp.objects.create( TagRegex.objects.create(
tag=ku_tag, tag=ku_tag,
name='Find University of Kansas', name='Find University of Kansas',
regexp='University\s+of\s+Kansas') regex='University\s+of\s+Kansas'
)
suggested_tags = suggest_tags(content='I was once a student at the University of Kansas') suggested_tags = suggest_tags('I was once a student at the University of Kansas')
self.assertTrue(ku_tag in suggested_tags) self.assertTrue(ku_tag in suggested_tags)
def test_bad_regexp(self): def test_bad_regex(self):
ku_tag = Tag.objects.create(name='ku') ku_tag = Tag.objects.create(name='ku')
ku_keyword1 = TagKeyword.objects.create( ku_keyword1 = TagKeyword.objects.create(
tag=ku_tag, tag=ku_tag,
keyword='kansas university') keyword='kansas university'
new_regexp = TagRegExp( )
new_regex = TagRegex(
tag=ku_tag, tag=ku_tag,
name='Find University of Kansas', name='Find University of Kansas',
regexp='University\s+of(\s+Kansas') regex='University\s+of(\s+Kansas'
self.assertRaises(ValidationError, new_regexp.save) )
self.assertRaises(ValidationError, new_regex.save)
suggested_tags = suggest_tags(content='I was once a student at the University of Kansas. Also known as kansas university by the way.') suggested_tags = suggest_tags('I was once a student at the University '
'of Kansas. Also known as kansas university by the way.')
self.assertTrue(ku_tag in suggested_tags) self.assertTrue(ku_tag in suggested_tags)
import re import re
from taggit.models import Tag
from taggit.contrib.suggest.models import TagKeyword, TagRegExp
from django.conf import settings from django.conf import settings
from taggit.contrib.suggest.models import TagKeyword, TagRegex
from taggit.models import Tag
def _suggest_keywords(content=None):
def _suggest_keywords(content):
""" Suggest by keywords """ """ Suggest by keywords """
suggested_keywords = set() suggested_keywords = set()
keywords = TagKeyword.objects.values_list('keyword', 'stem', 'tag') keywords = TagKeyword.objects.all()
for k in keywords: for k in keywords:
# Use the stem if available, otherwise use the whole keyword # Use the stem if available, otherwise use the whole keyword
if k[1]: if k.stem:
if k[1] in content: if k.stem in content:
suggested_keywords.add(k[2]) suggested_keywords.add(k.tag_id)
elif k[0] in content: elif k.keyword in content:
suggested_keywords.add(k[2]) suggested_keywords.add(k.tag_id)
return suggested_keywords return suggested_keywords
def _suggest_regexps(content=None): def _suggest_regexes(content):
""" Suggest by regular expressions """ """ Suggest by regular expressions """
# Grab all regular expressions and compile them # Grab all regular expressions and compile them
suggested_regexps = set() suggested_regexes = set()
regexps = set() regex_keywords = TagRegex.objects.all()
regexp_keywords = TagRegExp.objects.values_list(
'regexp',
'tag',
)
for r in regexp_keywords:
regexps.add((re.compile(r[0]), r[1]))
# Look for our regular expressions in the content # Look for our regular expressions in the content
for r in regexps: for r in regex_keywords:
if r[0].search(content): if re.search(r.regex, content):
suggested_regexps.add(r[1]) suggested_regexes.add(r.tag_id)
return suggested_regexps return suggested_regexes
def suggest_tags(content=None): def suggest_tags(content):
""" Suggest tags based on text content """ """ Suggest tags based on text content """
suggested_keywords = _suggest_keywords(content) suggested_keywords = _suggest_keywords(content)
suggested_regexps = _suggest_regexps(content) suggested_regexes = _suggest_regexes(content)
suggested_tag_ids = suggested_keywords | suggested_regexps suggested_tag_ids = suggested_keywords | suggested_regexes
return Tag.objects.filter(id__in=suggested_tag_ids) return Tag.objects.filter(id__in=suggested_tag_ids)
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or sign in to comment