├── .gitignore ├── AUTHORS ├── LICENSE ├── MANIFEST.in ├── NOTICE ├── README ├── doc_src ├── Makefile ├── _build │ └── doctrees │ │ ├── api.doctree │ │ ├── environment.pickle │ │ ├── getting_started.doctree │ │ ├── index.doctree │ │ ├── installation.doctree │ │ ├── markup.doctree │ │ ├── real_world_example.doctree │ │ └── reference │ │ ├── index.doctree │ │ ├── settings.doctree │ │ └── template_tags.doctree ├── _static │ ├── breadcrumb_background.png │ ├── default.css │ ├── documentation.png │ ├── header_sm_mid.png │ ├── scrn1.png │ ├── scrn2.png │ ├── searchfield_leftcap.png │ ├── searchfield_repeat.png │ ├── searchfield_rightcap.png │ ├── title_background.png │ ├── toc.js │ ├── triangle_closed.png │ ├── triangle_left.png │ └── triangle_open.png ├── _templates │ └── layout.html ├── api.rst ├── conf.py ├── getting_started.rst ├── index.rst ├── installation.rst ├── make.bat ├── markup.rst ├── real_world_example.rst └── reference │ ├── index.rst │ ├── settings.rst │ └── template_tags.rst ├── docs ├── .buildinfo ├── _sources │ ├── api.txt │ ├── getting_started.txt │ ├── index.txt │ ├── installation.txt │ ├── markup.txt │ ├── real_world_example.txt │ └── reference │ │ ├── index.txt │ │ ├── settings.txt │ │ └── template_tags.txt ├── _static │ ├── basic.css │ ├── breadcrumb_background.png │ ├── default.css │ ├── doctools.js │ ├── documentation.png │ ├── file.png │ ├── header_sm_mid.png │ ├── jquery.js │ ├── minus.png │ ├── plus.png │ ├── pygments.css │ ├── scrn1.png │ ├── scrn2.png │ ├── searchfield_leftcap.png │ ├── searchfield_repeat.png │ ├── searchfield_rightcap.png │ ├── searchtools.js │ ├── sidebar.js │ ├── title_background.png │ ├── toc.js │ ├── triangle_closed.png │ ├── triangle_left.png │ ├── triangle_open.png │ └── underscore.js ├── api.html ├── genindex.html ├── getting_started.html ├── index.html ├── installation.html ├── markup.html ├── objects.inv ├── real_world_example.html ├── reference │ ├── index.html │ ├── settings.html │ └── template_tags.html ├── search.html └── searchindex.js ├── example ├── __init__.py ├── manage.py ├── media │ └── static │ │ ├── css │ │ └── supertagloading.css │ │ └── js │ │ └── jquery.loading.1.6.4.min.js ├── settings.py ├── templates │ ├── admin │ │ └── change_form.html │ ├── base.html │ └── flatpages │ │ └── default.html └── urls.py ├── requirements.txt ├── setup.py └── supertagging ├── __init__.py ├── admin.py ├── calais.py ├── fields.py ├── handlers.py ├── management ├── __init__.py └── commands │ ├── __init__.py │ ├── st_migrate_pickled_object_fields.py │ └── st_process_queue.py ├── managers.py ├── markup.py ├── migrations ├── 0001_initial.py ├── 0002_auto__add_field_supertaggeditem_ignore.py └── __init__.py ├── models.py ├── modules └── __init__.py ├── settings.py ├── sql ├── add_display_fields.sql ├── supertaggeditem.sql └── supertaggedrelation_item_date.sql ├── static ├── css │ └── supertagloading.css └── js │ └── jquery.loading.1.6.4.min.js ├── templates ├── admin │ └── supertagging │ │ ├── relevancebar.css │ │ ├── relevancebar.html │ │ └── supertaggeditem │ │ ├── change_list.html │ │ ├── change_list_results.html │ │ └── pagination.html └── supertagging │ ├── markup.html │ └── render │ ├── relations │ └── default.html │ ├── tagged_items │ └── default.html │ ├── tagged_relations │ └── default.html │ └── tags │ └── default.html ├── templatetags ├── __init__.py └── supertagging_tags.py ├── tests.py └── utils.py /.gitignore: -------------------------------------------------------------------------------- 1 | *.pyc 2 | dev.db 3 | local_settings.py 4 | media/ugc 5 | docs/_build/ 6 | src/ 7 | pip-log.txt 8 | media/js/*.r*.js 9 | media/css/*.r*.css 10 | *DS_Store 11 | *.egg-info 12 | build/ 13 | dist/ 14 | -------------------------------------------------------------------------------- /AUTHORS: -------------------------------------------------------------------------------- 1 | Project leader(s): 2 | 3 | * Jose Soares (jsoares@washingtontimes.com) 4 | 5 | Project member(s): 6 | 7 | * Corey Oordt (coordt@washingtontimes.com) 8 | * Justin Quick (jquick@washingtontimes.com) 9 | * Jonathan Hensley (jhensley@washingtontimes.com) -------------------------------------------------------------------------------- /MANIFEST.in: -------------------------------------------------------------------------------- 1 | include AUTHORS 2 | include LICENSE 3 | include NOTICE 4 | include README 5 | include requirements.txt 6 | 7 | recursive-include doc_src *.rst *.html *.css *.js *.png 8 | recursive-include docs *.html *.css *.js *.png 9 | recursive-include supertagging/static *.css *.js 10 | 11 | recursive-include supertagging *.py 12 | recursive-include supertagging/sql/ *.sql 13 | recursive-include supertagging/templates/ *.html 14 | 15 | prune example -------------------------------------------------------------------------------- /NOTICE: -------------------------------------------------------------------------------- 1 | Django-Supertagging 2 | Copyright 2009 The Washington Times 3 | 4 | The product includes software developed at The Washington Times (opensource.washingtontimes.com) 5 | 6 | Some code base based on Django Tagging. 7 | 8 | Django Tagging 9 | -------------- 10 | 11 | Copyright (c) 2007, Jonathan Buchanan 12 | 13 | Permission is hereby granted, free of charge, to any person obtaining a copy of 14 | this software and associated documentation files (the "Software"), to deal in 15 | the Software without restriction, including without limitation the rights to 16 | use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of 17 | the Software, and to permit persons to whom the Software is furnished to do so, 18 | subject to the following conditions: 19 | 20 | The above copyright notice and this permission notice shall be included in all 21 | copies or substantial portions of the Software. 22 | 23 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 24 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS 25 | FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR 26 | COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER 27 | IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 28 | CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 29 | 30 | Initially based on code from James Bennett's Cab: 31 | 32 | Cab 33 | --- 34 | 35 | Copyright (c) 2007, James Bennett 36 | All rights reserved. 37 | 38 | Redistribution and use in source and binary forms, with or without 39 | modification, are permitted provided that the following conditions are 40 | met: 41 | 42 | * Redistributions of source code must retain the above copyright 43 | notice, this list of conditions and the following disclaimer. 44 | * Redistributions in binary form must reproduce the above 45 | copyright notice, this list of conditions and the following 46 | disclaimer in the documentation and/or other materials provided 47 | with the distribution. 48 | * Neither the name of the author nor the names of other 49 | contributors may be used to endorse or promote products derived 50 | from this software without specific prior written permission. 51 | 52 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 53 | "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 54 | LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 55 | A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 56 | OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 57 | SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 58 | LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 59 | DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 60 | THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 61 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 62 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -------------------------------------------------------------------------------- /README: -------------------------------------------------------------------------------- 1 | Django SuperTagging 2 | 3 | Inspired by django-tagging, this project came up when we wanted to 4 | automate content tagging. Using OpenCalais service we are able to retrieve 5 | a large array of data, including basic entities (tags) and relations (attributes 6 | about the tag). 7 | 8 | Prerequisites 9 | - simplejson ( http://pypi.python.org/pypi/simplejson ) 10 | 11 | 12 | -------------------------------------------------------------------------------- /doc_src/Makefile: -------------------------------------------------------------------------------- 1 | # Makefile for Sphinx documentation 2 | # 3 | 4 | # You can set these variables from the command line. 5 | SPHINXOPTS = -a 6 | SPHINXBUILD = sphinx-build 7 | PAPER = 8 | BUILDDIR = _build 9 | DESTDIR = .. 10 | 11 | # Internal variables. 12 | PAPEROPT_a4 = -D latex_paper_size=a4 13 | PAPEROPT_letter = -D latex_paper_size=letter 14 | ALLSPHINXOPTS = -d $(BUILDDIR)/doctrees $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) . 15 | 16 | .PHONY: help clean html dirhtml pickle json htmlhelp qthelp latex changes linkcheck doctest 17 | 18 | help: 19 | @echo "Please use \`make ' where is one of" 20 | @echo " html to make standalone HTML files" 21 | @echo " dirhtml to make HTML files named index.html in directories" 22 | @echo " pickle to make pickle files" 23 | @echo " json to make JSON files" 24 | @echo " htmlhelp to make HTML files and a HTML help project" 25 | @echo " qthelp to make HTML files and a qthelp project" 26 | @echo " latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter" 27 | @echo " changes to make an overview of all changed/added/deprecated items" 28 | @echo " linkcheck to check all external links for integrity" 29 | @echo " doctest to run all doctests embedded in the documentation (if enabled)" 30 | 31 | clean: 32 | -rm -rf $(BUILDDIR)/* 33 | 34 | html: 35 | $(SPHINXBUILD) -b html $(ALLSPHINXOPTS) $(DESTDIR)/docs 36 | @echo 37 | @echo "Build finished. The HTML pages are in $(DESTDIR)/docs." 38 | 39 | dirhtml: 40 | $(SPHINXBUILD) -b dirhtml $(ALLSPHINXOPTS) $(BUILDDIR)/dirhtml 41 | @echo 42 | @echo "Build finished. The HTML pages are in $(BUILDDIR)/dirhtml." 43 | 44 | pickle: 45 | $(SPHINXBUILD) -b pickle $(ALLSPHINXOPTS) $(BUILDDIR)/pickle 46 | @echo 47 | @echo "Build finished; now you can process the pickle files." 48 | 49 | json: 50 | $(SPHINXBUILD) -b json $(ALLSPHINXOPTS) $(BUILDDIR)/json 51 | @echo 52 | @echo "Build finished; now you can process the JSON files." 53 | 54 | htmlhelp: 55 | $(SPHINXBUILD) -b htmlhelp $(ALLSPHINXOPTS) $(BUILDDIR)/htmlhelp 56 | @echo 57 | @echo "Build finished; now you can run HTML Help Workshop with the" \ 58 | ".hhp project file in $(BUILDDIR)/htmlhelp." 59 | 60 | qthelp: 61 | $(SPHINXBUILD) -b qthelp $(ALLSPHINXOPTS) $(BUILDDIR)/qthelp 62 | @echo 63 | @echo "Build finished; now you can run "qcollectiongenerator" with the" \ 64 | ".qhcp project file in $(BUILDDIR)/qthelp, like this:" 65 | @echo "# qcollectiongenerator $(BUILDDIR)/qthelp/app.qhcp" 66 | @echo "To view the help file:" 67 | @echo "# assistant -collectionFile $(BUILDDIR)/qthelp/app.qhc" 68 | 69 | latex: 70 | $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex 71 | @echo 72 | @echo "Build finished; the LaTeX files are in $(BUILDDIR)/latex." 73 | @echo "Run \`make all-pdf' or \`make all-ps' in that directory to" \ 74 | "run these through (pdf)latex." 75 | 76 | changes: 77 | $(SPHINXBUILD) -b changes $(ALLSPHINXOPTS) $(BUILDDIR)/changes 78 | @echo 79 | @echo "The overview file is in $(BUILDDIR)/changes." 80 | 81 | linkcheck: 82 | $(SPHINXBUILD) -b linkcheck $(ALLSPHINXOPTS) $(BUILDDIR)/linkcheck 83 | @echo 84 | @echo "Link check complete; look for any errors in the above output " \ 85 | "or in $(BUILDDIR)/linkcheck/output.txt." 86 | 87 | doctest: 88 | $(SPHINXBUILD) -b doctest $(ALLSPHINXOPTS) $(BUILDDIR)/doctest 89 | @echo "Testing of doctests in the sources finished, look at the " \ 90 | "results in $(BUILDDIR)/doctest/output.txt." 91 | -------------------------------------------------------------------------------- /doc_src/_build/doctrees/api.doctree: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/callowayproject/django-supertagging/9b7d70343c2ff72e8f6dc971f6b873e1777ecc6c/doc_src/_build/doctrees/api.doctree -------------------------------------------------------------------------------- /doc_src/_build/doctrees/environment.pickle: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/callowayproject/django-supertagging/9b7d70343c2ff72e8f6dc971f6b873e1777ecc6c/doc_src/_build/doctrees/environment.pickle -------------------------------------------------------------------------------- /doc_src/_build/doctrees/getting_started.doctree: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/callowayproject/django-supertagging/9b7d70343c2ff72e8f6dc971f6b873e1777ecc6c/doc_src/_build/doctrees/getting_started.doctree -------------------------------------------------------------------------------- /doc_src/_build/doctrees/index.doctree: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/callowayproject/django-supertagging/9b7d70343c2ff72e8f6dc971f6b873e1777ecc6c/doc_src/_build/doctrees/index.doctree -------------------------------------------------------------------------------- /doc_src/_build/doctrees/installation.doctree: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/callowayproject/django-supertagging/9b7d70343c2ff72e8f6dc971f6b873e1777ecc6c/doc_src/_build/doctrees/installation.doctree -------------------------------------------------------------------------------- /doc_src/_build/doctrees/markup.doctree: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/callowayproject/django-supertagging/9b7d70343c2ff72e8f6dc971f6b873e1777ecc6c/doc_src/_build/doctrees/markup.doctree -------------------------------------------------------------------------------- /doc_src/_build/doctrees/real_world_example.doctree: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/callowayproject/django-supertagging/9b7d70343c2ff72e8f6dc971f6b873e1777ecc6c/doc_src/_build/doctrees/real_world_example.doctree -------------------------------------------------------------------------------- /doc_src/_build/doctrees/reference/index.doctree: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/callowayproject/django-supertagging/9b7d70343c2ff72e8f6dc971f6b873e1777ecc6c/doc_src/_build/doctrees/reference/index.doctree -------------------------------------------------------------------------------- /doc_src/_build/doctrees/reference/settings.doctree: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/callowayproject/django-supertagging/9b7d70343c2ff72e8f6dc971f6b873e1777ecc6c/doc_src/_build/doctrees/reference/settings.doctree -------------------------------------------------------------------------------- /doc_src/_build/doctrees/reference/template_tags.doctree: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/callowayproject/django-supertagging/9b7d70343c2ff72e8f6dc971f6b873e1777ecc6c/doc_src/_build/doctrees/reference/template_tags.doctree -------------------------------------------------------------------------------- /doc_src/_static/breadcrumb_background.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/callowayproject/django-supertagging/9b7d70343c2ff72e8f6dc971f6b873e1777ecc6c/doc_src/_static/breadcrumb_background.png -------------------------------------------------------------------------------- /doc_src/_static/documentation.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/callowayproject/django-supertagging/9b7d70343c2ff72e8f6dc971f6b873e1777ecc6c/doc_src/_static/documentation.png -------------------------------------------------------------------------------- /doc_src/_static/header_sm_mid.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/callowayproject/django-supertagging/9b7d70343c2ff72e8f6dc971f6b873e1777ecc6c/doc_src/_static/header_sm_mid.png -------------------------------------------------------------------------------- /doc_src/_static/scrn1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/callowayproject/django-supertagging/9b7d70343c2ff72e8f6dc971f6b873e1777ecc6c/doc_src/_static/scrn1.png -------------------------------------------------------------------------------- /doc_src/_static/scrn2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/callowayproject/django-supertagging/9b7d70343c2ff72e8f6dc971f6b873e1777ecc6c/doc_src/_static/scrn2.png -------------------------------------------------------------------------------- /doc_src/_static/searchfield_leftcap.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/callowayproject/django-supertagging/9b7d70343c2ff72e8f6dc971f6b873e1777ecc6c/doc_src/_static/searchfield_leftcap.png -------------------------------------------------------------------------------- /doc_src/_static/searchfield_repeat.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/callowayproject/django-supertagging/9b7d70343c2ff72e8f6dc971f6b873e1777ecc6c/doc_src/_static/searchfield_repeat.png -------------------------------------------------------------------------------- /doc_src/_static/searchfield_rightcap.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/callowayproject/django-supertagging/9b7d70343c2ff72e8f6dc971f6b873e1777ecc6c/doc_src/_static/searchfield_rightcap.png -------------------------------------------------------------------------------- /doc_src/_static/title_background.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/callowayproject/django-supertagging/9b7d70343c2ff72e8f6dc971f6b873e1777ecc6c/doc_src/_static/title_background.png -------------------------------------------------------------------------------- /doc_src/_static/toc.js: -------------------------------------------------------------------------------- 1 | var TOC = { 2 | load: function () { 3 | $('#toc_button').click(TOC.toggle); 4 | }, 5 | 6 | toggle: function () { 7 | if ($('#sphinxsidebar').toggle().is(':hidden')) { 8 | $('div.document').css('left', "0px"); 9 | $('toc_button').removeClass("open"); 10 | } else { 11 | $('div.document').css('left', "230px"); 12 | $('#toc_button').addClass("open"); 13 | } 14 | return $('#sphinxsidebar'); 15 | } 16 | }; 17 | 18 | $(document).ready(function () { 19 | TOC.load(); 20 | }); -------------------------------------------------------------------------------- /doc_src/_static/triangle_closed.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/callowayproject/django-supertagging/9b7d70343c2ff72e8f6dc971f6b873e1777ecc6c/doc_src/_static/triangle_closed.png -------------------------------------------------------------------------------- /doc_src/_static/triangle_left.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/callowayproject/django-supertagging/9b7d70343c2ff72e8f6dc971f6b873e1777ecc6c/doc_src/_static/triangle_left.png -------------------------------------------------------------------------------- /doc_src/_static/triangle_open.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/callowayproject/django-supertagging/9b7d70343c2ff72e8f6dc971f6b873e1777ecc6c/doc_src/_static/triangle_open.png -------------------------------------------------------------------------------- /doc_src/_templates/layout.html: -------------------------------------------------------------------------------- 1 | {% extends "basic/layout.html" %} 2 | {%- block doctype -%} 3 | 5 | {%- endblock %} 6 | {%- set reldelim1 = reldelim1 is not defined and ' »' or reldelim1 %} 7 | {%- set reldelim2 = reldelim2 is not defined and ' |' or reldelim2 %} 8 | {%- block linktags %} 9 | {%- if hasdoc('about') %} 10 | 11 | {%- endif %} 12 | {%- if hasdoc('genindex') %} 13 | 14 | {%- endif %} 15 | {%- if hasdoc('search') %} 16 | 17 | {%- endif %} 18 | {%- if hasdoc('copyright') %} 19 | 20 | {%- endif %} 21 | 22 | {%- if parents %} 23 | 24 | {%- endif %} 25 | {%- if next %} 26 | 27 | {%- endif %} 28 | {%- if prev %} 29 | 30 | {%- endif %} 31 | {%- endblock %} 32 | {%- block extrahead %} {% endblock %} 33 | {%- block header %}{% endblock %} 34 | {%- block relbar1 %} 35 |
36 |

{{docstitle}}

37 |
38 | 49 | {% endblock %} 50 | 51 | {%- block sidebar1 %} 52 | {%- if not embedded %}{% if not theme_nosidebar|tobool %} 53 |
54 |
55 | {%- block sidebarlogo %} 56 | {%- if logo %} 57 | 60 | {%- endif %} 61 | {%- endblock %} 62 | {%- block sidebartoc %} 63 | 64 | {{ toctree() }} 65 | {%- endblock %} 66 | {%- block sidebarrel %} 67 | {%- endblock %} 68 | {%- block sidebarsourcelink %} 69 | {%- if show_source and has_source and sourcename %} 70 |

{{ _('This Page') }}

71 | 75 | {%- endif %} 76 | {%- endblock %} 77 | {%- if customsidebar %} 78 | {% include customsidebar %} 79 | {%- endif %} 80 | {%- block sidebarsearch %} 81 | {%- if pagename != "search" %} 82 | 98 | 99 | {%- endif %} 100 | {%- endblock %} 101 |
102 |
103 | {%- endif %}{% endif %} 104 | 105 | {% endblock %} 106 | {%- block document %} 107 |
108 | {%- if not embedded %}{% if not theme_nosidebar|tobool %} 109 |
110 | {%- endif %}{% endif %} 111 |
112 | {% block body %} {% endblock %} 113 |
114 | {%- if not embedded %}{% if not theme_nosidebar|tobool %} 115 |
116 | {%- endif %}{% endif %} 117 |
118 | 132 | {%- endblock %} 133 | {%- block sidebar2 %}{% endblock %} 134 | {%- block relbar2 %}{% endblock %} 135 | {%- block footer %} 136 | 143 | 144 | {%- endblock %} 145 | -------------------------------------------------------------------------------- /doc_src/api.rst: -------------------------------------------------------------------------------- 1 | .. _api: 2 | 3 | API Reference 4 | ============= 5 | 6 | .. contents:: 7 | :depth: 3 8 | 9 | .. _api_supertag: 10 | 11 | SuperTag 12 | ******** 13 | 14 | Fields 15 | ------ 16 | 17 | * **calais_id** - Contains the OpenCalais entity ID 18 | * CharField 19 | * Length: 255 20 | * Unique 21 | * **substitute** - Substitute tags in order to have better disambiguation. 22 | * ForeignKey to self 23 | * null=True, blank=True 24 | * **name** - The tag name. 25 | * CharField 26 | * Length: 150 27 | * **slug** - Slugified name 28 | * SlugField 29 | * Length: 150 30 | * **stype** - Tag type as returned by OpenCalais 31 | * CharField 32 | * Length: 100 33 | * **properties** - Tag properties as returned by OpenCalais 34 | * `PickledObjectField `_ 35 | * null=True, blank=True 36 | * **enabled** - Weather or not this tag is used. 37 | * BooleanField 38 | * Default: True 39 | 40 | Optional Fields 41 | --------------- 42 | 43 | If :ref:`setting_include_display_fields` is True, these fields will be 44 | included with the model. 45 | 46 | * **display_name** - Name used for display purposes. Since all SuperTag name are lowered when returned from calais, we can use this field to set the case correctly for example 47 | * CharField 48 | * Length: 150 49 | * null=True, blank=True 50 | * **description** - Description of the tag 51 | * TextField 52 | * null=True, blank=True 53 | * **icon** - Image field for the tag 54 | * ImageField 55 | * null=True, blank=True 56 | * **related** - Manually relating tags 57 | * ManyToManyField to self 58 | * null=True, blank=True 59 | 60 | 61 | Methods 62 | ------- 63 | 64 | get_name 65 | ~~~~~~~~ 66 | 67 | Gets the name of the tag, this will try to retrieve the display name first 68 | if the display fields are available, if the display fields are not available 69 | the normal name will be returned. 70 | 71 | has_display_fields 72 | ~~~~~~~~~~~~~~~~~~ 73 | 74 | Returns True or False, if the display fields are available. 75 | 76 | render 77 | ~~~~~~ 78 | 79 | Renders the instance, view :ref:`render` for more information. 80 | 81 | .. _api_supertagrelation: 82 | 83 | SuperTagRelation 84 | **************** 85 | 86 | Fields 87 | ------ 88 | 89 | * **tag** - The associated tag 90 | * ForeignKey to :ref:`api_supertag` 91 | * **stype** - The type of relation 92 | * CharField 93 | * Length: 100 94 | * **name** - Name of the relation 95 | * CharField 96 | * Length: 150 97 | * **properties** - Relation properties returned by OpenCalais 98 | * `PickledObjectField `_ 99 | * null=True, blank=True 100 | 101 | Methods 102 | ------- 103 | 104 | render 105 | ~~~~~~ 106 | 107 | Renders the instance, view :ref:`render` for more information. 108 | 109 | 110 | .. _api_supertaggeditem: 111 | 112 | SuperTaggedItem 113 | *************** 114 | 115 | Generic relation to a :ref:`api_supertag` 116 | 117 | Fields 118 | ------ 119 | 120 | * **tag** - The associated tag 121 | * ForeignKey to :ref:`api_supertag` 122 | * **content_type** - Content type of an object 123 | * ForeignKey to `django.contrib.contenttypes.models.ContentType` 124 | * **object_id** - Instance primary key 125 | * PositiveIntegerField 126 | * **content_object** - Gernric relation 127 | * GenericForeignKey to content_type and object_id 128 | * **field** - The name of the field this instance refers to 129 | * CharField 130 | * Length: 100 131 | * **process_type** - The type used to process the data, "TEXT/HTML", "TEXT/RAW" or "TEXT/XML" 132 | * CharField 133 | * Length: 10 134 | * null=True, blank=True 135 | * **relevance** - The relevance score 136 | * IntegerField 137 | * null=True, blank=True 138 | * **instances** - Contains a list of all the tags found in the content. 139 | * `PickledObjectField `_ 140 | * null=True, blank=True 141 | * **item_date** - Date of the object 142 | * DateTimeField 143 | * null=True, blank=True 144 | 145 | Methods 146 | ------- 147 | 148 | render 149 | ~~~~~~ 150 | 151 | Renders the instance, view :ref:`render` for more information. 152 | 153 | .. _api_supertaggedrelationitem: 154 | 155 | SuperTaggedRelationItem 156 | *********************** 157 | 158 | Fields 159 | ------ 160 | 161 | * **relation** - Associated relation 162 | * ForignKey to :ref:`api_supertagrelation` 163 | * **content_type** - Content type of an object 164 | * ForeignKey to `django.contrib.contenttypes.models.ContentType` 165 | * **object_id** - Instance primary key 166 | * PositiveIntegerField 167 | * **content_object** - Gernric relation 168 | * GenericForeignKey to content_type and object_id 169 | * **field** - The name of the field this instance refers to 170 | * CharField 171 | * Length: 100 172 | * **process_type** - The type used to process the data, "TEXT/HTML", "TEXT/RAW" or "TEXT/XML" 173 | * CharField 174 | * Length: 10 175 | * null=True, blank=True 176 | * **instances** - Contains a list of all the tags found in the content. 177 | * `PickledObjectField `_ 178 | * null=True, blank=True 179 | * **item_date** - Date of the object 180 | * DateTimeField 181 | * null=True, blank=True 182 | 183 | Methods 184 | ------- 185 | 186 | render 187 | ~~~~~~ 188 | 189 | Renders the instance, view :ref:`render` for more information. 190 | 191 | .. _api_supertagprocessqueue: 192 | 193 | SuperTagProcessQueue 194 | ******************** 195 | 196 | Holds a generic relation to an object to be processed at a later time, this 197 | model is only used when :ref:`setting_use_queue` is set to `True` 198 | 199 | Fields 200 | ------ 201 | 202 | * **content_type** - Content type of an object 203 | * ForeignKey to `django.contrib.contenttypes.models.ContentType` 204 | * **object_id** - Instance primary key 205 | * PositiveIntegerField 206 | * **content_object** - Gernric relation 207 | * GenericForeignKey to content_type and object_id 208 | * **locked** - Weather the object is being processed 209 | * BooleanField 210 | * Default: False 211 | 212 | 213 | .. _render: 214 | 215 | Rendering Items 216 | *************** 217 | 218 | :ref:`api_supertag`, :ref:`api_supertaggeditem`, :ref:`api_supertagrelation` 219 | and :ref:`api_supertaggedrelationitem` have a `render` method in order to 220 | correctly display its contents. 221 | 222 | Template Locations 223 | ------------------ 224 | 225 | Default location for these templates are in `supertagging/templates/render`. 226 | For each model there is an additional folder: 227 | 228 | * SuperTag: "tags/" 229 | * SuperTaggedItem: "tagged_items/" 230 | * SuperTagRelation: "relations/" 231 | * SuperTaggedRelationItem: "tagged_relations/" 232 | 233 | For example the default template for a SuperTaggedItem would be 234 | "supertagging/templates/render/tagged_items/default.html" 235 | 236 | This default template is the last resort, below is a detail list of template 237 | paths that will be checked first 238 | 239 | 1. template argument - this is a full path starting in your templates dir 240 | 2. template_path + `stype` + `app` + `model` + `suffix` - for :ref:`api_supertag` and :ref:`api_supertagrelation` a type, model, app and suffix will be added. 241 | * supertagging/render/tags//____.html 242 | * supertagging/render/tags/people/stories__story__custom.html 243 | 3. template_path + `stype` + `app` + `model` - Same as above but without the suffix 244 | * supertagging/render/tags/people/stories__story.html 245 | 4. template_path + `stype` + default + `suffix` - Same as #2 except not `app` and `model` 246 | * supertagging/render/tags/people/default__custom.html 247 | 5. template_path + `stype` + default - Same as #4 except without the suffix 248 | * supertagging/render/tags/people/default.html 249 | 6. template_path + default - the last possible path to look for the template 250 | * supertagging/render/tags/default.html 251 | 252 | .. note:: 253 | 254 | As stated in #2 of the list above, `stype` only applies to :ref:`api_supertag` and :ref:`api_supertagrelation` 255 | since :ref:`api_supertaggeditem` and :ref:`api_supertaggedrelationitem` 256 | doesn't contain the `stype` field. It will simply not be part of the path. 257 | 258 | Template Context 259 | ---------------- 260 | 261 | :ref:`api_supertag` and :ref:`api_supertagrelation` has only it self returned 262 | in the context 263 | 264 | * **obj** - self 265 | 266 | :ref:`api_supertaggeditem` and :ref:`api_supertaggedrelationitem` has 2 conext 267 | variables 268 | 269 | * **obj** - the generic related item 270 | * **content** - self -------------------------------------------------------------------------------- /doc_src/conf.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # 3 | # app documentation build configuration file, created by 4 | # sphinx-quickstart on Wed Oct 21 13:18:22 2009. 5 | # 6 | # This file is execfile()d with the current directory set to its containing dir. 7 | # 8 | # Note that not all possible configuration values are present in this 9 | # autogenerated file. 10 | # 11 | # All configuration values have a default; values that are commented out 12 | # serve to show the default. 13 | 14 | import sys, os 15 | 16 | # If extensions (or modules to document with autodoc) are in another directory, 17 | # add these directories to sys.path here. If the directory is relative to the 18 | # documentation root, use os.path.abspath to make it absolute, like shown here. 19 | sys.path.append(os.path.abspath('..')) 20 | os.environ['DJANGO_SETTINGS_MODULE'] = 'example.settings' 21 | import supertagging 22 | # -- General configuration ----------------------------------------------------- 23 | 24 | # Add any Sphinx extension module names here, as strings. They can be extensions 25 | # coming with Sphinx (named 'sphinx.ext.*') or your custom ones. 26 | extensions = ['sphinx.ext.autodoc'] 27 | 28 | # Add any paths that contain templates here, relative to this directory. 29 | templates_path = ['_templates'] 30 | 31 | # The suffix of source filenames. 32 | source_suffix = '.rst' 33 | 34 | # The encoding of source files. 35 | #source_encoding = 'utf-8' 36 | 37 | # The master toctree document. 38 | master_doc = 'index' 39 | 40 | # General information about the project. 41 | project = u'Django SuperTagging' 42 | copyright = u'2010, The Washington Times' 43 | 44 | # The version info for the project you're documenting, acts as replacement for 45 | # |version| and |release|, also used in various other places throughout the 46 | # built documents. 47 | # 48 | # The short X.Y version. 49 | version = supertagging.__version__ 50 | # The full version, including alpha/beta/rc tags. 51 | release = supertagging.__version__ 52 | 53 | # The language for content autogenerated by Sphinx. Refer to documentation 54 | # for a list of supported languages. 55 | #language = None 56 | 57 | # There are two options for replacing |today|: either, you set today to some 58 | # non-false value, then it is used: 59 | #today = '' 60 | # Else, today_fmt is used as the format for a strftime call. 61 | #today_fmt = '%B %d, %Y' 62 | 63 | # List of documents that shouldn't be included in the build. 64 | #unused_docs = [] 65 | 66 | # List of directories, relative to source directory, that shouldn't be searched 67 | # for source files. 68 | exclude_trees = ['_build'] 69 | 70 | # The reST default role (used for this markup: `text`) to use for all documents. 71 | #default_role = None 72 | 73 | # If true, '()' will be appended to :func: etc. cross-reference text. 74 | #add_function_parentheses = True 75 | 76 | # If true, the current module name will be prepended to all description 77 | # unit titles (such as .. function::). 78 | #add_module_names = True 79 | 80 | # If true, sectionauthor and moduleauthor directives will be shown in the 81 | # output. They are ignored by default. 82 | #show_authors = False 83 | 84 | # The name of the Pygments (syntax highlighting) style to use. 85 | pygments_style = 'sphinx' 86 | 87 | # A list of ignored prefixes for module index sorting. 88 | #modindex_common_prefix = [] 89 | 90 | 91 | # -- Options for HTML output --------------------------------------------------- 92 | 93 | # The theme to use for HTML and HTML Help pages. Major themes that come with 94 | # Sphinx are currently 'default' and 'sphinxdoc'. 95 | html_theme = 'default' 96 | 97 | # Theme options are theme-specific and customize the look and feel of a theme 98 | # further. For a list of options available for each theme, see the 99 | # documentation. 100 | #html_theme_options = {} 101 | 102 | # Add any paths that contain custom themes here, relative to this directory. 103 | #html_theme_path = [] 104 | 105 | # The name for this set of Sphinx documents. If None, it defaults to 106 | # " v documentation". 107 | #html_title = None 108 | 109 | # A shorter title for the navigation bar. Default is the same as html_title. 110 | #html_short_title = None 111 | 112 | # The name of an image file (relative to this directory) to place at the top 113 | # of the sidebar. 114 | #html_logo = None 115 | 116 | # The name of an image file (within the static path) to use as favicon of the 117 | # docs. This file should be a Windows icon file (.ico) being 16x16 or 32x32 118 | # pixels large. 119 | #html_favicon = None 120 | 121 | # Add any paths that contain custom static files (such as style sheets) here, 122 | # relative to this directory. They are copied after the builtin static files, 123 | # so a file named "default.css" will overwrite the builtin "default.css". 124 | html_static_path = ['_static'] 125 | 126 | # If not '', a 'Last updated on:' timestamp is inserted at every page bottom, 127 | # using the given strftime format. 128 | #html_last_updated_fmt = '%b %d, %Y' 129 | 130 | # If true, SmartyPants will be used to convert quotes and dashes to 131 | # typographically correct entities. 132 | #html_use_smartypants = True 133 | 134 | # Custom sidebar templates, maps document names to template names. 135 | #html_sidebars = {} 136 | 137 | # Additional templates that should be rendered to pages, maps page names to 138 | # template names. 139 | #html_additional_pages = {} 140 | 141 | # If false, no module index is generated. 142 | #html_use_modindex = True 143 | 144 | # If false, no index is generated. 145 | #html_use_index = True 146 | 147 | # If true, the index is split into individual pages for each letter. 148 | #html_split_index = False 149 | 150 | # If true, links to the reST sources are added to the pages. 151 | html_show_sourcelink = False 152 | 153 | # If true, an OpenSearch description file will be output, and all pages will 154 | # contain a tag referring to it. The value of this option must be the 155 | # base URL from which the finished HTML is served. 156 | #html_use_opensearch = '' 157 | 158 | # If nonempty, this is the file name suffix for HTML files (e.g. ".xhtml"). 159 | #html_file_suffix = '' 160 | 161 | # Output file base name for HTML help builder. 162 | htmlhelp_basename = 'DjangoSuperTaggingdoc' 163 | 164 | 165 | # -- Options for LaTeX output -------------------------------------------------- 166 | 167 | # The paper size ('letter' or 'a4'). 168 | #latex_paper_size = 'letter' 169 | 170 | # The font size ('10pt', '11pt' or '12pt'). 171 | #latex_font_size = '10pt' 172 | 173 | # Grouping the document tree into LaTeX files. List of tuples 174 | # (source start file, target name, title, author, documentclass [howto/manual]). 175 | latex_documents = [ 176 | ('index', 'app.tex', u'$$$$APP_NAME$$$$ Documentation', 177 | u'me', 'manual'), 178 | ] 179 | 180 | # The name of an image file (relative to this directory) to place at the top of 181 | # the title page. 182 | #latex_logo = None 183 | 184 | # For "manual" documents, if this is true, then toplevel headings are parts, 185 | # not chapters. 186 | #latex_use_parts = False 187 | 188 | # Additional stuff for the LaTeX preamble. 189 | #latex_preamble = '' 190 | 191 | # Documents to append as an appendix to all manuals. 192 | #latex_appendices = [] 193 | 194 | # If false, no module index is generated. 195 | #latex_use_modindex = True 196 | -------------------------------------------------------------------------------- /doc_src/getting_started.rst: -------------------------------------------------------------------------------- 1 | .. _getting_started: 2 | 3 | Getting Started 4 | =============== 5 | 6 | If you have not installed SuperTagging yet, go to the :ref:`installation` page. 7 | 8 | Create basic settings 9 | ********************* 10 | 11 | In your ``settings.py`` file: 12 | 13 | .. code-block:: python 14 | 15 | SUPERTAGGING_SETTINGS = { 16 | 'ENABLED': True, 17 | 'DEBUG': True, 18 | } 19 | 20 | 21 | Setting up OpenCalais API 22 | ************************* 23 | 24 | Go to `OpenCalais `_'s website and register for 25 | an api key, and in your ``settings.py`` file, alter ``SUPERTAGGING_SETTINGS``\ : 26 | 27 | .. code-block:: python 28 | 29 | SUPERTAGGING_SETTINGS = { 30 | 'ENABLED': True, 31 | 'DEBUG': True, 32 | 'OPEN_CALAIS': { 33 | 'API_KEY': 'YOUR_API_KEY', 34 | } 35 | } 36 | 37 | 38 | Setting up models to be tagged 39 | ****************************** 40 | 41 | You will need to decide which models and which fields in those models you 42 | will want SuperTagging to mark for tagging: 43 | 44 | .. code-block:: python 45 | 46 | SUPERTAGGING_SETTINGS = { 47 | 'ENABLED': True, 48 | 'DEBUG': True, 49 | 'OPEN_CALAIS': { 50 | 'API_KEY': 'YOUR_API_KEY', 51 | }, 52 | 'WATCHED_FIELDS': { 53 | 'stories.story': { 54 | 'fields':[ 55 | {'name': 'body'}, 56 | ], 57 | }, 58 | }, 59 | } 60 | 61 | 62 | The code above tells SuperTagging to tag the **body** field of model 63 | **stories.story**. We can specify any number of fields and models as well. 64 | 65 | .. code-block:: python 66 | 67 | SUPERTAGGING_SETTINGS = { 68 | 'ENABLED': True, 69 | 'DEBUG': True, 70 | 'OPEN_CALAIS': { 71 | 'API_KEY': 'YOUR_API_KEY', 72 | }, 73 | 'WATCHED_FIELDS': { 74 | 'stories.story': { 75 | 'fields':[ 76 | {'name': 'body'}, 77 | {'name': 'tease'}, 78 | {'name': 'kicker'}, 79 | ], 80 | }, 81 | 'media.image': { 82 | 'fields':[ 83 | {'name': 'caption'}, 84 | {'name': 'description'}, 85 | ], 86 | } 87 | }, 88 | } 89 | 90 | 91 | View :ref:`setting_modules` for more information. 92 | 93 | Set up automatic processing 94 | *************************** 95 | 96 | Finally, add: 97 | 98 | .. code-block:: python 99 | 100 | SUPERTAGGING_SETTINGS = { 101 | 'ENABLED': True, 102 | 'DEBUG': True, 103 | 'OPEN_CALAIS': { 104 | 'API_KEY': 'YOUR_API_KEY', 105 | }, 106 | 'WATCHED_FIELDS': { 107 | 'stories.story': { 108 | 'fields':[ 109 | {'name': 'body'}, 110 | ], 111 | }, 112 | }, 113 | 'AUTO_PROCESS': True, 114 | } 115 | 116 | Post save and post delete signals will be connected to the models 117 | specified in `WATCHED_FIELDS`. Visit :ref:`reference_settings` to 118 | view more details about the SuperTagging settings 119 | 120 | View the complete list of :ref:`reference_settings` 121 | 122 | Conclusion 123 | ********** 124 | 125 | That is all that is needed to get SuperTagging to start tagging your data. 126 | Upon saving a instance of one of the models specified in 127 | `SUPERTAGGING_MODULES`, the field(s) data will be sent to OpenCalais 128 | for processing. 129 | 130 | 131 | Next step: View the :ref:`real_world_example` section of how The Washington 132 | Times has SuperTagging setup. -------------------------------------------------------------------------------- /doc_src/index.rst: -------------------------------------------------------------------------------- 1 | .. app documentation master file, created by 2 | sphinx-quickstart on Wed Oct 21 13:18:22 2009. 3 | You can adapt this file completely to your liking, but it should at least 4 | contain the root `toctree` directive. 5 | 6 | Welcome to Django SuperTagging's documentation! 7 | =============================================== 8 | 9 | SuperTagging is an auto-tagging app using `OpenCalais `_, 10 | based off of `Django Tagging `_ 11 | 12 | Contents: 13 | 14 | .. toctree:: 15 | :maxdepth: 2 16 | :glob: 17 | 18 | installation 19 | getting_started 20 | real_world_example 21 | api 22 | markup 23 | 24 | reference/index 25 | 26 | Indices and tables 27 | ================== 28 | 29 | * :ref:`genindex` 30 | * :ref:`modindex` 31 | * :ref:`search` 32 | 33 | -------------------------------------------------------------------------------- /doc_src/installation.rst: -------------------------------------------------------------------------------- 1 | .. _installation: 2 | 3 | Installation 4 | ============ 5 | 6 | Download SuperTagging 7 | ********************* 8 | 9 | There are a couple ways for you to get Django-SuperTagging, 10 | 11 | 1. Clone the git repository `from GitHub `_ 12 | 2. Use pip to install it from `PyPI `_ 13 | 14 | :: 15 | 16 | pip install supertagging 17 | 18 | 19 | Dependencies 20 | ************ 21 | 22 | * `simplejson `_ *(Required)* 23 | * `freebase `_ *(Optional)* 24 | 25 | 26 | Add SuperTagging to your project 27 | ******************************** 28 | 29 | Add to INSTALLED_APPS 30 | 31 | .. code-block:: python 32 | 33 | INSTALLED_APPS = ( 34 | ... 35 | supertagging, 36 | ... 37 | ) 38 | 39 | Run syncdb:: 40 | 41 | >>> ./manage.py syncdb 42 | -------------------------------------------------------------------------------- /doc_src/make.bat: -------------------------------------------------------------------------------- 1 | @ECHO OFF 2 | 3 | REM Command file for Sphinx documentation 4 | 5 | set SPHINXBUILD=sphinx-build 6 | set BUILDDIR=_build 7 | set ALLSPHINXOPTS=-d %BUILDDIR%/doctrees %SPHINXOPTS% . 8 | if NOT "%PAPER%" == "" ( 9 | set ALLSPHINXOPTS=-D latex_paper_size=%PAPER% %ALLSPHINXOPTS% 10 | ) 11 | 12 | if "%1" == "" goto help 13 | 14 | if "%1" == "help" ( 15 | :help 16 | echo.Please use `make ^` where ^ is one of 17 | echo. html to make standalone HTML files 18 | echo. dirhtml to make HTML files named index.html in directories 19 | echo. pickle to make pickle files 20 | echo. json to make JSON files 21 | echo. htmlhelp to make HTML files and a HTML help project 22 | echo. qthelp to make HTML files and a qthelp project 23 | echo. latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter 24 | echo. changes to make an overview over all changed/added/deprecated items 25 | echo. linkcheck to check all external links for integrity 26 | echo. doctest to run all doctests embedded in the documentation if enabled 27 | goto end 28 | ) 29 | 30 | if "%1" == "clean" ( 31 | for /d %%i in (%BUILDDIR%\*) do rmdir /q /s %%i 32 | del /q /s %BUILDDIR%\* 33 | goto end 34 | ) 35 | 36 | if "%1" == "html" ( 37 | %SPHINXBUILD% -b html %ALLSPHINXOPTS% %BUILDDIR%/html 38 | echo. 39 | echo.Build finished. The HTML pages are in %BUILDDIR%/html. 40 | goto end 41 | ) 42 | 43 | if "%1" == "dirhtml" ( 44 | %SPHINXBUILD% -b dirhtml %ALLSPHINXOPTS% %BUILDDIR%/dirhtml 45 | echo. 46 | echo.Build finished. The HTML pages are in %BUILDDIR%/dirhtml. 47 | goto end 48 | ) 49 | 50 | if "%1" == "pickle" ( 51 | %SPHINXBUILD% -b pickle %ALLSPHINXOPTS% %BUILDDIR%/pickle 52 | echo. 53 | echo.Build finished; now you can process the pickle files. 54 | goto end 55 | ) 56 | 57 | if "%1" == "json" ( 58 | %SPHINXBUILD% -b json %ALLSPHINXOPTS% %BUILDDIR%/json 59 | echo. 60 | echo.Build finished; now you can process the JSON files. 61 | goto end 62 | ) 63 | 64 | if "%1" == "htmlhelp" ( 65 | %SPHINXBUILD% -b htmlhelp %ALLSPHINXOPTS% %BUILDDIR%/htmlhelp 66 | echo. 67 | echo.Build finished; now you can run HTML Help Workshop with the ^ 68 | .hhp project file in %BUILDDIR%/htmlhelp. 69 | goto end 70 | ) 71 | 72 | if "%1" == "qthelp" ( 73 | %SPHINXBUILD% -b qthelp %ALLSPHINXOPTS% %BUILDDIR%/qthelp 74 | echo. 75 | echo.Build finished; now you can run "qcollectiongenerator" with the ^ 76 | .qhcp project file in %BUILDDIR%/qthelp, like this: 77 | echo.^> qcollectiongenerator %BUILDDIR%\qthelp\app.qhcp 78 | echo.To view the help file: 79 | echo.^> assistant -collectionFile %BUILDDIR%\qthelp\app.ghc 80 | goto end 81 | ) 82 | 83 | if "%1" == "latex" ( 84 | %SPHINXBUILD% -b latex %ALLSPHINXOPTS% %BUILDDIR%/latex 85 | echo. 86 | echo.Build finished; the LaTeX files are in %BUILDDIR%/latex. 87 | goto end 88 | ) 89 | 90 | if "%1" == "changes" ( 91 | %SPHINXBUILD% -b changes %ALLSPHINXOPTS% %BUILDDIR%/changes 92 | echo. 93 | echo.The overview file is in %BUILDDIR%/changes. 94 | goto end 95 | ) 96 | 97 | if "%1" == "linkcheck" ( 98 | %SPHINXBUILD% -b linkcheck %ALLSPHINXOPTS% %BUILDDIR%/linkcheck 99 | echo. 100 | echo.Link check complete; look for any errors in the above output ^ 101 | or in %BUILDDIR%/linkcheck/output.txt. 102 | goto end 103 | ) 104 | 105 | if "%1" == "doctest" ( 106 | %SPHINXBUILD% -b doctest %ALLSPHINXOPTS% %BUILDDIR%/doctest 107 | echo. 108 | echo.Testing of doctests in the sources finished, look at the ^ 109 | results in %BUILDDIR%/doctest/output.txt. 110 | goto end 111 | ) 112 | 113 | :end 114 | -------------------------------------------------------------------------------- /doc_src/markup.rst: -------------------------------------------------------------------------------- 1 | .. _markup: 2 | 3 | Markup 4 | ====== 5 | 6 | This is a way to populate your content with extra content in relation to the 7 | tags. The most common way would be to replace where the tags are located with 8 | links to another section of your site with more information. 9 | 10 | Setup 11 | ***** 12 | 13 | In the settings you will need to have 14 | 15 | .. code-block:: python 16 | 17 | SUPERTAGGING_SETTINGS = { 18 | 19 | # ... Other settings 20 | 21 | 'MARKUP': { 22 | 'ENABLED': True, 23 | } 24 | } 25 | 26 | How It Works 27 | ************ 28 | 29 | When SuperTagging loads up and markup is enabled, it will add an additional 30 | attribute for every field specified in :ref:`setting_modules`\ . 31 | 32 | .. code-block:: python 33 | 34 | SUPERTAGGING_SETTINGS = { 35 | 'ENABLED': True, 36 | 'WATCHED_FIELDS': { 37 | 'stories.story': 38 | {'fields':[ 39 | {'name': 'body', 40 | 'markup_handler': 'MyCustomHandler'}]}, 41 | 'media.image': 42 | {'fields':[ 43 | {'name': 'caption'}]}, 44 | 'blog.entry': 45 | {'fields':[ 46 | {'name': 'content'}, 47 | {'name': 'tease', 48 | 'markup': False}]} 49 | }, 50 | 51 | # ... Other settings 52 | 53 | 'MARKUP': { 54 | 'ENABLED': True, 55 | 'FIELD_SUFFIX': "tagged", 56 | }, 57 | } 58 | 59 | 60 | Lets take the code sample above as an example. We notice that markup is 61 | enabled and the prefix for the markup fields is `tagged`. The first module 62 | is a **story** model, and the field named **body** is marked to be tagged. 63 | It also specifies a custom markup handler, which we'll get to a bit later. 64 | The next model is a **image** model and the **caption** field is marked for 65 | tagging. The last model is an **entry** model and it has 2 fields marked for 66 | tagging, **content** and **tease**, but tease is not to be marked up. 67 | 68 | After `SuperTagging` is done loading you will end up with three additional 69 | attributes for the three different models. 70 | 71 | * **Story model:** ``body__tagged`` 72 | * **Image model:** ``caption__tagged`` 73 | * **Entry model:** ``content__tagged`` 74 | 75 | Notice that the a ``tease__tagged`` does not exist for the **Entry** model because the markup flag for that field is ``False``\ . 76 | 77 | Markup handler 78 | ************** 79 | 80 | Each field will be assigned a `MarkupHandler` object, which can be found 81 | in `supertagging/markup.py` file. This module does all the markup processing 82 | for you on the fly. If an error occurs, since the original content is never 83 | touched, the original content is returned. 84 | 85 | You can create your own custom handler as well. 86 | 87 | .. code-block:: python 88 | 89 | from supertagging.markup import MarkupHandler 90 | 91 | class MyCustomHandler(MarkupHandler): 92 | def handle(self, instance): 93 | # DO YOUR CUSTOM MARKUP HERE 94 | return "MARKED UP CONTENT" 95 | 96 | The ``handle`` method needs to return a string of the marked up content. 97 | 98 | If you want a create a custom handler but use the default markup method, your code might look something like this: 99 | 100 | .. code-block:: python 101 | 102 | from supertagging.markup import MarkupHandler, markup_content 103 | 104 | class MyCustomHandler(MarkupHandler): 105 | def handle(self, instance): 106 | # DO SOMETHING HERE 107 | return markup_content(instance, self.field) 108 | 109 | 110 | Markup Template 111 | *************** 112 | 113 | `markup.html` 114 | 115 | This template is used to render the tags in a marked up state. Below is the 116 | default html rendered. 117 | 118 | .. code-block:: django 119 | 120 | {{ actual_value }} 121 | 122 | **Context** 123 | 124 | * actual_value - the value of the tag, this might be the same as the tag name or a reference to the tag, IE: 'his', 'her' etc. 125 | * tag - a `SuperTag` instance 126 | 127 | 128 | Caching 129 | ******* 130 | 131 | There is a build-in cache for the markup, since every time we call this new 132 | attribute, a couple database calls need to happen to retrieve all the tags 133 | and its meta data for an instance. 134 | 135 | You can change the default timeout for this cache by changing the following setting 136 | 137 | .. code-block:: python 138 | 139 | SUPERTAGGING_MARKUP_CONTENT_CACHE_TIMEOUT = 3600 140 | 141 | 142 | Gotchas 143 | ******* 144 | 145 | In some cases, after enabling markup and successfully tagging an instance the markup 146 | does not show up. Two things might cause this, 1 is the cache has not expired and 2 147 | the markup did not validate. 148 | 149 | Markup validation happens when the markup field is called and the data retrieved does 150 | not match what the instance has stored. This usually means that the instance was edited 151 | and the field that gets tagged was changed and it has not been re-processed by 152 | OpenCalais. -------------------------------------------------------------------------------- /doc_src/reference/index.rst: -------------------------------------------------------------------------------- 1 | .. The reference section is for low-level documentation for programmers. 2 | There should be a file for each class 3 | Include Docstring and parameter expectations for each class 4 | 5 | Reference 6 | ========= 7 | 8 | .. toctree:: 9 | :maxdepth: 1 10 | :glob: 11 | 12 | settings 13 | template_tags -------------------------------------------------------------------------------- /doc_src/reference/template_tags.rst: -------------------------------------------------------------------------------- 1 | .. _template_tags: 2 | 3 | Template Tags 4 | ============= 5 | 6 | .. contents:: 7 | :depth: 4 8 | 9 | Here is the list of current template tags, most of these are tags from 10 | `Django Tagging `_ with some addtions 11 | 12 | 13 | .. note:: 14 | 15 | Tag names have changed slightly, the biggest difference is that now there 16 | is "super" prepended to them. This is so we don't clash with a project 17 | that uses Django-Tagging and SuperTagging together. 18 | 19 | The following "Tags from Django-Tagging" section are a modified version 20 | of Django-Tagging template tag documentation 21 | 22 | Tags from Django-Tagging 23 | ************************ 24 | 25 | The ``supertagging.templatetags.supertagging_tags`` module defines a number of 26 | template tags which may be used to work with tags. 27 | 28 | Tag reference 29 | ------------- 30 | 31 | supertags_for_model 32 | ~~~~~~~~~~~~~~~~~~~ 33 | 34 | Retrieves a list of ``SuperTag`` objects associated with a given model and 35 | stores them in a context variable. 36 | 37 | Usage 38 | 39 | .. code-block:: django 40 | 41 | {% supertags_for_model [model] as [varname] %} 42 | 43 | The model is specified in ``[appname].[modelname]`` format. 44 | 45 | Extended usage 46 | 47 | .. code-block:: django 48 | 49 | {% supertags_for_model [model] as [varname] with counts %} 50 | 51 | 52 | If specified - by providing extra ``with counts`` arguments - adds a 53 | ``count`` attribute to each tag containing the number of instances of 54 | the given model which have been tagged with it. 55 | 56 | Examples 57 | 58 | .. code-block:: django 59 | 60 | {% supertags_for_model products.Widget as widget_tags %} 61 | {% supertags_for_model products.Widget as widget_tags with counts %} 62 | 63 | supertag_cloud_for_model 64 | ~~~~~~~~~~~~~~~~~~~~~~~~ 65 | 66 | Retrieves a list of ``SuperTag`` objects for a given model, with tag cloud 67 | attributes set, and stores them in a context variable. 68 | 69 | Usage 70 | 71 | .. code-block:: django 72 | 73 | {% supertag_cloud_for_model [model] as [varname] %} 74 | 75 | The model is specified in ``[appname].[modelname]`` format. 76 | 77 | Extended usage 78 | 79 | .. code-block:: django 80 | 81 | {% supertag_cloud_for_model [model] as [varname] with [options] %} 82 | 83 | Extra options can be provided after an optional ``with`` argument, with 84 | each option being specified in ``[name]=[value]`` format. Valid extra 85 | options are: 86 | 87 | ``steps`` 88 | Integer. Defines the range of font sizes. 89 | 90 | ``min_count`` 91 | Integer. Defines the minimum number of times a tag must have 92 | been used to appear in the cloud. 93 | 94 | ``distribution`` 95 | One of ``linear`` or ``log``. Defines the font-size 96 | distribution algorithm to use when generating the tag cloud. 97 | 98 | Examples 99 | 100 | .. code-block:: django 101 | 102 | {% supertag_cloud_for_model products.Widget as widget_tags %} 103 | {% supertag_cloud_for_model products.Widget as widget_tags with steps=9 min_count=3 distribution=log %} 104 | 105 | supertags_for_object 106 | ~~~~~~~~~~~~~~~~~~~~ 107 | 108 | Retrieves a list of ``SuperTag`` objects associated with an object and stores 109 | them in a context variable. 110 | 111 | Usage 112 | 113 | .. code-block:: django 114 | 115 | {% supertags_for_object [object] as [varname] %} 116 | 117 | Example 118 | 119 | .. code-block:: django 120 | 121 | {% supertags_for_object foo_object as tag_list %} 122 | 123 | supertagged_objects 124 | ~~~~~~~~~~~~~~~~~~~ 125 | 126 | Retrieves a list of instances of a given model which are tagged with a 127 | given ``SuperTag`` and stores them in a context variable. 128 | 129 | Usage 130 | 131 | .. code-block:: django 132 | 133 | {% supertagged_objects [tag] in [model] as [varname] %} 134 | 135 | The model is specified in ``[appname].[modelname]`` format. 136 | 137 | The tag must be an instance of a ``SuperTag``, not the name of a tag. 138 | 139 | Example 140 | 141 | .. code-block:: django 142 | 143 | {% supertagged_objects comedy_tag in tv.Show as comedies %} 144 | 145 | 146 | New Tags for SuperTagging 147 | ************************* 148 | 149 | Below is a list of the new tags that can be used with SuperTagging 150 | 151 | Tag reference 152 | ------------- 153 | 154 | relations_for_supertag 155 | ~~~~~~~~~~~~~~~~~~~~~~ 156 | 157 | Usage 158 | 159 | .. code-block:: django 160 | 161 | {% relations_for_supertag [tag] as [varname] %} 162 | {% relations_for_supertag [tag] as [varname] with type=[TYPE] %} 163 | 164 | The tag must of an instance of a ``SuperTag``, not the name of a tag. 165 | 166 | Example 167 | 168 | .. code-block:: django 169 | 170 | {% relations_for_supertag state_tag as relations %} 171 | {% relations_for_supertag state_tag as relations with type=Quotation %} 172 | 173 | relations_for_object 174 | ~~~~~~~~~~~~~~~~~~~~ 175 | 176 | Useage 177 | 178 | .. code-block:: django 179 | 180 | {% relations_for_object [object] as [varname] %} 181 | {% relations_for_object [object] as [varname] with [type=TYPE]} 182 | 183 | Example 184 | 185 | .. code-block:: django 186 | 187 | {% relations_for_object story as story_relations %} 188 | {% relations_for_object story as story_relations with type=Quotation %} 189 | 190 | relations_for 191 | ~~~~~~~~~~~~~ 192 | 193 | Returns a list of `SuperTagRelation` objects for a tag within a given object. 194 | 195 | Useage 196 | 197 | .. code-block:: django 198 | 199 | {% relations_for [tag] in [object] as [varname] %} 200 | 201 | Example 202 | 203 | .. code-block:: django 204 | 205 | {% relations_for state_tag in obj as obj_relations %} 206 | 207 | supertag_render 208 | ~~~~~~~~~~~~~~~ 209 | 210 | Useage 211 | 212 | .. code-block:: django 213 | 214 | {% supertag_render [SuperTag or SuperTaggedItem or SuperTagRelation or SuperTaggedRelationItem] [with] [suffix=S] [template=T] %} 215 | 216 | Example 217 | 218 | .. code-block:: django 219 | 220 | {% supertag_render tag %} 221 | {% supertag_render tagged_item with suffix=custom %} 222 | {% supertag_render rel_item with template=mycustomtemplates/supertags/custom.html %} 223 | 224 | Only suffix OR template can be specified, but not both. 225 | 226 | View :ref:`render` for more information about rendering. 227 | -------------------------------------------------------------------------------- /docs/.buildinfo: -------------------------------------------------------------------------------- 1 | # Sphinx build info version 1 2 | # This file hashes the configuration used when building these files. When it is not found, a full rebuild will be done. 3 | config: 4 | tags: 5 | -------------------------------------------------------------------------------- /docs/_sources/api.txt: -------------------------------------------------------------------------------- 1 | .. _api: 2 | 3 | API Reference 4 | ============= 5 | 6 | .. contents:: 7 | :depth: 3 8 | 9 | .. _api_supertag: 10 | 11 | SuperTag 12 | ******** 13 | 14 | Fields 15 | ------ 16 | 17 | * **calais_id** - Contains the OpenCalais entity ID 18 | * CharField 19 | * Length: 255 20 | * Unique 21 | * **substitute** - Substitute tags in order to have better disambiguation. 22 | * ForeignKey to self 23 | * null=True, blank=True 24 | * **name** - The tag name. 25 | * CharField 26 | * Length: 150 27 | * **slug** - Slugified name 28 | * SlugField 29 | * Length: 150 30 | * **stype** - Tag type as returned by OpenCalais 31 | * CharField 32 | * Length: 100 33 | * **properties** - Tag properties as returned by OpenCalais 34 | * `PickledObjectField `_ 35 | * null=True, blank=True 36 | * **enabled** - Weather or not this tag is used. 37 | * BooleanField 38 | * Default: True 39 | 40 | Optional Fields 41 | --------------- 42 | 43 | If :ref:`setting_include_display_fields` is True, these fields will be 44 | included with the model. 45 | 46 | * **display_name** - Name used for display purposes. Since all SuperTag name are lowered when returned from calais, we can use this field to set the case correctly for example 47 | * CharField 48 | * Length: 150 49 | * null=True, blank=True 50 | * **description** - Description of the tag 51 | * TextField 52 | * null=True, blank=True 53 | * **icon** - Image field for the tag 54 | * ImageField 55 | * null=True, blank=True 56 | * **related** - Manually relating tags 57 | * ManyToManyField to self 58 | * null=True, blank=True 59 | 60 | 61 | Methods 62 | ------- 63 | 64 | get_name 65 | ~~~~~~~~ 66 | 67 | Gets the name of the tag, this will try to retrieve the display name first 68 | if the display fields are available, if the display fields are not available 69 | the normal name will be returned. 70 | 71 | has_display_fields 72 | ~~~~~~~~~~~~~~~~~~ 73 | 74 | Returns True or False, if the display fields are available. 75 | 76 | render 77 | ~~~~~~ 78 | 79 | Renders the instance, view :ref:`render` for more information. 80 | 81 | .. _api_supertagrelation: 82 | 83 | SuperTagRelation 84 | **************** 85 | 86 | Fields 87 | ------ 88 | 89 | * **tag** - The associated tag 90 | * ForeignKey to :ref:`api_supertag` 91 | * **stype** - The type of relation 92 | * CharField 93 | * Length: 100 94 | * **name** - Name of the relation 95 | * CharField 96 | * Length: 150 97 | * **properties** - Relation properties returned by OpenCalais 98 | * `PickledObjectField `_ 99 | * null=True, blank=True 100 | 101 | Methods 102 | ------- 103 | 104 | render 105 | ~~~~~~ 106 | 107 | Renders the instance, view :ref:`render` for more information. 108 | 109 | 110 | .. _api_supertaggeditem: 111 | 112 | SuperTaggedItem 113 | *************** 114 | 115 | Generic relation to a :ref:`api_supertag` 116 | 117 | Fields 118 | ------ 119 | 120 | * **tag** - The associated tag 121 | * ForeignKey to :ref:`api_supertag` 122 | * **content_type** - Content type of an object 123 | * ForeignKey to `django.contrib.contenttypes.models.ContentType` 124 | * **object_id** - Instance primary key 125 | * PositiveIntegerField 126 | * **content_object** - Gernric relation 127 | * GenericForeignKey to content_type and object_id 128 | * **field** - The name of the field this instance refers to 129 | * CharField 130 | * Length: 100 131 | * **process_type** - The type used to process the data, "TEXT/HTML", "TEXT/RAW" or "TEXT/XML" 132 | * CharField 133 | * Length: 10 134 | * null=True, blank=True 135 | * **relevance** - The relevance score 136 | * IntegerField 137 | * null=True, blank=True 138 | * **instances** - Contains a list of all the tags found in the content. 139 | * `PickledObjectField `_ 140 | * null=True, blank=True 141 | * **item_date** - Date of the object 142 | * DateTimeField 143 | * null=True, blank=True 144 | 145 | Methods 146 | ------- 147 | 148 | render 149 | ~~~~~~ 150 | 151 | Renders the instance, view :ref:`render` for more information. 152 | 153 | .. _api_supertaggedrelationitem: 154 | 155 | SuperTaggedRelationItem 156 | *********************** 157 | 158 | Fields 159 | ------ 160 | 161 | * **relation** - Associated relation 162 | * ForignKey to :ref:`api_supertagrelation` 163 | * **content_type** - Content type of an object 164 | * ForeignKey to `django.contrib.contenttypes.models.ContentType` 165 | * **object_id** - Instance primary key 166 | * PositiveIntegerField 167 | * **content_object** - Gernric relation 168 | * GenericForeignKey to content_type and object_id 169 | * **field** - The name of the field this instance refers to 170 | * CharField 171 | * Length: 100 172 | * **process_type** - The type used to process the data, "TEXT/HTML", "TEXT/RAW" or "TEXT/XML" 173 | * CharField 174 | * Length: 10 175 | * null=True, blank=True 176 | * **instances** - Contains a list of all the tags found in the content. 177 | * `PickledObjectField `_ 178 | * null=True, blank=True 179 | * **item_date** - Date of the object 180 | * DateTimeField 181 | * null=True, blank=True 182 | 183 | Methods 184 | ------- 185 | 186 | render 187 | ~~~~~~ 188 | 189 | Renders the instance, view :ref:`render` for more information. 190 | 191 | .. _api_supertagprocessqueue: 192 | 193 | SuperTagProcessQueue 194 | ******************** 195 | 196 | Holds a generic relation to an object to be processed at a later time, this 197 | model is only used when :ref:`setting_use_queue` is set to `True` 198 | 199 | Fields 200 | ------ 201 | 202 | * **content_type** - Content type of an object 203 | * ForeignKey to `django.contrib.contenttypes.models.ContentType` 204 | * **object_id** - Instance primary key 205 | * PositiveIntegerField 206 | * **content_object** - Gernric relation 207 | * GenericForeignKey to content_type and object_id 208 | * **locked** - Weather the object is being processed 209 | * BooleanField 210 | * Default: False 211 | 212 | 213 | .. _render: 214 | 215 | Rendering Items 216 | *************** 217 | 218 | :ref:`api_supertag`, :ref:`api_supertaggeditem`, :ref:`api_supertagrelation` 219 | and :ref:`api_supertaggedrelationitem` have a `render` method in order to 220 | correctly display its contents. 221 | 222 | Template Locations 223 | ------------------ 224 | 225 | Default location for these templates are in `supertagging/templates/render`. 226 | For each model there is an additional folder: 227 | 228 | * SuperTag: "tags/" 229 | * SuperTaggedItem: "tagged_items/" 230 | * SuperTagRelation: "relations/" 231 | * SuperTaggedRelationItem: "tagged_relations/" 232 | 233 | For example the default template for a SuperTaggedItem would be 234 | "supertagging/templates/render/tagged_items/default.html" 235 | 236 | This default template is the last resort, below is a detail list of template 237 | paths that will be checked first 238 | 239 | 1. template argument - this is a full path starting in your templates dir 240 | 2. template_path + `stype` + `app` + `model` + `suffix` - for :ref:`api_supertag` and :ref:`api_supertagrelation` a type, model, app and suffix will be added. 241 | * supertagging/render/tags//____.html 242 | * supertagging/render/tags/people/stories__story__custom.html 243 | 3. template_path + `stype` + `app` + `model` - Same as above but without the suffix 244 | * supertagging/render/tags/people/stories__story.html 245 | 4. template_path + `stype` + default + `suffix` - Same as #2 except not `app` and `model` 246 | * supertagging/render/tags/people/default__custom.html 247 | 5. template_path + `stype` + default - Same as #4 except without the suffix 248 | * supertagging/render/tags/people/default.html 249 | 6. template_path + default - the last possible path to look for the template 250 | * supertagging/render/tags/default.html 251 | 252 | .. note:: 253 | 254 | As stated in #2 of the list above, `stype` only applies to :ref:`api_supertag` and :ref:`api_supertagrelation` 255 | since :ref:`api_supertaggeditem` and :ref:`api_supertaggedrelationitem` 256 | doesn't contain the `stype` field. It will simply not be part of the path. 257 | 258 | Template Context 259 | ---------------- 260 | 261 | :ref:`api_supertag` and :ref:`api_supertagrelation` has only it self returned 262 | in the context 263 | 264 | * **obj** - self 265 | 266 | :ref:`api_supertaggeditem` and :ref:`api_supertaggedrelationitem` has 2 conext 267 | variables 268 | 269 | * **obj** - the generic related item 270 | * **content** - self -------------------------------------------------------------------------------- /docs/_sources/getting_started.txt: -------------------------------------------------------------------------------- 1 | .. _getting_started: 2 | 3 | Getting Started 4 | =============== 5 | 6 | If you have not installed SuperTagging yet, go to the :ref:`installation` page. 7 | 8 | Create basic settings 9 | ********************* 10 | 11 | In your ``settings.py`` file: 12 | 13 | .. code-block:: python 14 | 15 | SUPERTAGGING_SETTINGS = { 16 | 'ENABLED': True, 17 | 'DEBUG': True, 18 | } 19 | 20 | 21 | Setting up OpenCalais API 22 | ************************* 23 | 24 | Go to `OpenCalais `_'s website and register for 25 | an api key, and in your ``settings.py`` file, alter ``SUPERTAGGING_SETTINGS``\ : 26 | 27 | .. code-block:: python 28 | 29 | SUPERTAGGING_SETTINGS = { 30 | 'ENABLED': True, 31 | 'DEBUG': True, 32 | 'OPEN_CALAIS': { 33 | 'API_KEY': 'YOUR_API_KEY', 34 | } 35 | } 36 | 37 | 38 | Setting up models to be tagged 39 | ****************************** 40 | 41 | You will need to decide which models and which fields in those models you 42 | will want SuperTagging to mark for tagging: 43 | 44 | .. code-block:: python 45 | 46 | SUPERTAGGING_SETTINGS = { 47 | 'ENABLED': True, 48 | 'DEBUG': True, 49 | 'OPEN_CALAIS': { 50 | 'API_KEY': 'YOUR_API_KEY', 51 | }, 52 | 'WATCHED_FIELDS': { 53 | 'stories.story': { 54 | 'fields':[ 55 | {'name': 'body'}, 56 | ], 57 | }, 58 | }, 59 | } 60 | 61 | 62 | The code above tells SuperTagging to tag the **body** field of model 63 | **stories.story**. We can specify any number of fields and models as well. 64 | 65 | .. code-block:: python 66 | 67 | SUPERTAGGING_SETTINGS = { 68 | 'ENABLED': True, 69 | 'DEBUG': True, 70 | 'OPEN_CALAIS': { 71 | 'API_KEY': 'YOUR_API_KEY', 72 | }, 73 | 'WATCHED_FIELDS': { 74 | 'stories.story': { 75 | 'fields':[ 76 | {'name': 'body'}, 77 | {'name': 'tease'}, 78 | {'name': 'kicker'}, 79 | ], 80 | }, 81 | 'media.image': { 82 | 'fields':[ 83 | {'name': 'caption'}, 84 | {'name': 'description'}, 85 | ], 86 | } 87 | }, 88 | } 89 | 90 | 91 | View :ref:`setting_modules` for more information. 92 | 93 | Set up automatic processing 94 | *************************** 95 | 96 | Finally, add: 97 | 98 | .. code-block:: python 99 | 100 | SUPERTAGGING_SETTINGS = { 101 | 'ENABLED': True, 102 | 'DEBUG': True, 103 | 'OPEN_CALAIS': { 104 | 'API_KEY': 'YOUR_API_KEY', 105 | }, 106 | 'WATCHED_FIELDS': { 107 | 'stories.story': { 108 | 'fields':[ 109 | {'name': 'body'}, 110 | ], 111 | }, 112 | }, 113 | 'AUTO_PROCESS': True, 114 | } 115 | 116 | Post save and post delete signals will be connected to the models 117 | specified in `WATCHED_FIELDS`. Visit :ref:`reference_settings` to 118 | view more details about the SuperTagging settings 119 | 120 | View the complete list of :ref:`reference_settings` 121 | 122 | Conclusion 123 | ********** 124 | 125 | That is all that is needed to get SuperTagging to start tagging your data. 126 | Upon saving a instance of one of the models specified in 127 | `SUPERTAGGING_MODULES`, the field(s) data will be sent to OpenCalais 128 | for processing. 129 | 130 | 131 | Next step: View the :ref:`real_world_example` section of how The Washington 132 | Times has SuperTagging setup. -------------------------------------------------------------------------------- /docs/_sources/index.txt: -------------------------------------------------------------------------------- 1 | .. app documentation master file, created by 2 | sphinx-quickstart on Wed Oct 21 13:18:22 2009. 3 | You can adapt this file completely to your liking, but it should at least 4 | contain the root `toctree` directive. 5 | 6 | Welcome to Django SuperTagging's documentation! 7 | =============================================== 8 | 9 | SuperTagging is an auto-tagging app using `OpenCalais `_, 10 | based off of `Django Tagging `_ 11 | 12 | Contents: 13 | 14 | .. toctree:: 15 | :maxdepth: 2 16 | :glob: 17 | 18 | installation 19 | getting_started 20 | real_world_example 21 | api 22 | markup 23 | 24 | reference/index 25 | 26 | Indices and tables 27 | ================== 28 | 29 | * :ref:`genindex` 30 | * :ref:`modindex` 31 | * :ref:`search` 32 | 33 | -------------------------------------------------------------------------------- /docs/_sources/installation.txt: -------------------------------------------------------------------------------- 1 | .. _installation: 2 | 3 | Installation 4 | ============ 5 | 6 | Download SuperTagging 7 | ********************* 8 | 9 | There are a couple ways for you to get Django-SuperTagging, 10 | 11 | 1. Clone the git repository `from GitHub `_ 12 | 2. Use pip to install it from `PyPI `_ 13 | 14 | :: 15 | 16 | pip install supertagging 17 | 18 | 19 | Dependencies 20 | ************ 21 | 22 | * `simplejson `_ *(Required)* 23 | * `freebase `_ *(Optional)* 24 | 25 | 26 | Add SuperTagging to your project 27 | ******************************** 28 | 29 | Add to INSTALLED_APPS 30 | 31 | .. code-block:: python 32 | 33 | INSTALLED_APPS = ( 34 | ... 35 | supertagging, 36 | ... 37 | ) 38 | 39 | Run syncdb:: 40 | 41 | >>> ./manage.py syncdb 42 | -------------------------------------------------------------------------------- /docs/_sources/markup.txt: -------------------------------------------------------------------------------- 1 | .. _markup: 2 | 3 | Markup 4 | ====== 5 | 6 | This is a way to populate your content with extra content in relation to the 7 | tags. The most common way would be to replace where the tags are located with 8 | links to another section of your site with more information. 9 | 10 | Setup 11 | ***** 12 | 13 | In the settings you will need to have 14 | 15 | .. code-block:: python 16 | 17 | SUPERTAGGING_SETTINGS = { 18 | 19 | # ... Other settings 20 | 21 | 'MARKUP': { 22 | 'ENABLED': True, 23 | } 24 | } 25 | 26 | How It Works 27 | ************ 28 | 29 | When SuperTagging loads up and markup is enabled, it will add an additional 30 | attribute for every field specified in :ref:`setting_modules`\ . 31 | 32 | .. code-block:: python 33 | 34 | SUPERTAGGING_SETTINGS = { 35 | 'ENABLED': True, 36 | 'WATCHED_FIELDS': { 37 | 'stories.story': 38 | {'fields':[ 39 | {'name': 'body', 40 | 'markup_handler': 'MyCustomHandler'}]}, 41 | 'media.image': 42 | {'fields':[ 43 | {'name': 'caption'}]}, 44 | 'blog.entry': 45 | {'fields':[ 46 | {'name': 'content'}, 47 | {'name': 'tease', 48 | 'markup': False}]} 49 | }, 50 | 51 | # ... Other settings 52 | 53 | 'MARKUP': { 54 | 'ENABLED': True, 55 | 'FIELD_SUFFIX': "tagged", 56 | }, 57 | } 58 | 59 | 60 | Lets take the code sample above as an example. We notice that markup is 61 | enabled and the prefix for the markup fields is `tagged`. The first module 62 | is a **story** model, and the field named **body** is marked to be tagged. 63 | It also specifies a custom markup handler, which we'll get to a bit later. 64 | The next model is a **image** model and the **caption** field is marked for 65 | tagging. The last model is an **entry** model and it has 2 fields marked for 66 | tagging, **content** and **tease**, but tease is not to be marked up. 67 | 68 | After `SuperTagging` is done loading you will end up with three additional 69 | attributes for the three different models. 70 | 71 | * **Story model:** ``body__tagged`` 72 | * **Image model:** ``caption__tagged`` 73 | * **Entry model:** ``content__tagged`` 74 | 75 | Notice that the a ``tease__tagged`` does not exist for the **Entry** model because the markup flag for that field is ``False``\ . 76 | 77 | Markup handler 78 | ************** 79 | 80 | Each field will be assigned a `MarkupHandler` object, which can be found 81 | in `supertagging/markup.py` file. This module does all the markup processing 82 | for you on the fly. If an error occurs, since the original content is never 83 | touched, the original content is returned. 84 | 85 | You can create your own custom handler as well. 86 | 87 | .. code-block:: python 88 | 89 | from supertagging.markup import MarkupHandler 90 | 91 | class MyCustomHandler(MarkupHandler): 92 | def handle(self, instance): 93 | # DO YOUR CUSTOM MARKUP HERE 94 | return "MARKED UP CONTENT" 95 | 96 | The ``handle`` method needs to return a string of the marked up content. 97 | 98 | If you want a create a custom handler but use the default markup method, your code might look something like this: 99 | 100 | .. code-block:: python 101 | 102 | from supertagging.markup import MarkupHandler, markup_content 103 | 104 | class MyCustomHandler(MarkupHandler): 105 | def handle(self, instance): 106 | # DO SOMETHING HERE 107 | return markup_content(instance, self.field) 108 | 109 | 110 | Markup Template 111 | *************** 112 | 113 | `markup.html` 114 | 115 | This template is used to render the tags in a marked up state. Below is the 116 | default html rendered. 117 | 118 | .. code-block:: django 119 | 120 | {{ actual_value }} 121 | 122 | **Context** 123 | 124 | * actual_value - the value of the tag, this might be the same as the tag name or a reference to the tag, IE: 'his', 'her' etc. 125 | * tag - a `SuperTag` instance 126 | 127 | 128 | Caching 129 | ******* 130 | 131 | There is a build-in cache for the markup, since every time we call this new 132 | attribute, a couple database calls need to happen to retrieve all the tags 133 | and its meta data for an instance. 134 | 135 | You can change the default timeout for this cache by changing the following setting 136 | 137 | .. code-block:: python 138 | 139 | SUPERTAGGING_MARKUP_CONTENT_CACHE_TIMEOUT = 3600 140 | 141 | 142 | Gotchas 143 | ******* 144 | 145 | In some cases, after enabling markup and successfully tagging an instance the markup 146 | does not show up. Two things might cause this, 1 is the cache has not expired and 2 147 | the markup did not validate. 148 | 149 | Markup validation happens when the markup field is called and the data retrieved does 150 | not match what the instance has stored. This usually means that the instance was edited 151 | and the field that gets tagged was changed and it has not been re-processed by 152 | OpenCalais. -------------------------------------------------------------------------------- /docs/_sources/reference/index.txt: -------------------------------------------------------------------------------- 1 | .. The reference section is for low-level documentation for programmers. 2 | There should be a file for each class 3 | Include Docstring and parameter expectations for each class 4 | 5 | Reference 6 | ========= 7 | 8 | .. toctree:: 9 | :maxdepth: 1 10 | :glob: 11 | 12 | settings 13 | template_tags -------------------------------------------------------------------------------- /docs/_sources/reference/template_tags.txt: -------------------------------------------------------------------------------- 1 | .. _template_tags: 2 | 3 | Template Tags 4 | ============= 5 | 6 | .. contents:: 7 | :depth: 4 8 | 9 | Here is the list of current template tags, most of these are tags from 10 | `Django Tagging `_ with some addtions 11 | 12 | 13 | .. note:: 14 | 15 | Tag names have changed slightly, the biggest difference is that now there 16 | is "super" prepended to them. This is so we don't clash with a project 17 | that uses Django-Tagging and SuperTagging together. 18 | 19 | The following "Tags from Django-Tagging" section are a modified version 20 | of Django-Tagging template tag documentation 21 | 22 | Tags from Django-Tagging 23 | ************************ 24 | 25 | The ``supertagging.templatetags.supertagging_tags`` module defines a number of 26 | template tags which may be used to work with tags. 27 | 28 | Tag reference 29 | ------------- 30 | 31 | supertags_for_model 32 | ~~~~~~~~~~~~~~~~~~~ 33 | 34 | Retrieves a list of ``SuperTag`` objects associated with a given model and 35 | stores them in a context variable. 36 | 37 | Usage 38 | 39 | .. code-block:: django 40 | 41 | {% supertags_for_model [model] as [varname] %} 42 | 43 | The model is specified in ``[appname].[modelname]`` format. 44 | 45 | Extended usage 46 | 47 | .. code-block:: django 48 | 49 | {% supertags_for_model [model] as [varname] with counts %} 50 | 51 | 52 | If specified - by providing extra ``with counts`` arguments - adds a 53 | ``count`` attribute to each tag containing the number of instances of 54 | the given model which have been tagged with it. 55 | 56 | Examples 57 | 58 | .. code-block:: django 59 | 60 | {% supertags_for_model products.Widget as widget_tags %} 61 | {% supertags_for_model products.Widget as widget_tags with counts %} 62 | 63 | supertag_cloud_for_model 64 | ~~~~~~~~~~~~~~~~~~~~~~~~ 65 | 66 | Retrieves a list of ``SuperTag`` objects for a given model, with tag cloud 67 | attributes set, and stores them in a context variable. 68 | 69 | Usage 70 | 71 | .. code-block:: django 72 | 73 | {% supertag_cloud_for_model [model] as [varname] %} 74 | 75 | The model is specified in ``[appname].[modelname]`` format. 76 | 77 | Extended usage 78 | 79 | .. code-block:: django 80 | 81 | {% supertag_cloud_for_model [model] as [varname] with [options] %} 82 | 83 | Extra options can be provided after an optional ``with`` argument, with 84 | each option being specified in ``[name]=[value]`` format. Valid extra 85 | options are: 86 | 87 | ``steps`` 88 | Integer. Defines the range of font sizes. 89 | 90 | ``min_count`` 91 | Integer. Defines the minimum number of times a tag must have 92 | been used to appear in the cloud. 93 | 94 | ``distribution`` 95 | One of ``linear`` or ``log``. Defines the font-size 96 | distribution algorithm to use when generating the tag cloud. 97 | 98 | Examples 99 | 100 | .. code-block:: django 101 | 102 | {% supertag_cloud_for_model products.Widget as widget_tags %} 103 | {% supertag_cloud_for_model products.Widget as widget_tags with steps=9 min_count=3 distribution=log %} 104 | 105 | supertags_for_object 106 | ~~~~~~~~~~~~~~~~~~~~ 107 | 108 | Retrieves a list of ``SuperTag`` objects associated with an object and stores 109 | them in a context variable. 110 | 111 | Usage 112 | 113 | .. code-block:: django 114 | 115 | {% supertags_for_object [object] as [varname] %} 116 | 117 | Example 118 | 119 | .. code-block:: django 120 | 121 | {% supertags_for_object foo_object as tag_list %} 122 | 123 | supertagged_objects 124 | ~~~~~~~~~~~~~~~~~~~ 125 | 126 | Retrieves a list of instances of a given model which are tagged with a 127 | given ``SuperTag`` and stores them in a context variable. 128 | 129 | Usage 130 | 131 | .. code-block:: django 132 | 133 | {% supertagged_objects [tag] in [model] as [varname] %} 134 | 135 | The model is specified in ``[appname].[modelname]`` format. 136 | 137 | The tag must be an instance of a ``SuperTag``, not the name of a tag. 138 | 139 | Example 140 | 141 | .. code-block:: django 142 | 143 | {% supertagged_objects comedy_tag in tv.Show as comedies %} 144 | 145 | 146 | New Tags for SuperTagging 147 | ************************* 148 | 149 | Below is a list of the new tags that can be used with SuperTagging 150 | 151 | Tag reference 152 | ------------- 153 | 154 | relations_for_supertag 155 | ~~~~~~~~~~~~~~~~~~~~~~ 156 | 157 | Usage 158 | 159 | .. code-block:: django 160 | 161 | {% relations_for_supertag [tag] as [varname] %} 162 | {% relations_for_supertag [tag] as [varname] with type=[TYPE] %} 163 | 164 | The tag must of an instance of a ``SuperTag``, not the name of a tag. 165 | 166 | Example 167 | 168 | .. code-block:: django 169 | 170 | {% relations_for_supertag state_tag as relations %} 171 | {% relations_for_supertag state_tag as relations with type=Quotation %} 172 | 173 | relations_for_object 174 | ~~~~~~~~~~~~~~~~~~~~ 175 | 176 | Useage 177 | 178 | .. code-block:: django 179 | 180 | {% relations_for_object [object] as [varname] %} 181 | {% relations_for_object [object] as [varname] with [type=TYPE]} 182 | 183 | Example 184 | 185 | .. code-block:: django 186 | 187 | {% relations_for_object story as story_relations %} 188 | {% relations_for_object story as story_relations with type=Quotation %} 189 | 190 | relations_for 191 | ~~~~~~~~~~~~~ 192 | 193 | Returns a list of `SuperTagRelation` objects for a tag within a given object. 194 | 195 | Useage 196 | 197 | .. code-block:: django 198 | 199 | {% relations_for [tag] in [object] as [varname] %} 200 | 201 | Example 202 | 203 | .. code-block:: django 204 | 205 | {% relations_for state_tag in obj as obj_relations %} 206 | 207 | supertag_render 208 | ~~~~~~~~~~~~~~~ 209 | 210 | Useage 211 | 212 | .. code-block:: django 213 | 214 | {% supertag_render [SuperTag or SuperTaggedItem or SuperTagRelation or SuperTaggedRelationItem] [with] [suffix=S] [template=T] %} 215 | 216 | Example 217 | 218 | .. code-block:: django 219 | 220 | {% supertag_render tag %} 221 | {% supertag_render tagged_item with suffix=custom %} 222 | {% supertag_render rel_item with template=mycustomtemplates/supertags/custom.html %} 223 | 224 | Only suffix OR template can be specified, but not both. 225 | 226 | View :ref:`render` for more information about rendering. 227 | -------------------------------------------------------------------------------- /docs/_static/breadcrumb_background.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/callowayproject/django-supertagging/9b7d70343c2ff72e8f6dc971f6b873e1777ecc6c/docs/_static/breadcrumb_background.png -------------------------------------------------------------------------------- /docs/_static/doctools.js: -------------------------------------------------------------------------------- 1 | /* 2 | * doctools.js 3 | * ~~~~~~~~~~~ 4 | * 5 | * Sphinx JavaScript utilties for all documentation. 6 | * 7 | * :copyright: Copyright 2007-2011 by the Sphinx team, see AUTHORS. 8 | * :license: BSD, see LICENSE for details. 9 | * 10 | */ 11 | 12 | /** 13 | * select a different prefix for underscore 14 | */ 15 | $u = _.noConflict(); 16 | 17 | /** 18 | * make the code below compatible with browsers without 19 | * an installed firebug like debugger 20 | if (!window.console || !console.firebug) { 21 | var names = ["log", "debug", "info", "warn", "error", "assert", "dir", 22 | "dirxml", "group", "groupEnd", "time", "timeEnd", "count", "trace", 23 | "profile", "profileEnd"]; 24 | window.console = {}; 25 | for (var i = 0; i < names.length; ++i) 26 | window.console[names[i]] = function() {}; 27 | } 28 | */ 29 | 30 | /** 31 | * small helper function to urldecode strings 32 | */ 33 | jQuery.urldecode = function(x) { 34 | return decodeURIComponent(x).replace(/\+/g, ' '); 35 | } 36 | 37 | /** 38 | * small helper function to urlencode strings 39 | */ 40 | jQuery.urlencode = encodeURIComponent; 41 | 42 | /** 43 | * This function returns the parsed url parameters of the 44 | * current request. Multiple values per key are supported, 45 | * it will always return arrays of strings for the value parts. 46 | */ 47 | jQuery.getQueryParameters = function(s) { 48 | if (typeof s == 'undefined') 49 | s = document.location.search; 50 | var parts = s.substr(s.indexOf('?') + 1).split('&'); 51 | var result = {}; 52 | for (var i = 0; i < parts.length; i++) { 53 | var tmp = parts[i].split('=', 2); 54 | var key = jQuery.urldecode(tmp[0]); 55 | var value = jQuery.urldecode(tmp[1]); 56 | if (key in result) 57 | result[key].push(value); 58 | else 59 | result[key] = [value]; 60 | } 61 | return result; 62 | }; 63 | 64 | /** 65 | * small function to check if an array contains 66 | * a given item. 67 | */ 68 | jQuery.contains = function(arr, item) { 69 | for (var i = 0; i < arr.length; i++) { 70 | if (arr[i] == item) 71 | return true; 72 | } 73 | return false; 74 | }; 75 | 76 | /** 77 | * highlight a given string on a jquery object by wrapping it in 78 | * span elements with the given class name. 79 | */ 80 | jQuery.fn.highlightText = function(text, className) { 81 | function highlight(node) { 82 | if (node.nodeType == 3) { 83 | var val = node.nodeValue; 84 | var pos = val.toLowerCase().indexOf(text); 85 | if (pos >= 0 && !jQuery(node.parentNode).hasClass(className)) { 86 | var span = document.createElement("span"); 87 | span.className = className; 88 | span.appendChild(document.createTextNode(val.substr(pos, text.length))); 89 | node.parentNode.insertBefore(span, node.parentNode.insertBefore( 90 | document.createTextNode(val.substr(pos + text.length)), 91 | node.nextSibling)); 92 | node.nodeValue = val.substr(0, pos); 93 | } 94 | } 95 | else if (!jQuery(node).is("button, select, textarea")) { 96 | jQuery.each(node.childNodes, function() { 97 | highlight(this); 98 | }); 99 | } 100 | } 101 | return this.each(function() { 102 | highlight(this); 103 | }); 104 | }; 105 | 106 | /** 107 | * Small JavaScript module for the documentation. 108 | */ 109 | var Documentation = { 110 | 111 | init : function() { 112 | this.fixFirefoxAnchorBug(); 113 | this.highlightSearchWords(); 114 | this.initIndexTable(); 115 | }, 116 | 117 | /** 118 | * i18n support 119 | */ 120 | TRANSLATIONS : {}, 121 | PLURAL_EXPR : function(n) { return n == 1 ? 0 : 1; }, 122 | LOCALE : 'unknown', 123 | 124 | // gettext and ngettext don't access this so that the functions 125 | // can safely bound to a different name (_ = Documentation.gettext) 126 | gettext : function(string) { 127 | var translated = Documentation.TRANSLATIONS[string]; 128 | if (typeof translated == 'undefined') 129 | return string; 130 | return (typeof translated == 'string') ? translated : translated[0]; 131 | }, 132 | 133 | ngettext : function(singular, plural, n) { 134 | var translated = Documentation.TRANSLATIONS[singular]; 135 | if (typeof translated == 'undefined') 136 | return (n == 1) ? singular : plural; 137 | return translated[Documentation.PLURALEXPR(n)]; 138 | }, 139 | 140 | addTranslations : function(catalog) { 141 | for (var key in catalog.messages) 142 | this.TRANSLATIONS[key] = catalog.messages[key]; 143 | this.PLURAL_EXPR = new Function('n', 'return +(' + catalog.plural_expr + ')'); 144 | this.LOCALE = catalog.locale; 145 | }, 146 | 147 | /** 148 | * add context elements like header anchor links 149 | */ 150 | addContextElements : function() { 151 | $('div[id] > :header:first').each(function() { 152 | $('\u00B6'). 153 | attr('href', '#' + this.id). 154 | attr('title', _('Permalink to this headline')). 155 | appendTo(this); 156 | }); 157 | $('dt[id]').each(function() { 158 | $('\u00B6'). 159 | attr('href', '#' + this.id). 160 | attr('title', _('Permalink to this definition')). 161 | appendTo(this); 162 | }); 163 | }, 164 | 165 | /** 166 | * workaround a firefox stupidity 167 | */ 168 | fixFirefoxAnchorBug : function() { 169 | if (document.location.hash && $.browser.mozilla) 170 | window.setTimeout(function() { 171 | document.location.href += ''; 172 | }, 10); 173 | }, 174 | 175 | /** 176 | * highlight the search words provided in the url in the text 177 | */ 178 | highlightSearchWords : function() { 179 | var params = $.getQueryParameters(); 180 | var terms = (params.highlight) ? params.highlight[0].split(/\s+/) : []; 181 | if (terms.length) { 182 | var body = $('div.body'); 183 | window.setTimeout(function() { 184 | $.each(terms, function() { 185 | body.highlightText(this.toLowerCase(), 'highlighted'); 186 | }); 187 | }, 10); 188 | $('') 190 | .appendTo($('.sidebar .this-page-menu')); 191 | } 192 | }, 193 | 194 | /** 195 | * init the domain index toggle buttons 196 | */ 197 | initIndexTable : function() { 198 | var togglers = $('img.toggler').click(function() { 199 | var src = $(this).attr('src'); 200 | var idnum = $(this).attr('id').substr(7); 201 | $('tr.cg-' + idnum).toggle(); 202 | if (src.substr(-9) == 'minus.png') 203 | $(this).attr('src', src.substr(0, src.length-9) + 'plus.png'); 204 | else 205 | $(this).attr('src', src.substr(0, src.length-8) + 'minus.png'); 206 | }).css('display', ''); 207 | if (DOCUMENTATION_OPTIONS.COLLAPSE_INDEX) { 208 | togglers.click(); 209 | } 210 | }, 211 | 212 | /** 213 | * helper function to hide the search marks again 214 | */ 215 | hideSearchWords : function() { 216 | $('.sidebar .this-page-menu li.highlight-link').fadeOut(300); 217 | $('span.highlighted').removeClass('highlighted'); 218 | }, 219 | 220 | /** 221 | * make the url absolute 222 | */ 223 | makeURL : function(relativeURL) { 224 | return DOCUMENTATION_OPTIONS.URL_ROOT + '/' + relativeURL; 225 | }, 226 | 227 | /** 228 | * get the current relative url 229 | */ 230 | getCurrentURL : function() { 231 | var path = document.location.pathname; 232 | var parts = path.split(/\//); 233 | $.each(DOCUMENTATION_OPTIONS.URL_ROOT.split(/\//), function() { 234 | if (this == '..') 235 | parts.pop(); 236 | }); 237 | var url = parts.join('/'); 238 | return path.substring(url.lastIndexOf('/') + 1, path.length - 1); 239 | } 240 | }; 241 | 242 | // quick alias for translations 243 | _ = Documentation.gettext; 244 | 245 | $(document).ready(function() { 246 | Documentation.init(); 247 | }); 248 | -------------------------------------------------------------------------------- /docs/_static/documentation.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/callowayproject/django-supertagging/9b7d70343c2ff72e8f6dc971f6b873e1777ecc6c/docs/_static/documentation.png -------------------------------------------------------------------------------- /docs/_static/file.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/callowayproject/django-supertagging/9b7d70343c2ff72e8f6dc971f6b873e1777ecc6c/docs/_static/file.png -------------------------------------------------------------------------------- /docs/_static/header_sm_mid.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/callowayproject/django-supertagging/9b7d70343c2ff72e8f6dc971f6b873e1777ecc6c/docs/_static/header_sm_mid.png -------------------------------------------------------------------------------- /docs/_static/minus.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/callowayproject/django-supertagging/9b7d70343c2ff72e8f6dc971f6b873e1777ecc6c/docs/_static/minus.png -------------------------------------------------------------------------------- /docs/_static/plus.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/callowayproject/django-supertagging/9b7d70343c2ff72e8f6dc971f6b873e1777ecc6c/docs/_static/plus.png -------------------------------------------------------------------------------- /docs/_static/pygments.css: -------------------------------------------------------------------------------- 1 | .highlight .hll { background-color: #ffffcc } 2 | .highlight { background: #eeffcc; } 3 | .highlight .c { color: #408090; font-style: italic } /* Comment */ 4 | .highlight .err { border: 1px solid #FF0000 } /* Error */ 5 | .highlight .k { color: #007020; font-weight: bold } /* Keyword */ 6 | .highlight .o { color: #666666 } /* Operator */ 7 | .highlight .cm { color: #408090; font-style: italic } /* Comment.Multiline */ 8 | .highlight .cp { color: #007020 } /* Comment.Preproc */ 9 | .highlight .c1 { color: #408090; font-style: italic } /* Comment.Single */ 10 | .highlight .cs { color: #408090; background-color: #fff0f0 } /* Comment.Special */ 11 | .highlight .gd { color: #A00000 } /* Generic.Deleted */ 12 | .highlight .ge { font-style: italic } /* Generic.Emph */ 13 | .highlight .gr { color: #FF0000 } /* Generic.Error */ 14 | .highlight .gh { color: #000080; font-weight: bold } /* Generic.Heading */ 15 | .highlight .gi { color: #00A000 } /* Generic.Inserted */ 16 | .highlight .go { color: #303030 } /* Generic.Output */ 17 | .highlight .gp { color: #c65d09; font-weight: bold } /* Generic.Prompt */ 18 | .highlight .gs { font-weight: bold } /* Generic.Strong */ 19 | .highlight .gu { color: #800080; font-weight: bold } /* Generic.Subheading */ 20 | .highlight .gt { color: #0040D0 } /* Generic.Traceback */ 21 | .highlight .kc { color: #007020; font-weight: bold } /* Keyword.Constant */ 22 | .highlight .kd { color: #007020; font-weight: bold } /* Keyword.Declaration */ 23 | .highlight .kn { color: #007020; font-weight: bold } /* Keyword.Namespace */ 24 | .highlight .kp { color: #007020 } /* Keyword.Pseudo */ 25 | .highlight .kr { color: #007020; font-weight: bold } /* Keyword.Reserved */ 26 | .highlight .kt { color: #902000 } /* Keyword.Type */ 27 | .highlight .m { color: #208050 } /* Literal.Number */ 28 | .highlight .s { color: #4070a0 } /* Literal.String */ 29 | .highlight .na { color: #4070a0 } /* Name.Attribute */ 30 | .highlight .nb { color: #007020 } /* Name.Builtin */ 31 | .highlight .nc { color: #0e84b5; font-weight: bold } /* Name.Class */ 32 | .highlight .no { color: #60add5 } /* Name.Constant */ 33 | .highlight .nd { color: #555555; font-weight: bold } /* Name.Decorator */ 34 | .highlight .ni { color: #d55537; font-weight: bold } /* Name.Entity */ 35 | .highlight .ne { color: #007020 } /* Name.Exception */ 36 | .highlight .nf { color: #06287e } /* Name.Function */ 37 | .highlight .nl { color: #002070; font-weight: bold } /* Name.Label */ 38 | .highlight .nn { color: #0e84b5; font-weight: bold } /* Name.Namespace */ 39 | .highlight .nt { color: #062873; font-weight: bold } /* Name.Tag */ 40 | .highlight .nv { color: #bb60d5 } /* Name.Variable */ 41 | .highlight .ow { color: #007020; font-weight: bold } /* Operator.Word */ 42 | .highlight .w { color: #bbbbbb } /* Text.Whitespace */ 43 | .highlight .mf { color: #208050 } /* Literal.Number.Float */ 44 | .highlight .mh { color: #208050 } /* Literal.Number.Hex */ 45 | .highlight .mi { color: #208050 } /* Literal.Number.Integer */ 46 | .highlight .mo { color: #208050 } /* Literal.Number.Oct */ 47 | .highlight .sb { color: #4070a0 } /* Literal.String.Backtick */ 48 | .highlight .sc { color: #4070a0 } /* Literal.String.Char */ 49 | .highlight .sd { color: #4070a0; font-style: italic } /* Literal.String.Doc */ 50 | .highlight .s2 { color: #4070a0 } /* Literal.String.Double */ 51 | .highlight .se { color: #4070a0; font-weight: bold } /* Literal.String.Escape */ 52 | .highlight .sh { color: #4070a0 } /* Literal.String.Heredoc */ 53 | .highlight .si { color: #70a0d0; font-style: italic } /* Literal.String.Interpol */ 54 | .highlight .sx { color: #c65d09 } /* Literal.String.Other */ 55 | .highlight .sr { color: #235388 } /* Literal.String.Regex */ 56 | .highlight .s1 { color: #4070a0 } /* Literal.String.Single */ 57 | .highlight .ss { color: #517918 } /* Literal.String.Symbol */ 58 | .highlight .bp { color: #007020 } /* Name.Builtin.Pseudo */ 59 | .highlight .vc { color: #bb60d5 } /* Name.Variable.Class */ 60 | .highlight .vg { color: #bb60d5 } /* Name.Variable.Global */ 61 | .highlight .vi { color: #bb60d5 } /* Name.Variable.Instance */ 62 | .highlight .il { color: #208050 } /* Literal.Number.Integer.Long */ -------------------------------------------------------------------------------- /docs/_static/scrn1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/callowayproject/django-supertagging/9b7d70343c2ff72e8f6dc971f6b873e1777ecc6c/docs/_static/scrn1.png -------------------------------------------------------------------------------- /docs/_static/scrn2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/callowayproject/django-supertagging/9b7d70343c2ff72e8f6dc971f6b873e1777ecc6c/docs/_static/scrn2.png -------------------------------------------------------------------------------- /docs/_static/searchfield_leftcap.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/callowayproject/django-supertagging/9b7d70343c2ff72e8f6dc971f6b873e1777ecc6c/docs/_static/searchfield_leftcap.png -------------------------------------------------------------------------------- /docs/_static/searchfield_repeat.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/callowayproject/django-supertagging/9b7d70343c2ff72e8f6dc971f6b873e1777ecc6c/docs/_static/searchfield_repeat.png -------------------------------------------------------------------------------- /docs/_static/searchfield_rightcap.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/callowayproject/django-supertagging/9b7d70343c2ff72e8f6dc971f6b873e1777ecc6c/docs/_static/searchfield_rightcap.png -------------------------------------------------------------------------------- /docs/_static/sidebar.js: -------------------------------------------------------------------------------- 1 | /* 2 | * sidebar.js 3 | * ~~~~~~~~~~ 4 | * 5 | * This script makes the Sphinx sidebar collapsible. 6 | * 7 | * .sphinxsidebar contains .sphinxsidebarwrapper. This script adds 8 | * in .sphixsidebar, after .sphinxsidebarwrapper, the #sidebarbutton 9 | * used to collapse and expand the sidebar. 10 | * 11 | * When the sidebar is collapsed the .sphinxsidebarwrapper is hidden 12 | * and the width of the sidebar and the margin-left of the document 13 | * are decreased. When the sidebar is expanded the opposite happens. 14 | * This script saves a per-browser/per-session cookie used to 15 | * remember the position of the sidebar among the pages. 16 | * Once the browser is closed the cookie is deleted and the position 17 | * reset to the default (expanded). 18 | * 19 | * :copyright: Copyright 2007-2011 by the Sphinx team, see AUTHORS. 20 | * :license: BSD, see LICENSE for details. 21 | * 22 | */ 23 | 24 | $(function() { 25 | // global elements used by the functions. 26 | // the 'sidebarbutton' element is defined as global after its 27 | // creation, in the add_sidebar_button function 28 | var bodywrapper = $('.bodywrapper'); 29 | var sidebar = $('.sphinxsidebar'); 30 | var sidebarwrapper = $('.sphinxsidebarwrapper'); 31 | 32 | // original margin-left of the bodywrapper and width of the sidebar 33 | // with the sidebar expanded 34 | var bw_margin_expanded = bodywrapper.css('margin-left'); 35 | var ssb_width_expanded = sidebar.width(); 36 | 37 | // margin-left of the bodywrapper and width of the sidebar 38 | // with the sidebar collapsed 39 | var bw_margin_collapsed = '.8em'; 40 | var ssb_width_collapsed = '.8em'; 41 | 42 | // colors used by the current theme 43 | var dark_color = $('.related').css('background-color'); 44 | var light_color = $('.document').css('background-color'); 45 | 46 | function sidebar_is_collapsed() { 47 | return sidebarwrapper.is(':not(:visible)'); 48 | } 49 | 50 | function toggle_sidebar() { 51 | if (sidebar_is_collapsed()) 52 | expand_sidebar(); 53 | else 54 | collapse_sidebar(); 55 | } 56 | 57 | function collapse_sidebar() { 58 | sidebarwrapper.hide(); 59 | sidebar.css('width', ssb_width_collapsed); 60 | bodywrapper.css('margin-left', bw_margin_collapsed); 61 | sidebarbutton.css({ 62 | 'margin-left': '0', 63 | 'height': bodywrapper.height() 64 | }); 65 | sidebarbutton.find('span').text('»'); 66 | sidebarbutton.attr('title', _('Expand sidebar')); 67 | document.cookie = 'sidebar=collapsed'; 68 | } 69 | 70 | function expand_sidebar() { 71 | bodywrapper.css('margin-left', bw_margin_expanded); 72 | sidebar.css('width', ssb_width_expanded); 73 | sidebarwrapper.show(); 74 | sidebarbutton.css({ 75 | 'margin-left': ssb_width_expanded-12, 76 | 'height': bodywrapper.height() 77 | }); 78 | sidebarbutton.find('span').text('«'); 79 | sidebarbutton.attr('title', _('Collapse sidebar')); 80 | document.cookie = 'sidebar=expanded'; 81 | } 82 | 83 | function add_sidebar_button() { 84 | sidebarwrapper.css({ 85 | 'float': 'left', 86 | 'margin-right': '0', 87 | 'width': ssb_width_expanded - 28 88 | }); 89 | // create the button 90 | sidebar.append( 91 | '
«
' 92 | ); 93 | var sidebarbutton = $('#sidebarbutton'); 94 | light_color = sidebarbutton.css('background-color'); 95 | // find the height of the viewport to center the '<<' in the page 96 | var viewport_height; 97 | if (window.innerHeight) 98 | viewport_height = window.innerHeight; 99 | else 100 | viewport_height = $(window).height(); 101 | sidebarbutton.find('span').css({ 102 | 'display': 'block', 103 | 'margin-top': (viewport_height - sidebar.position().top - 20) / 2 104 | }); 105 | 106 | sidebarbutton.click(toggle_sidebar); 107 | sidebarbutton.attr('title', _('Collapse sidebar')); 108 | sidebarbutton.css({ 109 | 'color': '#FFFFFF', 110 | 'border-left': '1px solid ' + dark_color, 111 | 'font-size': '1.2em', 112 | 'cursor': 'pointer', 113 | 'height': bodywrapper.height(), 114 | 'padding-top': '1px', 115 | 'margin-left': ssb_width_expanded - 12 116 | }); 117 | 118 | sidebarbutton.hover( 119 | function () { 120 | $(this).css('background-color', dark_color); 121 | }, 122 | function () { 123 | $(this).css('background-color', light_color); 124 | } 125 | ); 126 | } 127 | 128 | function set_position_from_cookie() { 129 | if (!document.cookie) 130 | return; 131 | var items = document.cookie.split(';'); 132 | for(var k=0; k=e.computed&&(e={value:f,computed:g})});return e.value};b.min=function(a,c,d){if(!c&&b.isArray(a))return Math.min.apply(Math,a);var e={computed:Infinity};b.each(a,function(f,g,h){g=c?c.call(d,f,g,h):f;gf?1:0}),"value")};b.sortedIndex=function(a,c,d){d=d||b.identity;for(var e=0,f=a.length;e>1;d(a[g])=0})})};b.zip=function(){for(var a=b.toArray(arguments),c=b.max(b.pluck(a,"length")),d=new Array(c),e=0;e0?f-c:c-f)>=0)return e;e[g++]=f}};b.bind=function(a,c){var d=b.rest(arguments,2);return function(){return a.apply(c||j,d.concat(b.toArray(arguments)))}};b.bindAll=function(a){var c=b.rest(arguments);if(c.length==0)c=b.functions(a);b.each(c,function(d){a[d]=b.bind(a[d],a)}); 10 | return a};b.delay=function(a,c){var d=b.rest(arguments,2);return setTimeout(function(){return a.apply(a,d)},c)};b.defer=function(a){return b.delay.apply(b,[a,1].concat(b.rest(arguments)))};b.wrap=function(a,c){return function(){var d=[a].concat(b.toArray(arguments));return c.apply(c,d)}};b.compose=function(){var a=b.toArray(arguments);return function(){for(var c=b.toArray(arguments),d=a.length-1;d>=0;d--)c=[a[d].apply(this,c)];return c[0]}};b.keys=function(a){if(b.isArray(a))return b.range(0,a.length); 11 | var c=[];for(var d in a)q.call(a,d)&&c.push(d);return c};b.values=function(a){return b.map(a,b.identity)};b.functions=function(a){return b.select(b.keys(a),function(c){return b.isFunction(a[c])}).sort()};b.extend=function(a,c){for(var d in c)a[d]=c[d];return a};b.clone=function(a){if(b.isArray(a))return a.slice(0);return b.extend({},a)};b.tap=function(a,c){c(a);return a};b.isEqual=function(a,c){if(a===c)return true;var d=typeof a;if(d!=typeof c)return false;if(a==c)return true;if(!a&&c||a&&!c)return false; 12 | if(a.isEqual)return a.isEqual(c);if(b.isDate(a)&&b.isDate(c))return a.getTime()===c.getTime();if(b.isNaN(a)&&b.isNaN(c))return true;if(b.isRegExp(a)&&b.isRegExp(c))return a.source===c.source&&a.global===c.global&&a.ignoreCase===c.ignoreCase&&a.multiline===c.multiline;if(d!=="object")return false;if(a.length&&a.length!==c.length)return false;d=b.keys(a);var e=b.keys(c);if(d.length!=e.length)return false;for(var f in a)if(!b.isEqual(a[f],c[f]))return false;return true};b.isEmpty=function(a){return b.keys(a).length== 13 | 0};b.isElement=function(a){return!!(a&&a.nodeType==1)};b.isArray=function(a){return!!(a&&a.concat&&a.unshift)};b.isArguments=function(a){return a&&b.isNumber(a.length)&&!b.isArray(a)&&!r.call(a,"length")};b.isFunction=function(a){return!!(a&&a.constructor&&a.call&&a.apply)};b.isString=function(a){return!!(a===""||a&&a.charCodeAt&&a.substr)};b.isNumber=function(a){return p.call(a)==="[object Number]"};b.isDate=function(a){return!!(a&&a.getTimezoneOffset&&a.setUTCFullYear)};b.isRegExp=function(a){return!!(a&& 14 | a.test&&a.exec&&(a.ignoreCase||a.ignoreCase===false))};b.isNaN=function(a){return b.isNumber(a)&&isNaN(a)};b.isNull=function(a){return a===null};b.isUndefined=function(a){return typeof a=="undefined"};b.noConflict=function(){j._=n;return this};b.identity=function(a){return a};b.breakLoop=function(){throw m;};var s=0;b.uniqueId=function(a){var c=s++;return a?a+c:c};b.template=function(a,c){a=new Function("obj","var p=[],print=function(){p.push.apply(p,arguments);};with(obj){p.push('"+a.replace(/[\r\t\n]/g, 15 | " ").replace(/'(?=[^%]*%>)/g,"\t").split("'").join("\\'").split("\t").join("'").replace(/<%=(.+?)%>/g,"',$1,'").split("<%").join("');").split("%>").join("p.push('")+"');}return p.join('');");return c?a(c):a};b.forEach=b.each;b.foldl=b.inject=b.reduce;b.foldr=b.reduceRight;b.filter=b.select;b.every=b.all;b.some=b.any;b.head=b.first;b.tail=b.rest;b.methods=b.functions;var l=function(a,c){return c?b(a).chain():a};b.each(b.functions(b),function(a){var c=b[a];i.prototype[a]=function(){var d=b.toArray(arguments); 16 | o.call(d,this._wrapped);return l(c.apply(b,d),this._chain)}});b.each(["pop","push","reverse","shift","sort","splice","unshift"],function(a){var c=Array.prototype[a];i.prototype[a]=function(){c.apply(this._wrapped,arguments);return l(this._wrapped,this._chain)}});b.each(["concat","join","slice"],function(a){var c=Array.prototype[a];i.prototype[a]=function(){return l(c.apply(this._wrapped,arguments),this._chain)}});i.prototype.chain=function(){this._chain=true;return this};i.prototype.value=function(){return this._wrapped}})(); 17 | -------------------------------------------------------------------------------- /docs/genindex.html: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 6 | 7 | 8 | 9 | Index — Django SuperTagging v0.5 documentation 10 | 11 | 12 | 21 | 22 | 23 | 24 | 25 | 26 | 27 |
28 |

Django SuperTagging v0.5 documentation

29 |
30 | 39 | 40 |
41 |
42 | 43 | 51 | 52 | 53 | 54 | 55 | 71 | 72 |
73 |
74 | 75 | 76 | 77 |
78 |
79 |
80 |
81 | 82 | 83 |

Index

84 | 85 |
86 | 87 |
88 | 89 | 90 |
91 |
92 |
93 | 99 |
100 |
101 | 105 | 106 | 107 | -------------------------------------------------------------------------------- /docs/index.html: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 6 | 7 | 8 | 9 | Welcome to Django SuperTagging’s documentation! — Django SuperTagging v0.5 documentation 10 | 11 | 12 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 |
29 |

Django SuperTagging v0.5 documentation

30 |
31 | 41 | 42 |
43 |
44 | 45 | 53 | 54 | 70 | 71 |
72 |
73 | 74 | 75 | 76 |
77 |
78 |
79 |
80 | 81 |
82 |

Welcome to Django SuperTagging’s documentation!

83 |

SuperTagging is an auto-tagging app using OpenCalais, 84 | based off of Django Tagging

85 |

Contents:

86 | 133 |
134 |
135 |

Indices and tables

136 | 141 |
142 | 143 | 144 |
145 |
146 |
147 | 153 |
154 |
155 | 159 | 160 | 161 | -------------------------------------------------------------------------------- /docs/installation.html: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 6 | 7 | 8 | 9 | Installation — Django SuperTagging v0.5 documentation 10 | 11 | 12 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 |
30 |

Django SuperTagging v0.5 documentation

31 |
32 | 43 | 44 |
45 |
46 | 47 | 60 | 61 | 77 | 78 |
79 |
80 | 81 | 82 | 83 |
84 |
85 |
86 |
87 | 88 |
89 |

Installation

90 |
91 |

Download SuperTagging

92 |

There are a couple ways for you to get Django-SuperTagging,

93 |
94 |
    95 |
  1. Clone the git repository from GitHub
  2. 96 |
  3. Use pip to install it from PyPI
  4. 97 |
98 |
99 |
pip install supertagging
100 |
101 |
102 |
103 |

Dependencies

104 | 108 |
109 |
110 |

Add SuperTagging to your project

111 |

Add to INSTALLED_APPS

112 |
INSTALLED_APPS = (
113 |     ...
114 |     supertagging,
115 |     ...
116 | )
117 |
118 |

Run syncdb:

119 |
>>> ./manage.py syncdb
120 | 
121 |
122 |
123 |
124 | 125 | 126 |
127 |
128 |
129 | 135 |
136 |
137 | 141 | 142 | 143 | -------------------------------------------------------------------------------- /docs/objects.inv: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/callowayproject/django-supertagging/9b7d70343c2ff72e8f6dc971f6b873e1777ecc6c/docs/objects.inv -------------------------------------------------------------------------------- /docs/reference/index.html: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 6 | 7 | 8 | 9 | Reference — Django SuperTagging v0.5 documentation 10 | 11 | 12 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 |
30 |

Django SuperTagging v0.5 documentation

31 |
32 | 43 | 44 |
45 |
46 | 47 | 59 | 60 | 76 | 77 |
78 |
79 | 80 | 81 | 82 |
83 |
84 |
85 |
86 | 87 |
88 |

Reference

89 |
90 | 94 |
95 |
96 | 97 | 98 |
99 |
100 |
101 | 107 |
108 |
109 | 113 | 114 | 115 | -------------------------------------------------------------------------------- /docs/search.html: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 6 | 7 | 8 | 9 | Search — Django SuperTagging v0.5 documentation 10 | 11 | 12 | 21 | 22 | 23 | 24 | 25 | 26 | 29 | 30 | 31 | 32 | 33 |
34 |

Django SuperTagging v0.5 documentation

35 |
36 | 45 | 46 |
47 |
48 | 49 | 57 | 58 |
59 |
60 | 61 | 62 | 63 |
64 |
65 |
66 |
67 | 68 |

Search

69 |
70 | 71 |

72 | Please activate JavaScript to enable the search 73 | functionality. 74 |

75 |
76 |

77 | From here you can search these documents. Enter your search 78 | words into the box below and click "search". Note that the search 79 | function will automatically search for all of the words. Pages 80 | containing fewer words won't appear in the result list. 81 |

82 |
83 | 84 | 85 | 86 |
87 | 88 |
89 | 90 |
91 | 92 |
93 |
94 |
95 | 101 |
102 |
103 | 107 | 108 | 109 | -------------------------------------------------------------------------------- /example/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/callowayproject/django-supertagging/9b7d70343c2ff72e8f6dc971f6b873e1777ecc6c/example/__init__.py -------------------------------------------------------------------------------- /example/manage.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | from django.core.management import execute_manager 3 | try: 4 | import settings # Assumed to be in the same directory. 5 | except ImportError: 6 | import sys 7 | sys.stderr.write("Error: Can't find the file 'settings.py' in the directory containing %r. It appears you've customized things.\nYou'll have to run django-admin.py, passing it your settings module.\n(If the file settings.py does indeed exist, it's causing an ImportError somehow.)\n" % __file__) 8 | sys.exit(1) 9 | 10 | if __name__ == "__main__": 11 | execute_manager(settings) 12 | -------------------------------------------------------------------------------- /example/media/static/css/supertagloading.css: -------------------------------------------------------------------------------- 1 | .loading { 2 | background: #FFF; 3 | color: black; 4 | font-weight: bold; 5 | padding: 4px; 6 | border-radius: 5px; 7 | -o-border-radius: 5px; 8 | -moz-border-radius: 5px; 9 | -webkit-border-radius: 5px; 10 | -khtml-border-radius: 5px; 11 | border-bottom: 1px solid #999; 12 | border-right: 1px solid #999; 13 | border-left: 1px solid #999; 14 | } 15 | .loading.top { 16 | border-top-left-radius: 0px; 17 | border-top-right-radius: 0px; 18 | -moz-border-radius-topleft: 0px; 19 | -moz-border-radius-topright: 0px; 20 | -webkit-border-top-left-radius: 0px; 21 | -webkit-border-top-right-radius: 0px; 22 | } 23 | .loading-masked { overflow: hidden; } 24 | .loading-error { 25 | color: #FFF; 26 | background: red; 27 | } -------------------------------------------------------------------------------- /example/media/static/js/jquery.loading.1.6.4.min.js: -------------------------------------------------------------------------------- 1 | ;(function($){var L=$.loading=function(show,opts){return $('body').loading(show,opts,true);};$.fn.loading=function(show,opts,page){opts=toOpts(show,opts);var base=page?$.extend(true,{},L,L.pageOptions):L;return this.each(function(){var $el=$(this),l=$.extend(true,{},base,$.metadata?$el.metadata():null,opts);if(typeof l.onAjax=="boolean"){L.setAjax.call($el,l);}else{L.toggle.call($el,l);}});};var fixed={position:$.browser.msie?'absolute':'fixed'};$.extend(L,{version:"1.6.4",align:'top-left',pulse:'working error',mask:false,img:null,element:null,text:'Loading...',onAjax:undefined,delay:0,max:0,classname:'loading',imgClass:'loading-img',elementClass:'loading-element',maskClass:'loading-mask',css:{position:'absolute',whiteSpace:'nowrap',zIndex:1001},maskCss:{position:'absolute',opacity:.15,background:'#333',zIndex:101,display:'block',cursor:'wait'},cloneEvents:true,pageOptions:{page:true,align:'top-center',css:fixed,maskCss:fixed},html:'
',maskHtml:'
',maskedClass:'loading-masked',maskEvents:'mousedown mouseup keydown keypress',resizeEvents:'resize',working:{time:10000,text:'Still working...',run:function(l){var w=l.working,self=this;w.timeout=setTimeout(function(){self.height('auto').width('auto').text(l.text=w.text);l.place.call(self,l);},w.time);}},error:{time:100000,text:'Task may have failed...',classname:'loading-error',run:function(l){var e=l.error,self=this;e.timeout=setTimeout(function(){self.height('auto').width('auto').text(l.text=e.text).addClass(e.classname);l.place.call(self,l);},e.time);}},fade:{time:800,speed:'slow',run:function(l){var f=l.fade,s=f.speed,self=this;f.interval=setInterval(function(){self.fadeOut(s).fadeIn(s);},f.time);}},ellipsis:{time:300,run:function(l){var e=l.ellipsis,self=this;e.interval=setInterval(function(){var et=self.text(),t=l.text,i=dotIndex(t);self.text((et.length-i)<3?et+'.':t.substring(0,i));},e.time);function dotIndex(t){var x=t.indexOf('.');return x<0?t.length:x;}}},type:{time:100,run:function(l){var t=l.type,self=this;t.interval=setInterval(function(){var e=self.text(),el=e.length,txt=l.text;self.text(el==txt.length?txt.charAt(0):txt.substring(0,el+1));},t.time);}},toggle:function(l){var old=this.data('loading');if(old){if(l.show!==true)old.off.call(this,old,l);}else{if(l.show!==false)l.on.call(this,l);}},setAjax:function(l){if(l.onAjax){var self=this,count=0,A=l.ajax={start:function(){if(!count++)l.on.call(self,l);},stop:function(){if(!--count)l.off.call(self,l,l);}};this.bind('ajaxStart.loading',A.start).bind('ajaxStop.loading',A.stop);}else{this.unbind('ajaxStart.loading ajaxStop.loading');}},on:function(l,force){var p=l.parent=this.data('loading',l);if(l.max)l.maxout=setTimeout(function(){l.off.call(p,l,l);},l.max);if(l.delay&&!force){return l.timeout=setTimeout(function(){delete l.timeout;l.on.call(p,l,true);},l.delay);} 2 | if(l.mask)l.mask=l.createMask.call(p,l);l.display=l.create.call(p,l);if(l.img){l.initImg.call(p,l);}else if(l.element){l.initElement.call(p,l);}else{l.init.call(p,l);} 3 | p.trigger('loadingStart',[l]);},initImg:function(l){var self=this;l.imgElement=$('').bind('load',function(){l.init.call(self,l);});l.display.addClass(l.imgClass).append(l.imgElement);},initElement:function(l){l.element=$(l.element).clone(l.cloneEvents).show();l.display.addClass(l.elementClass).append(l.element);l.init.call(this,l);},init:function(l){l.place.call(l.display,l);if(l.pulse)l.initPulse.call(this,l);},initPulse:function(l){$.each(l.pulse.split(' '),function(){l[this].run.call(l.display,l);});},create:function(l){var el=$(l.html).addClass(l.classname).css(l.css).appendTo(this);if(l.text&&!l.img&&!l.element)el.text(l.originalText=l.text);$(window).bind(l.resizeEvents,l.resizer=function(){l.resize(l);});return el;},resize:function(l){l.parent.box=null;if(l.mask)l.mask.hide();l.place.call(l.display.hide(),l);if(l.mask)l.mask.show().css(l.parent.box);},createMask:function(l){var box=l.measure.call(this.addClass(l.maskedClass),l);l.handler=function(e){return l.maskHandler(e,l);};$(document).bind(l.maskEvents,l.handler);return $(l.maskHtml).addClass(l.maskClass).css(box).css(l.maskCss).appendTo(this);},maskHandler:function(e,l){var $els=$(e.target).parents().andSelf();if($els.filter('.'+l.classname).length!=0)return true;return!l.page&&$els.filter('.'+l.maskedClass).length==0;},place:function(l){var box=l.align,v='top',h='left';if(typeof box=="object"){box=$.extend(l.calc.call(this,v,h,l),box);}else{if(box!='top-left'){var s=box.split('-');if(s.length==1){v=h=s[0];}else{v=s[0];h=s[1];}} 4 | if(!this.hasClass(v))this.addClass(v);if(!this.hasClass(h))this.addClass(h);box=l.calc.call(this,v,h,l);} 5 | this.show().css(l.box=box);},calc:function(v,h,l){var box=$.extend({},l.measure.call(l.parent,l)),H=$.boxModel?this.height():this.innerHeight(),W=$.boxModel?this.width():this.innerWidth();if(v!='top'){var d=box.height-H;if(v=='center'){d/=2;}else if(v!='bottom'){d=0;}else if($.boxModel){d-=css(this,'paddingTop')+css(this,'paddingBottom');} 6 | box.top+=d;} 7 | if(h!='left'){var d=box.width-W;if(h=='center'){d/=2;}else if(h!='right'){d=0;}else if($.boxModel){d-=css(this,'paddingLeft')+css(this,'paddingRight');} 8 | box.left+=d;} 9 | box.height=H;box.width=W;return box;},measure:function(l){return this.box||(this.box=l.page?l.pageBox(l):l.elementBox(this,l));},elementBox:function(e,l){if(e.css('position')=='absolute'){var box={top:0,left:0};}else{var box=e.position();box.top+=css(e,'marginTop');box.left+=css(e,'marginLeft');} 10 | box.height=e.outerHeight();box.width=e.outerWidth();return box;},pageBox:function(l){var full=$.boxModel&&l.css.position!='fixed';return{top:0,left:0,height:get(full,'Height'),width:get(full,'Width')};function get(full,side){var doc=document;if(full){var s=side.toLowerCase(),d=$(doc)[s](),w=$(window)[s]();return d-css($(doc.body),'marginTop')>w?d:w;} 11 | var c='client'+side;return Math.max(doc.documentElement[c],doc.body[c]);}},off:function(old,l){this.data('loading',null);if(old.maxout)clearTimeout(old.maxout);if(old.timeout)return clearTimeout(old.timeout);if(old.pulse)old.stopPulse.call(this,old,l);if(old.originalText)old.text=old.originalText;if(old.mask)old.stopMask.call(this,old,l);$(window).unbind(old.resizeEvents,old.resizer);if(old.display)old.display.remove();if(old.parent)old.parent.trigger('loadingEnd',[old]);},stopPulse:function(old,l){$.each(old.pulse.split(' '),function(){var p=old[this];if(p.end)p.end.call(l.display,old,l);if(p.interval)clearInterval(p.interval);if(p.timeout)clearTimeout(p.timeout);});},stopMask:function(old,l){this.removeClass(l.maskedClass);$(document).unbind(old.maskEvents,old.handler);old.mask.remove();}});function toOpts(s,l){if(l===undefined){l=(typeof s=="boolean")?{show:s}:s;}else{l.show=s;} 12 | if(l&&(l.img||l.element)&&!l.pulse)l.pulse=false;if(l&&l.onAjax!==undefined&&l.show===undefined)l.show=false;return l;} 13 | function css(el,prop){var val=el.css(prop);return val=='auto'?0:parseFloat(val,10);}})(jQuery); -------------------------------------------------------------------------------- /example/settings.py: -------------------------------------------------------------------------------- 1 | # Django settings for example project. 2 | 3 | DEBUG = True 4 | TEMPLATE_DEBUG = DEBUG 5 | import os, sys 6 | APP = os.path.abspath(os.path.dirname(os.path.dirname(__file__))) 7 | PROJ_ROOT = os.path.abspath(os.path.dirname(__file__)) 8 | sys.path.append(APP) 9 | 10 | ADMINS = ( 11 | # ('Your Name', 'your_email@domain.com'), 12 | ) 13 | 14 | MANAGERS = ADMINS 15 | 16 | DATABASES = { 17 | 'default': { 18 | 'ENGINE': 'django.db.backends.sqlite3', # Add 'postgresql_psycopg2', 'postgresql', 'mysql', 'sqlite3' or 'oracle'. 19 | 'NAME': 'dev.db', # Or path to database file if using sqlite3. 20 | 'USER': '', # Not used with sqlite3. 21 | 'PASSWORD': '', # Not used with sqlite3. 22 | 'HOST': '', # Set to empty string for localhost. Not used with sqlite3. 23 | 'PORT': '', # Set to empty string for default. Not used with sqlite3. 24 | } 25 | } 26 | 27 | # Local time zone for this installation. Choices can be found here: 28 | # http://en.wikipedia.org/wiki/List_of_tz_zones_by_name 29 | # although not all choices may be available on all operating systems. 30 | # If running in a Windows environment this must be set to the same as your 31 | # system time zone. 32 | TIME_ZONE = 'America/Chicago' 33 | 34 | # Language code for this installation. All choices can be found here: 35 | # http://www.i18nguy.com/unicode/language-identifiers.html 36 | LANGUAGE_CODE = 'en-us' 37 | 38 | SITE_ID = 1 39 | 40 | # If you set this to False, Django will make some optimizations so as not 41 | # to load the internationalization machinery. 42 | USE_I18N = True 43 | 44 | # Absolute filesystem path to the directory that will hold user-uploaded files. 45 | # Example: "/home/media/media.lawrence.com/media/" 46 | MEDIA_ROOT = os.path.abspath(os.path.join(PROJ_ROOT, 'media', 'uploads')) 47 | 48 | # URL that handles the media served from MEDIA_ROOT. Make sure to use a 49 | # trailing slash. 50 | # Examples: "http://media.lawrence.com/media/", "http://example.com/media/" 51 | MEDIA_URL = '/uploads/' 52 | 53 | # Absolute path to the directory static files should be collected to. 54 | # Don't put anything in this directory yourself; store your static files 55 | # in apps' "static/" subdirectories and in STATICFILES_DIRS. 56 | # Example: "/home/media/media.lawrence.com/static/" 57 | STATIC_ROOT = os.path.abspath(os.path.join(PROJ_ROOT, 'media', 'static')) 58 | 59 | # URL prefix for static files. 60 | # Example: "http://media.lawrence.com/static/" 61 | STATIC_URL = '/static/' 62 | 63 | # Additional locations of static files 64 | STATICFILES_DIRS = ( 65 | # Put strings here, like "/home/html/static" or "C:/www/django/static". 66 | # Always use forward slashes, even on Windows. 67 | # Don't forget to use absolute paths, not relative paths. 68 | ) 69 | 70 | # List of finder classes that know how to find static files in 71 | # various locations. 72 | STATICFILES_FINDERS = ( 73 | 'django.contrib.staticfiles.finders.FileSystemFinder', 74 | 'django.contrib.staticfiles.finders.AppDirectoriesFinder', 75 | # 'django.contrib.staticfiles.finders.DefaultStorageFinder', 76 | ) 77 | 78 | # URL prefix for admin static files -- CSS, JavaScript and images. 79 | # Make sure to use a trailing slash. 80 | # Examples: "http://foo.com/static/admin/", "/static/admin/". 81 | ADMIN_MEDIA_PREFIX = '/static/admin/' 82 | 83 | # Make this unique, and don't share it with anybody. 84 | SECRET_KEY = 'g2_39yupn*6j4p*cg2%w643jiq-1n_annua*%i8+rq0dx9p=$n' 85 | 86 | # List of callables that know how to import templates from various sources. 87 | TEMPLATE_LOADERS = ( 88 | 'django.template.loaders.filesystem.Loader', 89 | 'django.template.loaders.app_directories.Loader', 90 | ) 91 | 92 | MIDDLEWARE_CLASSES = ( 93 | 'django.middleware.common.CommonMiddleware', 94 | 'django.contrib.sessions.middleware.SessionMiddleware', 95 | 'django.middleware.csrf.CsrfViewMiddleware', 96 | 'django.contrib.flatpages.middleware.FlatpageFallbackMiddleware', 97 | 'django.contrib.auth.middleware.AuthenticationMiddleware', 98 | 'django.contrib.messages.middleware.MessageMiddleware', 99 | ) 100 | 101 | ROOT_URLCONF = 'example.urls' 102 | 103 | TEMPLATE_DIRS = ( 104 | # Put strings here, like "/home/html/django_templates" or "C:/www/django/templates". 105 | # Always use forward slashes, even on Windows. 106 | # Don't forget to use absolute paths, not relative paths. 107 | os.path.join(PROJ_ROOT, 'templates') 108 | ) 109 | 110 | INSTALLED_APPS = ( 111 | 'django.contrib.admin', 112 | 'django.contrib.auth', 113 | 'django.contrib.contenttypes', 114 | 'django.contrib.sessions', 115 | 'django.contrib.sites', 116 | 'django.contrib.messages', 117 | 'django.contrib.staticfiles', 118 | 'django.contrib.flatpages', 119 | 'supertagging', 120 | 'south', 121 | ) 122 | SUPERTAGGING_SETTINGS = { 123 | 'ENABLED': True, 124 | 'WATCHED_FIELDS': { 125 | 'flatpages.flatpage': { 126 | 'fields': [{ 127 | 'name': 'content', 128 | 'process_type': 'TEXT/RAW', 129 | 'markup': True 130 | }] 131 | } 132 | }, 133 | 'INCLUDE_DISPLAY_FIELDS': True, 134 | 'AUTO_PROCESS': True, 135 | 'DEBUG': True, 136 | 'USE_QUEUE': False, 137 | 'REGISTER_MODELS': True, 138 | 'SUBSTITUTE_TAG_UPDATE': True, 139 | 'RESOLVE_PROPERTY_KEYS': True, 140 | 'REMOVE_REL_ON_DISABLE': True, 141 | 'OPEN_CALAIS': { 142 | 'PROCESSING_DIRECTIVES': { 143 | 'enableMetadataType': "GenericRelations,SocialTags", 144 | }, 145 | 'PROCESS_RELATIONS': True, 146 | 'PROCESS_TOPICS': True, 147 | 'PROCESS_SOCIALTAGS': True, 148 | }, 149 | 'MARKUP': { 150 | 'ENABLED': True 151 | } 152 | } 153 | 154 | try: 155 | from local_settings import * 156 | except ImportError: 157 | pass 158 | 159 | SUPERTAGGING_SETTINGS['OPEN_CALAIS']['API_KEY'] = OPEN_CALAIS_API_KEY -------------------------------------------------------------------------------- /example/templates/admin/change_form.html: -------------------------------------------------------------------------------- 1 | {% extends "admin/base_site.html" %} 2 | {% load i18n admin_modify adminmedia supertagging_tags %} 3 | 4 | {% block extrahead %}{{ block.super }} 5 | {% url admin:jsi18n as jsi18nurl %} 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | {{ media }} 17 | {% endblock %} 18 | 19 | {% block extrastyle %}{{ block.super }}{% endblock %} 20 | 21 | {% block coltype %}{% if ordered_objects %}colMS{% else %}colM{% endif %}{% endblock %} 22 | 23 | {% block bodyclass %}{{ opts.app_label }}-{{ opts.object_name.lower }} change-form{% endblock %} 24 | 25 | {% block breadcrumbs %}{% if not is_popup %} 26 | 32 | {% endif %}{% endblock %} 33 | 34 | {% block content %}
35 | {% block object-tools %} 36 | {% if change %}{% if not is_popup %} 37 | 42 | {% endif %}{% endif %} 43 | {% endblock %} 44 |
{% csrf_token %}{% block form_top %}{% endblock %} 45 |
46 | {% if is_popup %}{% endif %} 47 | {% if save_on_top %}{% submit_row %}{% endif %} 48 | {% if errors %} 49 |

50 | {% blocktrans count errors|length as counter %}Please correct the error below.{% plural %}Please correct the errors below.{% endblocktrans %} 51 |

52 |
    {% for error in adminform.form.non_field_errors %}
  • {{ error }}
  • {% endfor %}
53 | {% endif %} 54 | 55 | {% for fieldset in adminform %} 56 | {% include "admin/includes/fieldset.html" %} 57 | {% endfor %} 58 | 59 | {% block after_field_sets %}{% endblock %} 60 | 61 | {% for inline_admin_formset in inline_admin_formsets %} 62 | {% include inline_admin_formset.opts.template %} 63 | {% endfor %} 64 | 65 | {% block after_related_objects %}{% endblock %} 66 | 67 | {% submit_row %} 68 | 69 | {% if add %} 70 | 71 | {% endif %} 72 | 73 | {# JavaScript for prepopulated fields #} 74 | {% prepopulated_fields_js %} 75 | 76 |
77 |
78 | {% endblock %} 79 | -------------------------------------------------------------------------------- /example/templates/base.html: -------------------------------------------------------------------------------- 1 | 3 | 4 | 5 | 6 | 7 | {% block title %}{% endblock %} 8 | 9 | 10 | {% block content %} 11 | {% endblock %} 12 | 13 | 14 | -------------------------------------------------------------------------------- /example/templates/flatpages/default.html: -------------------------------------------------------------------------------- 1 | {% extends "base.html" %} 2 | {% load supertagging_tags %} 3 | {% block title %}{{ flatpage.title }}{% endblock %} 4 | {% block content %} 5 | {# bar graph code adapted from http://djangosnippets.org/snippets/44/ #} 6 | 33 | {% if flatpage.content__tagged %} 34 |

Tagged Content

35 | {{ flatpage.content__tagged|safe }} 36 |
37 | {% endif %} 38 |

Original Content

39 | {{ flatpage.content }} 40 |
41 |

Supertags

42 |
    43 | {% for tag in flatpage.supertags %} 44 |
  • {{ tag.display_name }} ({{ tag.stype}}) 45 | {% widthratio tag.relevance 1000 100 %}%
  • 46 | {% endfor %} 47 |
48 |
49 | 50 | {% endblock %} -------------------------------------------------------------------------------- /example/urls.py: -------------------------------------------------------------------------------- 1 | from django.conf.urls.defaults import * 2 | from django.conf import settings 3 | 4 | from django.contrib import admin 5 | admin.autodiscover() 6 | 7 | urlpatterns = patterns('', 8 | # (r'^supertagging/', include('supertagging.urls')), 9 | (r'^admin/', include(admin.site.urls)), 10 | ) 11 | 12 | urlpatterns = urlpatterns + patterns('', 13 | (r'^static/(?P.*)$', 'django.views.static.serve', 14 | {'document_root': settings.MEDIA_ROOT}), 15 | ) if settings.DEBUG else urlpatterson 16 | 17 | -------------------------------------------------------------------------------- /requirements.txt: -------------------------------------------------------------------------------- 1 | simplejson==2.0.9 -------------------------------------------------------------------------------- /setup.py: -------------------------------------------------------------------------------- 1 | import os 2 | from setuptools import setup, find_packages 3 | import supertagging 4 | 5 | 6 | try: 7 | reqs = open(os.path.join(os.path.dirname(__file__),'requirements.txt')).read() 8 | except (IOError, OSError): 9 | reqs = '' 10 | 11 | setup( 12 | name = 'supertagging', 13 | version=supertagging.get_version(), 14 | description = 'An interface to the Open Calais service for semantic markup.', 15 | author = 'Jose Soares', 16 | author_email = 'jose@linux.com', 17 | url = 'https://github.com/callowayproject/django-supertagging', 18 | packages = find_packages(), 19 | include_package_data = True, 20 | install_requires = reqs, 21 | classifiers = [ 22 | 'Environment :: Web Environment', 23 | 'Framework :: Django', 24 | 'Intended Audience :: Developers', 25 | 'License :: OSI Approved :: Apache Software License', 26 | 'Programming Language :: Python', 27 | 'Operating System :: OS Independent', 28 | ] 29 | ) 30 | -------------------------------------------------------------------------------- /supertagging/__init__.py: -------------------------------------------------------------------------------- 1 | __version_info__ = { 2 | 'major': 0, 3 | 'minor': 5, 4 | 'micro': 4, 5 | 'releaselevel': 'final', 6 | 'serial': 1 7 | } 8 | 9 | def get_version(): 10 | vers = ["%(major)i.%(minor)i" % __version_info__, ] 11 | 12 | if __version_info__['micro']: 13 | vers.append(".%(micro)i" % __version_info__) 14 | if __version_info__['releaselevel'] != 'final': 15 | vers.append('%(releaselevel)s%(serial)i' % __version_info__) 16 | return ''.join(vers) 17 | 18 | __version__ = get_version() 19 | 20 | class AlreadyRegistered(Exception): 21 | """ 22 | An attempt was made to register a model more than once. 23 | """ 24 | pass 25 | 26 | 27 | registry = [] 28 | 29 | 30 | def register(model, tag_descriptor_attr='supertags', 31 | tagged_item_manager_attr='supertagged'): 32 | """ 33 | Sets the given model class up for working with supertags. 34 | """ 35 | 36 | from supertagging.managers import ModelTaggedItemManager, TagDescriptor 37 | from supertagging.models import SuperTaggedItem 38 | from django.contrib.contenttypes.generic import GenericRelation 39 | 40 | if model in registry: 41 | raise AlreadyRegistered("The model '%s' has already been " 42 | "registered." % model._meta.object_name) 43 | if hasattr(model, tag_descriptor_attr): 44 | raise AttributeError("'%s' already has an attribute '%s'. You must " 45 | "provide a custom tag_descriptor_attr to register." % ( 46 | model._meta.object_name, 47 | tag_descriptor_attr, 48 | ) 49 | ) 50 | if hasattr(model, tagged_item_manager_attr): 51 | raise AttributeError("'%s' already has an attribute '%s'. You must " 52 | "provide a custom tagged_item_manager_attr to register." % ( 53 | model._meta.object_name, 54 | tagged_item_manager_attr, 55 | ) 56 | ) 57 | 58 | # Add tag descriptor 59 | setattr(model, tag_descriptor_attr, TagDescriptor()) 60 | 61 | # Add custom manager 62 | ModelTaggedItemManager().contribute_to_class(model, tagged_item_manager_attr) 63 | 64 | # Add a reverse generic relationship to supertaggeditems 65 | GenericRelation(SuperTaggedItem).contribute_to_class(model, 'supertaggeditem_set') 66 | 67 | # Finally register in registry 68 | registry.append(model) -------------------------------------------------------------------------------- /supertagging/admin.py: -------------------------------------------------------------------------------- 1 | import django 2 | from django.contrib import admin 3 | from django.contrib.contenttypes.models import ContentType 4 | from django.utils.translation import ugettext, ugettext_lazy 5 | from django.utils.encoding import force_unicode, smart_str 6 | from django.http import HttpResponseRedirect 7 | 8 | from supertagging.models import SuperTag, SuperTaggedItem, SuperTagRelation 9 | from supertagging.models import SuperTaggedRelationItem, SuperTagProcessQueue 10 | 11 | from supertagging.settings import INCLUDE_DISPLAY_FIELDS 12 | from django.contrib.admin.views.main import (ChangeList, ALL_VAR, ORDER_VAR, 13 | ORDER_TYPE_VAR, PAGE_VAR, SEARCH_VAR, TO_FIELD_VAR, 14 | IS_POPUP_VAR, ERROR_FLAG) 15 | 16 | class SupertagChangeList(ChangeList): 17 | """ 18 | Lets list_editable work even if it is a popup 19 | """ 20 | def __init__(self, request, model, list_display, list_display_links, list_filter, date_hierarchy, search_fields, list_select_related, list_per_page, list_editable, model_admin): 21 | self.model = model 22 | self.opts = model._meta 23 | self.lookup_opts = self.opts 24 | self.root_query_set = model_admin.queryset(request) 25 | self.list_display = list_display 26 | self.list_display_links = list_display_links 27 | self.list_filter = list_filter 28 | self.date_hierarchy = date_hierarchy 29 | self.search_fields = search_fields 30 | self.list_select_related = list_select_related 31 | self.list_per_page = list_per_page 32 | self.model_admin = model_admin 33 | 34 | # Get search parameters from the query string. 35 | try: 36 | self.page_num = int(request.GET.get(PAGE_VAR, 0)) 37 | except ValueError: 38 | self.page_num = 0 39 | self.show_all = ALL_VAR in request.GET 40 | self.is_popup = IS_POPUP_VAR in request.GET 41 | self.to_field = request.GET.get(TO_FIELD_VAR) 42 | self.params = dict(request.GET.items()) 43 | if PAGE_VAR in self.params: 44 | del self.params[PAGE_VAR] 45 | if ERROR_FLAG in self.params: 46 | del self.params[ERROR_FLAG] 47 | 48 | self.list_editable = list_editable 49 | self.order_field, self.order_type = self.get_ordering() 50 | self.query = request.GET.get(SEARCH_VAR, '') 51 | self.query_set = self.get_query_set() 52 | self.get_results(request) 53 | self.title = (self.is_popup and ugettext('Select %s') % force_unicode(self.opts.verbose_name) or ugettext('Select %s to change') % force_unicode(self.opts.verbose_name)) 54 | self.filter_specs, self.has_filters = self.get_filters(request) 55 | self.pk_attname = self.lookup_opts.pk.attname 56 | 57 | def lock_items(modeladmin, request, queryset): 58 | queryset.update(locked=True) 59 | lock_items.short_description = "Lock selected Queue Items" 60 | 61 | def unlock_items(modeladmin, request, queryset): 62 | queryset.update(locked=False) 63 | unlock_items.short_description = "Unlock selected Queue Items" 64 | 65 | class SuperTagAdmin(admin.ModelAdmin): 66 | list_display = ('name', 'enabled', 'substitute', 'stype') 67 | ordering = ('name', ) 68 | search_fields = ('stype', 'name', ) 69 | list_filter = ('stype', ) 70 | 71 | actions = ['disable_tag', 'enable_tag'] 72 | 73 | raw_id_fields = ['substitute',] 74 | if INCLUDE_DISPLAY_FIELDS: 75 | raw_id_fields.append('related') 76 | 77 | def disable_tag(self, request, queryset): 78 | message_bit = "" 79 | for tag in queryset: 80 | message_bit = "%s %s," % (message_bit, tag.name) 81 | tag.enabled=False 82 | tag.save() 83 | 84 | self.message_user(request, "Tag(s): %s were Disabled." % message_bit) 85 | disable_tag.short_description = "Disable selected tags" 86 | 87 | 88 | def enable_tag(self, request, queryset): 89 | message_bit = "" 90 | for tag in queryset: 91 | message_bit = "%s %s," % (message_bit, tag.name) 92 | tag.enabled=True 93 | tag.save() 94 | 95 | self.message_user(request, "Tag(s): %s were Enabled." % message_bit) 96 | enable_tag.short_description = "Enable selected tags" 97 | 98 | class SuperTaggedItemAdmin(admin.ModelAdmin): 99 | list_display = ('tag_name', 'tag_type', 'field', 'relevance_bar', 'ignore') 100 | # if django.VERSION[1] > 1: 101 | # list_filter = ('field', 'tag__stype') 102 | # else: 103 | # list_filter = ('field', ) 104 | 105 | #search_fields = ('tag__name',) 106 | raw_id_fields = ('tag',) 107 | list_editable = ('ignore',) 108 | 109 | class Media: 110 | css = {'all': ('css/supertagloading.css',)} 111 | js = ('js/jquery.loading.1.6.4.min.js',) 112 | 113 | def tag_name(self, obj): 114 | if INCLUDE_DISPLAY_FIELDS: 115 | return obj.tag.display_name 116 | return obj.tag.name 117 | 118 | def tag_type(self, obj): 119 | return obj.tag.stype 120 | 121 | def get_changelist(self, request, **kwargs): 122 | """ 123 | Returns the ChangeList class for use on the changelist page. 124 | """ 125 | return SupertagChangeList 126 | 127 | def changelist_view(self, request, extra_context=None): 128 | if request.method == 'POST' and '_update_tags' in request.POST: 129 | ctype_id = request.GET.get(u'content_type__id', [False,]) 130 | obj_id = request.GET.get('object_id', [False]) 131 | if ctype_id == False or obj_id == False: 132 | return HttpResponseRedirect(request.get_full_path()) 133 | ctype = ContentType.objects.get(id=ctype_id) 134 | obj = ctype.get_object_for_this_type(id=obj_id) 135 | from supertagging.modules import process 136 | process(obj) 137 | msg = "Supertags have been updated." 138 | self.message_user(request, msg) 139 | return HttpResponseRedirect(request.get_full_path()) 140 | else: 141 | return super(SuperTaggedItemAdmin, self).changelist_view(request, extra_context) 142 | 143 | def relevance_bar(self, obj): 144 | from django.template import Context 145 | from django.template.loader import get_template 146 | if obj.relevance is not None: 147 | relevance = "%d%%" % (obj.relevance / 10.0) 148 | else: 149 | relevance = "0" 150 | 151 | tmpl = get_template("admin/supertagging/relevancebar.html") 152 | ctxt = Context({'relevance': relevance}) 153 | return tmpl.render(ctxt) 154 | relevance_bar.allow_tags = True 155 | relevance_bar.admin_order_field = 'relevance' 156 | relevance_bar.short_description = 'Relevance' 157 | 158 | def get_actions(self, request): 159 | return [] 160 | 161 | 162 | class SuperTaggedRelationItemAdmin(admin.ModelAdmin): 163 | list_display = ('content_object', 'relation', 'field', 'process_type', 'item_date') 164 | list_filter = ('process_type', 'field') 165 | 166 | raw_id_fields = ('relation',) 167 | 168 | 169 | class SuperTagRelationAdmin(admin.ModelAdmin): 170 | list_display = ('tag', 'name', 'stype',) 171 | ordering = ('tag', ) 172 | search_fields = ('stype', 'name', 'tag__name') 173 | list_filter = ('stype', 'name', ) 174 | 175 | raw_id_fields = ('tag',) 176 | 177 | 178 | class SuperTagProcessQueueAdmin(admin.ModelAdmin): 179 | list_display = ('__unicode__', 'locked') 180 | actions = [lock_items, unlock_items] 181 | 182 | 183 | admin.site.register(SuperTag, SuperTagAdmin) 184 | admin.site.register(SuperTaggedItem, SuperTaggedItemAdmin) 185 | admin.site.register(SuperTagRelation, SuperTagRelationAdmin) 186 | admin.site.register(SuperTaggedRelationItem, SuperTaggedRelationItemAdmin) 187 | admin.site.register(SuperTagProcessQueue, SuperTagProcessQueueAdmin) -------------------------------------------------------------------------------- /supertagging/fields.py: -------------------------------------------------------------------------------- 1 | """Copyright (c) 2009-2010 Gintautas Miliauskas 2 | 3 | Permission is hereby granted, free of charge, to any person 4 | obtaining a copy of this software and associated documentation 5 | files (the "Software"), to deal in the Software without 6 | restriction, including without limitation the rights to use, 7 | copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | copies of the Software, and to permit persons to whom the 9 | Software is furnished to do so, subject to the following 10 | conditions: 11 | 12 | The above copyright notice and this permission notice shall be 13 | included in all copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 16 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES 17 | OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 18 | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT 19 | HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, 20 | WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 21 | FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 22 | OTHER DEALINGS IN THE SOFTWARE.""" 23 | from copy import deepcopy 24 | from base64 import b64encode, b64decode 25 | from zlib import compress, decompress 26 | try: 27 | from cPickle import loads, dumps 28 | except ImportError: 29 | from pickle import loads, dumps 30 | 31 | from django.db import models 32 | from django.utils.encoding import force_unicode 33 | 34 | DEFAULT_PROTOCOL = 2 35 | 36 | class PickledObject(str): 37 | """ 38 | A subclass of string so it can be told whether a string is a pickled 39 | object or not (if the object is an instance of this class then it must 40 | [well, should] be a pickled one). 41 | 42 | Only really useful for passing pre-encoded values to ``default`` 43 | with ``dbsafe_encode``, not that doing so is necessary. If you 44 | remove PickledObject and its references, you won't be able to pass 45 | in pre-encoded values anymore, but you can always just pass in the 46 | python objects themselves. 47 | 48 | """ 49 | 50 | 51 | def dbsafe_encode(value, compress_object=False, pickle_protocol=DEFAULT_PROTOCOL): 52 | # We use deepcopy() here to avoid a problem with cPickle, where dumps 53 | # can generate different character streams for same lookup value if 54 | # they are referenced differently. 55 | # The reason this is important is because we do all of our lookups as 56 | # simple string matches, thus the character streams must be the same 57 | # for the lookups to work properly. See tests.py for more information. 58 | if not compress_object: 59 | value = b64encode(dumps(deepcopy(value), pickle_protocol)) 60 | else: 61 | value = b64encode(compress(dumps(deepcopy(value), pickle_protocol))) 62 | return PickledObject(value) 63 | 64 | 65 | def dbsafe_decode(value, compress_object=False): 66 | if not compress_object: 67 | value = loads(b64decode(value)) 68 | else: 69 | value = loads(decompress(b64decode(value))) 70 | return value 71 | 72 | 73 | class PickledObjectField(models.Field): 74 | """ 75 | A field that will accept *any* python object and store it in the 76 | database. PickledObjectField will optionally compress its values if 77 | declared with the keyword argument ``compress=True``. 78 | 79 | Does not actually encode and compress ``None`` objects (although you 80 | can still do lookups using None). This way, it is still possible to 81 | use the ``isnull`` lookup type correctly. 82 | """ 83 | 84 | __metaclass__ = models.SubfieldBase 85 | 86 | def __init__(self, *args, **kwargs): 87 | self.compress = kwargs.pop('compress', False) 88 | self.protocol = kwargs.pop('protocol', DEFAULT_PROTOCOL) 89 | kwargs.setdefault('editable', False) 90 | super(PickledObjectField, self).__init__(*args, **kwargs) 91 | 92 | def get_default(self): 93 | """ 94 | Returns the default value for this field. 95 | 96 | The default implementation on models.Field calls force_unicode 97 | on the default, which means you can't set arbitrary Python 98 | objects as the default. To fix this, we just return the value 99 | without calling force_unicode on it. Note that if you set a 100 | callable as a default, the field will still call it. It will 101 | *not* try to pickle and encode it. 102 | 103 | """ 104 | if self.has_default(): 105 | if callable(self.default): 106 | return self.default() 107 | return self.default 108 | # If the field doesn't have a default, then we punt to models.Field. 109 | return super(PickledObjectField, self).get_default() 110 | 111 | def to_python(self, value): 112 | """ 113 | B64decode and unpickle the object, optionally decompressing it. 114 | 115 | If an error is raised in de-pickling and we're sure the value is 116 | a definite pickle, the error is allowed to propogate. If we 117 | aren't sure if the value is a pickle or not, then we catch the 118 | error and return the original value instead. 119 | 120 | """ 121 | if value is not None: 122 | try: 123 | value = dbsafe_decode(value, self.compress) 124 | except: 125 | # If the value is a definite pickle; and an error is raised in 126 | # de-pickling it should be allowed to propogate. 127 | if isinstance(value, PickledObject): 128 | raise 129 | return value 130 | 131 | def get_db_prep_value(self, value, connection=None, prepared=False): 132 | """ 133 | Pickle and b64encode the object, optionally compressing it. 134 | 135 | The pickling protocol is specified explicitly (by default 2), 136 | rather than as -1 or HIGHEST_PROTOCOL, because we don't want the 137 | protocol to change over time. If it did, ``exact`` and ``in`` 138 | lookups would likely fail, since pickle would now be generating 139 | a different string. 140 | 141 | """ 142 | if value is not None and not isinstance(value, PickledObject): 143 | # We call force_unicode here explicitly, so that the encoded string 144 | # isn't rejected by the postgresql_psycopg2 backend. Alternatively, 145 | # we could have just registered PickledObject with the psycopg 146 | # marshaller (telling it to store it like it would a string), but 147 | # since both of these methods result in the same value being stored, 148 | # doing things this way is much easier. 149 | value = force_unicode(dbsafe_encode(value, self.compress, self.protocol)) 150 | return value 151 | 152 | def value_to_string(self, obj): 153 | value = self._get_val_from_obj(obj) 154 | return self.get_db_prep_value(value) 155 | 156 | def get_internal_type(self): 157 | return 'TextField' 158 | 159 | def get_db_prep_lookup(self, lookup_type, value, connection=None, prepared=False): 160 | if lookup_type not in ['exact', 'in', 'isnull']: 161 | raise TypeError('Lookup type %s is not supported.' % lookup_type) 162 | # The Field model already calls get_db_prep_value before doing the 163 | # actual lookup, so all we need to do is limit the lookup types. 164 | try: 165 | return super(PickledObjectField, self).get_db_prep_lookup( 166 | lookup_type, value, connection=connection, prepared=prepared) 167 | except TypeError: 168 | # Try not to break on older versions of Django, where the 169 | # `connection` and `prepared` parameters are not available. 170 | return super(PickledObjectField, self).get_db_prep_lookup( 171 | lookup_type, value) 172 | 173 | 174 | # South support; see http://south.aeracode.org/docs/tutorial/part4.html#simple-inheritance 175 | try: 176 | from south.modelsinspector import add_introspection_rules 177 | except ImportError: 178 | pass 179 | else: 180 | add_introspection_rules([], [r"^supertagging\.fields\.PickledObjectField"]) -------------------------------------------------------------------------------- /supertagging/handlers.py: -------------------------------------------------------------------------------- 1 | from django.db.models import get_model 2 | from django.db.models.signals import post_save, post_delete 3 | 4 | from supertagging.settings import USE_QUEUE, MODULES, AUTO_PROCESS, ST_DEBUG, MARKUP, MARKUP_FIELD_SUFFIX, REGISTER_MODELS 5 | from supertagging import register 6 | 7 | def save_handler(sender, instance, **kwargs): 8 | if instance: 9 | from supertagging.modules import process, add_to_queue 10 | if USE_QUEUE: 11 | add_to_queue(instance) 12 | else: 13 | process(instance) 14 | 15 | def delete_handler(sender, instance, **kwargs): 16 | if instance: 17 | from supertagging.modules import clean_up, remove_from_queue 18 | if USE_QUEUE: 19 | remove_from_queue(instance) 20 | else: 21 | clean_up(instance) 22 | 23 | def setup_handlers(): 24 | try: 25 | for k,v in MODULES.items(): 26 | app_label, model_name = k.split('.') 27 | model = get_model(app_label, model_name) 28 | 29 | # Add a tag attribute to the instance. 30 | if REGISTER_MODELS: 31 | register(model) 32 | 33 | # Setup post save and post delete handlers if model exists 34 | if model and AUTO_PROCESS: 35 | post_save.connect(save_handler, sender=model) 36 | post_delete.connect(delete_handler, sender=model) 37 | 38 | if MARKUP: 39 | # Add a custom attribute to a model with a marked up 40 | # version of the field specified. 41 | for f in v.get('fields', []): 42 | field = f.get('name', None) 43 | markup = f.get('markup', True) 44 | if markup and MARKUP and field: 45 | from supertagging.markup import get_handler_module 46 | handler = get_handler_module(f.get('markup_handler', None)) 47 | nfield = "%s__%s" % (field, MARKUP_FIELD_SUFFIX) 48 | setattr(model, nfield, handler(model, field)) 49 | 50 | except Exception, e: 51 | if ST_DEBUG: raise Exception(e) 52 | -------------------------------------------------------------------------------- /supertagging/management/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/callowayproject/django-supertagging/9b7d70343c2ff72e8f6dc971f6b873e1777ecc6c/supertagging/management/__init__.py -------------------------------------------------------------------------------- /supertagging/management/commands/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/callowayproject/django-supertagging/9b7d70343c2ff72e8f6dc971f6b873e1777ecc6c/supertagging/management/commands/__init__.py -------------------------------------------------------------------------------- /supertagging/management/commands/st_migrate_pickled_object_fields.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python 2 | import time 3 | from django.core.management.base import BaseCommand 4 | from django.db import transaction, connection 5 | from supertagging.models import SuperTag, SuperTagRelation, SuperTaggedItem, SuperTaggedRelationItem 6 | try: 7 | import cPickle as pickle 8 | except ImportError: 9 | import pickle 10 | 11 | class Command(BaseCommand): 12 | def handle(self, *args, **kwargs): 13 | c = Core() 14 | c.execute() 15 | 16 | 17 | def ResultIter(cursor, arraysize=1000): 18 | 'An iterator that uses fetchmany to keep memory usage down' 19 | while True: 20 | results = cursor.fetchmany(arraysize) 21 | if not results: 22 | break 23 | for result in results: 24 | yield result 25 | 26 | 27 | def convert_fields(model, field): 28 | print "-- Processing: %s" % model 29 | cursor = connection.cursor() 30 | 31 | sql = "SELECT id, %s FROM %s ORDER BY id LIMIT 100" % (field, model._meta.db_table) 32 | cursor.execute(sql) 33 | 34 | for result in ResultIter(cursor): 35 | pid, value = result 36 | print "-- Fixing row: %s" % pid 37 | 38 | try: 39 | old_data = pickle.loads(str(value)) 40 | except Exception, e: 41 | print "-- Error loading old data, continuing.. (%s)" % e 42 | old_data = value 43 | 44 | try: 45 | item = model.objects.get(pk=pid) 46 | if hasattr(item, field): 47 | setattr(item, field, old_data) 48 | item.save() 49 | except Exception, e: 50 | print "-- Error occuring while saving %s: %s" % (model, e) 51 | 52 | print "-- Done Processing: %s" % model 53 | 54 | class Core(object): 55 | """ 56 | Convert the old Pickled data 57 | """ 58 | @transaction.commit_manually 59 | def execute(self): 60 | print "Begin Pickled Field Conversion" 61 | 62 | convert_fields(SuperTag, "properties") 63 | transaction.commit() 64 | 65 | convert_fields(SuperTagRelation, "properties") 66 | transaction.commit() 67 | 68 | convert_fields(SuperTaggedItem, "instances") 69 | transaction.commit() 70 | 71 | convert_fields(SuperTaggedRelationItem, "instances") 72 | transaction.commit() 73 | 74 | print "Done" 75 | -------------------------------------------------------------------------------- /supertagging/management/commands/st_process_queue.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python 2 | import time 3 | from django.core.management.base import BaseCommand 4 | from django.db import transaction 5 | from django.conf import settings 6 | from django.contrib.contenttypes.models import ContentType 7 | 8 | from supertagging.models import SuperTagProcessQueue 9 | from supertagging.modules import process 10 | from supertagging import settings as st_settings 11 | 12 | class Command(BaseCommand): 13 | def handle(self, *args, **kwargs): 14 | c = Core() 15 | c.execute() 16 | 17 | 18 | class Core(object): 19 | """ 20 | The Core is responsible for driving Supertagging 21 | """ 22 | @transaction.commit_manually 23 | def execute(self): 24 | """ 25 | The main execution path; this function is invoked by a scheduler. 26 | """ 27 | processed, failed, objs_to_del, objs_to_reset = 0, 0, [], [] 28 | print 'Getting objects to process...' 29 | objects = SuperTagProcessQueue.objects.filter(locked=False) 30 | print 'Done. %s object(s)' % len(objects) 31 | print 'Locking object(s)...' 32 | SuperTagProcessQueue.objects.filter(locked=False).update(locked=True) 33 | transaction.commit() 34 | print 'Done.' 35 | for obj in objects: 36 | print 'Processing: %s...' % obj 37 | try: 38 | print 'Start processing object with calais...' 39 | process(obj.content_object) 40 | print 'Done' 41 | objs_to_del.append(obj.pk) 42 | print 'Committing calais data...' 43 | transaction.commit() 44 | print 'Done' 45 | processed += 1 46 | except Exception, e: 47 | print 'Failed to process object, rolling back... %s' % e 48 | objs_to_reset.append(obj.pk) 49 | transaction.rollback() 50 | print 'Done' 51 | failed += 1 52 | time.sleep(1) 53 | 54 | print 'Unlocking objects...' 55 | SuperTagProcessQueue.objects.filter(pk__in=objs_to_reset).update(locked=False) 56 | transaction.commit() 57 | print 'Done' 58 | print 'Deleting processed objects from queue...' 59 | SuperTagProcessQueue.objects.filter(pk__in=objs_to_del).delete() 60 | transaction.commit() 61 | print 'Done' 62 | print '%s of %s objects processed. %s failed.' % (processed, 63 | processed + failed, failed) 64 | -------------------------------------------------------------------------------- /supertagging/managers.py: -------------------------------------------------------------------------------- 1 | """ 2 | Custom managers for Django models registered with the supertagging 3 | application. 4 | """ 5 | from django.contrib.contenttypes.models import ContentType 6 | from django.db import models 7 | from supertagging.models import SuperTag, SuperTaggedItem 8 | 9 | class ModelTagManager(models.Manager): 10 | """ 11 | A manager for retrieving tags for a particular model. 12 | """ 13 | def get_query_set(self): 14 | ctype = ContentType.objects.get_for_model(self.model) 15 | return SuperTag.objects.filter( 16 | items__content_type__pk=ctype.pk, 17 | items__ignore=False).distinct() 18 | 19 | def cloud(self, *args, **kwargs): 20 | return SuperTag.objects.cloud_for_model(self.model, *args, **kwargs) 21 | 22 | def related(self, tags, *args, **kwargs): 23 | return SuperTag.objects.related_for_model(tags, self.model, *args, **kwargs) 24 | 25 | def usage(self, *args, **kwargs): 26 | return SuperTag.objects.usage_for_model(self.model, *args, **kwargs) 27 | 28 | class ModelTaggedItemManager(models.Manager): 29 | """ 30 | A manager for retrieving model instances based on their tags. 31 | """ 32 | def related_to(self, obj, queryset=None, num=None): 33 | if queryset is None: 34 | return SuperTaggedItem.objects.get_related(obj, self.model, num=num) 35 | else: 36 | return SuperTaggedItem.objects.get_related(obj, queryset, num=num) 37 | 38 | def with_all(self, tags, queryset=None): 39 | if queryset is None: 40 | return SuperTaggedItem.objects.get_by_model(self.model, tags) 41 | else: 42 | return SuperTaggedItem.objects.get_by_model(queryset, tags) 43 | 44 | def with_any(self, tags, queryset=None): 45 | if queryset is None: 46 | return SuperTaggedItem.objects.get_union_by_model(self.model, tags) 47 | else: 48 | return SuperTaggedItem.objects.get_union_by_model(queryset, tags) 49 | 50 | class TagDescriptor(object): 51 | """ 52 | A descriptor which provides access to a ``ModelTagManager`` for 53 | model classes and simple retrieval, updating and deletion of tags 54 | for model instances. 55 | """ 56 | def __get__(self, instance, owner): 57 | if not instance: 58 | tag_manager = ModelTagManager() 59 | tag_manager.model = owner 60 | return tag_manager 61 | else: 62 | return SuperTag.objects.get_for_object(instance) 63 | 64 | def __set__(self, instance, value): 65 | # Cannot update tags 66 | raise NotImplementedError 67 | 68 | def __delete__(self, instance): 69 | raise NotImplementedError -------------------------------------------------------------------------------- /supertagging/markup.py: -------------------------------------------------------------------------------- 1 | from django.contrib.contenttypes.models import ContentType 2 | from django.template.loader import render_to_string, get_template 3 | from django.core.cache import cache 4 | from django.db.models import get_model 5 | 6 | from supertagging import settings 7 | from supertagging.models import SuperTaggedItem 8 | 9 | class MarkupHandler(object): 10 | """ 11 | Default Markup handler 12 | """ 13 | def __init__(self, model, field): 14 | self.field = field 15 | self.model = model 16 | self.content_type = ContentType.objects.get_for_model(model) 17 | 18 | def __get__(self, instance, owner): 19 | if not instance: 20 | return 21 | 22 | data = self._get_cached_value(instance) 23 | if data: 24 | return data 25 | 26 | try: 27 | data = self.handle(instance) 28 | except Exception, e: 29 | data = getattr(instance, self.field) 30 | if settings.ST_DEBUG: raise Exception(e) 31 | 32 | cache.set(self._get_cache_key(instance), data, settings.MARKUP_CONTENT_CACHE_TIMEOUT) 33 | return data 34 | 35 | def _get_cache_key(self, instance=None): 36 | if instance: 37 | return "ST_HANDLER.%s.%s.%s" % (self.content_type.pk, instance.pk, self.field) 38 | return None 39 | 40 | def _get_cached_value(self, instance=None): 41 | if instance and self._get_cache_key(instance): 42 | key = self._get_cache_key(instance) 43 | return cache.get(key) 44 | return None 45 | 46 | def handle(self, instance=None): 47 | if instance: 48 | return markup_content(instance, self.field) 49 | return "" 50 | 51 | 52 | def invalidate_markup_cache(obj, field): 53 | if not obj: 54 | return 55 | 56 | ctype = ContentType.objects.get_for_model(obj) 57 | key = "ST_HANDLER.%s.%s.%s" % (ctype.pk, obj.pk, field) 58 | cache.delete(key) 59 | 60 | def get_handler_module(module): 61 | if not module: 62 | return MarkupHandler 63 | 64 | mod, f, i, fn = None, None, None, None 65 | msplit = module.split(".") 66 | if len(msplit) == 1: 67 | mod = msplit[0] 68 | else: 69 | f = msplit[:-1] 70 | i = msplit[-1:] 71 | fn = ".".join(f) 72 | 73 | if mod: 74 | try: 75 | return __import__(mod) 76 | except ImportError: 77 | return MarkupHandler 78 | else: 79 | try: 80 | mod = __import__(fn, fromlist=f) 81 | return getattr(mod, i[0]) 82 | except: 83 | return MarkupHandler 84 | 85 | class FailedMarkupValidation(Exception): 86 | def __init__(self, value): 87 | self.parameter = value 88 | def __str__(self): 89 | return repr(self.parameter) 90 | 91 | def tag_instance_cmp(x, y): 92 | if isinstance(x, dict) and isinstance(y, dict): 93 | return cmp(x['offset'],y['offset']) 94 | return cmp(1, 1) 95 | 96 | def markup_content(obj, field, markup_template='supertagging/markup.html'): 97 | """ 98 | Takes all the items (SuperTaggedItems), and retrieves all the 'instances' to 99 | embed the markup_template. 100 | """ 101 | ctype = ContentType.objects.get_for_model(obj) 102 | items = SuperTaggedItem.objects.filter( 103 | content_type__pk=ctype.pk, object_id=obj.pk, 104 | relevance__gte=settings.MIN_RELEVANCE_MARKUP).select_related() 105 | 106 | value = getattr(obj, field, '') 107 | full = [] 108 | for item in items: 109 | if not item.instances: 110 | continue 111 | i = item.instances 112 | skip = False 113 | for v in i: 114 | if isinstance(v, list): 115 | # TODO: figure out a better way to handle list of dicts 116 | skip = True 117 | continue 118 | if isinstance(v, dict): 119 | v['supertag'] = item.tag 120 | 121 | if not skip: 122 | full.extend(i) 123 | 124 | # Sort the list by the inner dict offset value in reverse 125 | full.sort(tag_instance_cmp, reverse=True) 126 | 127 | for n, i in enumerate(full): 128 | if 'offset' in i and 'length' in i and 'exact' in i: 129 | off, le, act_val = i['offset'], i['length'], i['exact'] 130 | if act_val.lower() in settings.MARKUP_EXCLUDES: 131 | continue 132 | else: 133 | continue 134 | 135 | # This tests to make sure the next tag does 136 | # not overlap the current tag 137 | if n != 0: 138 | if 'offset' in full[n-1]: 139 | prev_off = full[n-1]['offset'] 140 | if ((off+1)+le) > prev_off: 141 | continue 142 | 143 | # Validate that the data matches the data returned by calais 144 | if not value[off:(off+le)] == act_val: 145 | raise FailedMarkupValidation( 146 | "Markup failed validation: Offset: %s: \"%s\" didn't match \"%s\"" % (off, value[off:(off+le)], act_val)) 147 | break 148 | 149 | tag = i['supertag'] 150 | val = render_to_string(markup_template, {'tag': tag, 'actual_value': act_val}) 151 | pre, suf, repl = '','','' 152 | 153 | pre = value[:off] 154 | suf = value[(off+le):] 155 | repl = value[off:(off+le)] 156 | 157 | value = pre+val+suf 158 | 159 | return value -------------------------------------------------------------------------------- /supertagging/migrations/0002_auto__add_field_supertaggeditem_ignore.py: -------------------------------------------------------------------------------- 1 | # encoding: utf-8 2 | import datetime 3 | from south.db import db 4 | from south.v2 import SchemaMigration 5 | from django.db import models 6 | 7 | class Migration(SchemaMigration): 8 | 9 | def forwards(self, orm): 10 | 11 | # Adding field 'SuperTaggedItem.ignore' 12 | db.add_column('supertagging_supertaggeditem', 'ignore', self.gf('django.db.models.fields.BooleanField')(default=False), keep_default=False) 13 | 14 | 15 | def backwards(self, orm): 16 | 17 | # Deleting field 'SuperTaggedItem.ignore' 18 | db.delete_column('supertagging_supertaggeditem', 'ignore') 19 | 20 | 21 | models = { 22 | 'contenttypes.contenttype': { 23 | 'Meta': {'ordering': "('name',)", 'unique_together': "(('app_label', 'model'),)", 'object_name': 'ContentType', 'db_table': "'django_content_type'"}, 24 | 'app_label': ('django.db.models.fields.CharField', [], {'max_length': '100'}), 25 | 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), 26 | 'model': ('django.db.models.fields.CharField', [], {'max_length': '100'}), 27 | 'name': ('django.db.models.fields.CharField', [], {'max_length': '100'}) 28 | }, 29 | 'supertagging.supertag': { 30 | 'Meta': {'ordering': "('name',)", 'object_name': 'SuperTag'}, 31 | 'calais_id': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '255'}), 32 | 'description': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}), 33 | 'display_name': ('django.db.models.fields.CharField', [], {'max_length': '150', 'null': 'True', 'blank': 'True'}), 34 | 'enabled': ('django.db.models.fields.BooleanField', [], {'default': 'True'}), 35 | 'icon': ('django.db.models.fields.files.ImageField', [], {'max_length': '100', 'null': 'True', 'blank': 'True'}), 36 | 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), 37 | 'name': ('django.db.models.fields.CharField', [], {'max_length': '150'}), 38 | 'properties': ('supertagging.fields.PickledObjectField', [], {'null': 'True', 'blank': 'True'}), 39 | 'related': ('django.db.models.fields.related.ManyToManyField', [], {'blank': 'True', 'related_name': "'related_rel_+'", 'null': 'True', 'to': "orm['supertagging.SuperTag']"}), 40 | 'slug': ('django.db.models.fields.SlugField', [], {'max_length': '150', 'db_index': 'True'}), 41 | 'stype': ('django.db.models.fields.CharField', [], {'max_length': '100'}), 42 | 'substitute': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'substitute_tagsubstitute'", 'null': 'True', 'to': "orm['supertagging.SuperTag']"}) 43 | }, 44 | 'supertagging.supertaggeditem': { 45 | 'Meta': {'object_name': 'SuperTaggedItem'}, 46 | 'content_type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['contenttypes.ContentType']"}), 47 | 'field': ('django.db.models.fields.CharField', [], {'max_length': '100'}), 48 | 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), 49 | 'ignore': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), 50 | 'instances': ('supertagging.fields.PickledObjectField', [], {'null': 'True', 'blank': 'True'}), 51 | 'item_date': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}), 52 | 'object_id': ('django.db.models.fields.PositiveIntegerField', [], {}), 53 | 'process_type': ('django.db.models.fields.CharField', [], {'max_length': '20', 'null': 'True', 'blank': 'True'}), 54 | 'relevance': ('django.db.models.fields.IntegerField', [], {'null': 'True', 'blank': 'True'}), 55 | 'tag': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['supertagging.SuperTag']"}) 56 | }, 57 | 'supertagging.supertaggedrelationitem': { 58 | 'Meta': {'ordering': "['-item_date']", 'object_name': 'SuperTaggedRelationItem'}, 59 | 'content_type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['contenttypes.ContentType']"}), 60 | 'field': ('django.db.models.fields.CharField', [], {'max_length': '100'}), 61 | 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), 62 | 'instances': ('supertagging.fields.PickledObjectField', [], {'null': 'True', 'blank': 'True'}), 63 | 'item_date': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}), 64 | 'object_id': ('django.db.models.fields.PositiveIntegerField', [], {}), 65 | 'process_type': ('django.db.models.fields.CharField', [], {'max_length': '20', 'null': 'True', 'blank': 'True'}), 66 | 'relation': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['supertagging.SuperTagRelation']"}) 67 | }, 68 | 'supertagging.supertagprocessqueue': { 69 | 'Meta': {'object_name': 'SuperTagProcessQueue'}, 70 | 'content_type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['contenttypes.ContentType']"}), 71 | 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), 72 | 'locked': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), 73 | 'object_id': ('django.db.models.fields.PositiveIntegerField', [], {}) 74 | }, 75 | 'supertagging.supertagrelation': { 76 | 'Meta': {'object_name': 'SuperTagRelation'}, 77 | 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), 78 | 'name': ('django.db.models.fields.CharField', [], {'max_length': '150'}), 79 | 'properties': ('supertagging.fields.PickledObjectField', [], {'null': 'True', 'blank': 'True'}), 80 | 'stype': ('django.db.models.fields.CharField', [], {'max_length': '100'}), 81 | 'tag': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['supertagging.SuperTag']"}) 82 | } 83 | } 84 | 85 | complete_apps = ['supertagging'] 86 | -------------------------------------------------------------------------------- /supertagging/migrations/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/callowayproject/django-supertagging/9b7d70343c2ff72e8f6dc971f6b873e1777ecc6c/supertagging/migrations/__init__.py -------------------------------------------------------------------------------- /supertagging/sql/add_display_fields.sql: -------------------------------------------------------------------------------- 1 | 2 | ALTER TABLE supertagging_supertag ADD COLUMN display_name character varying(150); 3 | ALTER TABLE supertagging_supertag ADD COLUMN description text; 4 | ALTER TABLE supertagging_supertag ADD COLUMN icon character varying(100); 5 | 6 | CREATE TABLE supertagging_supertag_related 7 | ( 8 | id serial NOT NULL, 9 | from_supertag_id integer NOT NULL, 10 | to_supertag_id integer NOT NULL, 11 | CONSTRAINT supertagging_supertag_related_pkey PRIMARY KEY (id), 12 | CONSTRAINT supertagging_supertag_related_from_supertag_id_fkey FOREIGN KEY (from_supertag_id) 13 | REFERENCES supertagging_supertag (id) MATCH SIMPLE 14 | ON UPDATE NO ACTION ON DELETE NO ACTION DEFERRABLE INITIALLY DEFERRED, 15 | CONSTRAINT supertagging_supertag_related_to_supertag_id_fkey FOREIGN KEY (to_supertag_id) 16 | REFERENCES supertagging_supertag (id) MATCH SIMPLE 17 | ON UPDATE NO ACTION ON DELETE NO ACTION DEFERRABLE INITIALLY DEFERRED, 18 | CONSTRAINT supertagging_supertag_related_from_supertag_id_key UNIQUE (from_supertag_id, to_supertag_id) 19 | ) 20 | WITH (OIDS=FALSE); -------------------------------------------------------------------------------- /supertagging/sql/supertaggeditem.sql: -------------------------------------------------------------------------------- 1 | CREATE INDEX st_sti_generic_relation_key 2 | ON supertagging_supertaggeditem (object_id, content_type_id); 3 | 4 | CREATE INDEX st_sti_tagid_objid_contentid_relevance_key 5 | ON supertagging_supertaggeditem (tag_id, object_id, content_type_id, relevance); -------------------------------------------------------------------------------- /supertagging/sql/supertaggedrelation_item_date.sql: -------------------------------------------------------------------------------- 1 | ALTER TABLE supertagging_supertaggedrelationitem ADD COLUMN item_date timestamp with time zone; -------------------------------------------------------------------------------- /supertagging/static/css/supertagloading.css: -------------------------------------------------------------------------------- 1 | .loading { 2 | background: #FFF; 3 | color: black; 4 | font-weight: bold; 5 | padding: 4px; 6 | border-radius: 5px; 7 | -o-border-radius: 5px; 8 | -moz-border-radius: 5px; 9 | -webkit-border-radius: 5px; 10 | -khtml-border-radius: 5px; 11 | border-bottom: 1px solid #999; 12 | border-right: 1px solid #999; 13 | border-left: 1px solid #999; 14 | } 15 | .loading.top { 16 | border-top-left-radius: 0px; 17 | border-top-right-radius: 0px; 18 | -moz-border-radius-topleft: 0px; 19 | -moz-border-radius-topright: 0px; 20 | -webkit-border-top-left-radius: 0px; 21 | -webkit-border-top-right-radius: 0px; 22 | } 23 | .loading-masked { overflow: hidden; } 24 | .loading-error { 25 | color: #FFF; 26 | background: red; 27 | } -------------------------------------------------------------------------------- /supertagging/static/js/jquery.loading.1.6.4.min.js: -------------------------------------------------------------------------------- 1 | ;(function($){var L=$.loading=function(show,opts){return $('body').loading(show,opts,true);};$.fn.loading=function(show,opts,page){opts=toOpts(show,opts);var base=page?$.extend(true,{},L,L.pageOptions):L;return this.each(function(){var $el=$(this),l=$.extend(true,{},base,$.metadata?$el.metadata():null,opts);if(typeof l.onAjax=="boolean"){L.setAjax.call($el,l);}else{L.toggle.call($el,l);}});};var fixed={position:$.browser.msie?'absolute':'fixed'};$.extend(L,{version:"1.6.4",align:'top-left',pulse:'working error',mask:false,img:null,element:null,text:'Loading...',onAjax:undefined,delay:0,max:0,classname:'loading',imgClass:'loading-img',elementClass:'loading-element',maskClass:'loading-mask',css:{position:'absolute',whiteSpace:'nowrap',zIndex:1001},maskCss:{position:'absolute',opacity:.15,background:'#333',zIndex:101,display:'block',cursor:'wait'},cloneEvents:true,pageOptions:{page:true,align:'top-center',css:fixed,maskCss:fixed},html:'
',maskHtml:'
',maskedClass:'loading-masked',maskEvents:'mousedown mouseup keydown keypress',resizeEvents:'resize',working:{time:10000,text:'Still working...',run:function(l){var w=l.working,self=this;w.timeout=setTimeout(function(){self.height('auto').width('auto').text(l.text=w.text);l.place.call(self,l);},w.time);}},error:{time:100000,text:'Task may have failed...',classname:'loading-error',run:function(l){var e=l.error,self=this;e.timeout=setTimeout(function(){self.height('auto').width('auto').text(l.text=e.text).addClass(e.classname);l.place.call(self,l);},e.time);}},fade:{time:800,speed:'slow',run:function(l){var f=l.fade,s=f.speed,self=this;f.interval=setInterval(function(){self.fadeOut(s).fadeIn(s);},f.time);}},ellipsis:{time:300,run:function(l){var e=l.ellipsis,self=this;e.interval=setInterval(function(){var et=self.text(),t=l.text,i=dotIndex(t);self.text((et.length-i)<3?et+'.':t.substring(0,i));},e.time);function dotIndex(t){var x=t.indexOf('.');return x<0?t.length:x;}}},type:{time:100,run:function(l){var t=l.type,self=this;t.interval=setInterval(function(){var e=self.text(),el=e.length,txt=l.text;self.text(el==txt.length?txt.charAt(0):txt.substring(0,el+1));},t.time);}},toggle:function(l){var old=this.data('loading');if(old){if(l.show!==true)old.off.call(this,old,l);}else{if(l.show!==false)l.on.call(this,l);}},setAjax:function(l){if(l.onAjax){var self=this,count=0,A=l.ajax={start:function(){if(!count++)l.on.call(self,l);},stop:function(){if(!--count)l.off.call(self,l,l);}};this.bind('ajaxStart.loading',A.start).bind('ajaxStop.loading',A.stop);}else{this.unbind('ajaxStart.loading ajaxStop.loading');}},on:function(l,force){var p=l.parent=this.data('loading',l);if(l.max)l.maxout=setTimeout(function(){l.off.call(p,l,l);},l.max);if(l.delay&&!force){return l.timeout=setTimeout(function(){delete l.timeout;l.on.call(p,l,true);},l.delay);} 2 | if(l.mask)l.mask=l.createMask.call(p,l);l.display=l.create.call(p,l);if(l.img){l.initImg.call(p,l);}else if(l.element){l.initElement.call(p,l);}else{l.init.call(p,l);} 3 | p.trigger('loadingStart',[l]);},initImg:function(l){var self=this;l.imgElement=$('').bind('load',function(){l.init.call(self,l);});l.display.addClass(l.imgClass).append(l.imgElement);},initElement:function(l){l.element=$(l.element).clone(l.cloneEvents).show();l.display.addClass(l.elementClass).append(l.element);l.init.call(this,l);},init:function(l){l.place.call(l.display,l);if(l.pulse)l.initPulse.call(this,l);},initPulse:function(l){$.each(l.pulse.split(' '),function(){l[this].run.call(l.display,l);});},create:function(l){var el=$(l.html).addClass(l.classname).css(l.css).appendTo(this);if(l.text&&!l.img&&!l.element)el.text(l.originalText=l.text);$(window).bind(l.resizeEvents,l.resizer=function(){l.resize(l);});return el;},resize:function(l){l.parent.box=null;if(l.mask)l.mask.hide();l.place.call(l.display.hide(),l);if(l.mask)l.mask.show().css(l.parent.box);},createMask:function(l){var box=l.measure.call(this.addClass(l.maskedClass),l);l.handler=function(e){return l.maskHandler(e,l);};$(document).bind(l.maskEvents,l.handler);return $(l.maskHtml).addClass(l.maskClass).css(box).css(l.maskCss).appendTo(this);},maskHandler:function(e,l){var $els=$(e.target).parents().andSelf();if($els.filter('.'+l.classname).length!=0)return true;return!l.page&&$els.filter('.'+l.maskedClass).length==0;},place:function(l){var box=l.align,v='top',h='left';if(typeof box=="object"){box=$.extend(l.calc.call(this,v,h,l),box);}else{if(box!='top-left'){var s=box.split('-');if(s.length==1){v=h=s[0];}else{v=s[0];h=s[1];}} 4 | if(!this.hasClass(v))this.addClass(v);if(!this.hasClass(h))this.addClass(h);box=l.calc.call(this,v,h,l);} 5 | this.show().css(l.box=box);},calc:function(v,h,l){var box=$.extend({},l.measure.call(l.parent,l)),H=$.boxModel?this.height():this.innerHeight(),W=$.boxModel?this.width():this.innerWidth();if(v!='top'){var d=box.height-H;if(v=='center'){d/=2;}else if(v!='bottom'){d=0;}else if($.boxModel){d-=css(this,'paddingTop')+css(this,'paddingBottom');} 6 | box.top+=d;} 7 | if(h!='left'){var d=box.width-W;if(h=='center'){d/=2;}else if(h!='right'){d=0;}else if($.boxModel){d-=css(this,'paddingLeft')+css(this,'paddingRight');} 8 | box.left+=d;} 9 | box.height=H;box.width=W;return box;},measure:function(l){return this.box||(this.box=l.page?l.pageBox(l):l.elementBox(this,l));},elementBox:function(e,l){if(e.css('position')=='absolute'){var box={top:0,left:0};}else{var box=e.position();box.top+=css(e,'marginTop');box.left+=css(e,'marginLeft');} 10 | box.height=e.outerHeight();box.width=e.outerWidth();return box;},pageBox:function(l){var full=$.boxModel&&l.css.position!='fixed';return{top:0,left:0,height:get(full,'Height'),width:get(full,'Width')};function get(full,side){var doc=document;if(full){var s=side.toLowerCase(),d=$(doc)[s](),w=$(window)[s]();return d-css($(doc.body),'marginTop')>w?d:w;} 11 | var c='client'+side;return Math.max(doc.documentElement[c],doc.body[c]);}},off:function(old,l){this.data('loading',null);if(old.maxout)clearTimeout(old.maxout);if(old.timeout)return clearTimeout(old.timeout);if(old.pulse)old.stopPulse.call(this,old,l);if(old.originalText)old.text=old.originalText;if(old.mask)old.stopMask.call(this,old,l);$(window).unbind(old.resizeEvents,old.resizer);if(old.display)old.display.remove();if(old.parent)old.parent.trigger('loadingEnd',[old]);},stopPulse:function(old,l){$.each(old.pulse.split(' '),function(){var p=old[this];if(p.end)p.end.call(l.display,old,l);if(p.interval)clearInterval(p.interval);if(p.timeout)clearTimeout(p.timeout);});},stopMask:function(old,l){this.removeClass(l.maskedClass);$(document).unbind(old.maskEvents,old.handler);old.mask.remove();}});function toOpts(s,l){if(l===undefined){l=(typeof s=="boolean")?{show:s}:s;}else{l.show=s;} 12 | if(l&&(l.img||l.element)&&!l.pulse)l.pulse=false;if(l&&l.onAjax!==undefined&&l.show===undefined)l.show=false;return l;} 13 | function css(el,prop){var val=el.css(prop);return val=='auto'?0:parseFloat(val,10);}})(jQuery); -------------------------------------------------------------------------------- /supertagging/templates/admin/supertagging/relevancebar.css: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /supertagging/templates/admin/supertagging/relevancebar.html: -------------------------------------------------------------------------------- 1 | {% spaceless %} 2 |
3 |
4 |
5 | {{ relevance }} 6 |
7 |
8 |
9 | {% endspaceless %} -------------------------------------------------------------------------------- /supertagging/templates/admin/supertagging/supertaggeditem/change_list.html: -------------------------------------------------------------------------------- 1 | {% extends "admin/base_site.html" %} 2 | {% load adminmedia admin_list i18n %} 3 | 4 | {% block extrastyle %} 5 | {{ block.super }} 6 | 7 | {% if cl.formset %} 8 | 9 | {% endif %} 10 | {% if cl.formset or action_form %} 11 | {% url admin:jsi18n as jsi18nurl %} 12 | 13 | {% endif %} 14 | {{ media.css }} 15 | {% if not actions_on_top and not actions_on_bottom %} 16 | 19 | {% endif %} 20 | {% endblock %} 21 | 22 | {% block extrahead %} 23 | {{ block.super }} 24 | 25 | {{ media.js }} 26 | {% include "admin/supertagging/relevancebar.css" %} 27 | {% if action_form %}{% if actions_on_top or actions_on_bottom %} 28 | 35 | {% endif %}{% endif %} 36 | {% endblock %} 37 | 38 | {% block bodyclass %}change-list{% endblock %} 39 | 40 | {% if not is_popup %} 41 | {% block breadcrumbs %} 42 | 53 | {% endblock %} 54 | {% endif %} 55 | 56 | {% block coltype %}flex{% endblock %} 57 | {# {% block content_title %}

Supertags for {{ cl.result_list.0.content_object }}

{% endblock %} #} 58 | {% block content %} 59 |
60 | {% block object-tools %}{% block object-tools-items %}{% endblock %}{% endblock %} 61 | {% if cl.formset.errors %} 62 |

63 | {% blocktrans count cl.formset.errors|length as counter %}Please correct the error below.{% plural %}Please correct the errors below.{% endblocktrans %} 64 |

65 | {{ cl.formset.non_form_errors }} 66 | {% endif %} 67 |
68 | {% block search %}{% search_form cl %}{% endblock %} 69 | {% block date_hierarchy %}{% date_hierarchy cl %}{% endblock %} 70 | 71 | {% block filters %} 72 | {% if cl.has_filters %} 73 |
74 |

{% trans 'Filter' %}

75 | {% for spec in cl.filter_specs %}{% admin_list_filter cl spec %}{% endfor %} 76 |
77 | {% endif %} 78 | {% endblock %} 79 | 80 |
{% csrf_token %} 81 | {% if cl.formset %} 82 |
{{ cl.formset.management_form }}
83 | {% endif %} 84 | 85 | {% block result_list %} 86 | {% if action_form and actions_on_top and cl.full_result_count %}{% admin_actions %}{% endif %} 87 | {% load supertagging_tags %}{% supertaggeditem_result_list cl %} 88 | {% if action_form and actions_on_bottom and cl.full_result_count %}{% admin_actions %}{% endif %} 89 | {% endblock %} 90 | {% block pagination %}{% supertaggeditem_pagination cl %}{% endblock %} 91 |
92 |
93 |
94 | {% endblock %} 95 | -------------------------------------------------------------------------------- /supertagging/templates/admin/supertagging/supertaggeditem/change_list_results.html: -------------------------------------------------------------------------------- 1 | {% if result_hidden_fields %} 2 |
{# DIV for HTML validation #} 3 | {% for item in result_hidden_fields %}{{ item }}{% endfor %} 4 |
5 | {% endif %} 6 | {% if results %} 7 |
8 | 9 | 10 | 11 | {% for header in result_headers %}{% endfor %} 15 | 16 | 17 | 18 | {% for result in results %} 19 | {% if result.form.non_field_errors %} 20 | 21 | {% endif %} 22 | {% for item in result %}{{ item }}{% endfor %} 23 | {% endfor %} 24 | 25 |
12 | {% if header.sortable %}{% endif %} 13 | {{ header.text|capfirst }} 14 | {% if header.sortable %}{% endif %}
{{ result.form.non_field_errors }}
26 |
27 | {% endif %} 28 | -------------------------------------------------------------------------------- /supertagging/templates/admin/supertagging/supertaggeditem/pagination.html: -------------------------------------------------------------------------------- 1 | {% load admin_list %} 2 | {% load i18n %} 3 |

4 | {% if pagination_required %} 5 | {% for i in page_range %} 6 | {% paginator_number cl i %} 7 | {% endfor %} 8 | {% endif %} 9 | {{ cl.result_count }} {% ifequal cl.result_count 1 %}{{ cl.opts.verbose_name }}{% else %}{{ cl.opts.verbose_name_plural }}{% endifequal %} 10 | {% if show_all_url %}  {% trans 'Show all' %}{% endif %} 11 | {% if cl.formset and cl.result_count %}  {% endif %} 12 | {% if cl.formset %} 13 | 14 |   {% endif %} 15 |

16 | -------------------------------------------------------------------------------- /supertagging/templates/supertagging/markup.html: -------------------------------------------------------------------------------- 1 | {{ actual_value }} -------------------------------------------------------------------------------- /supertagging/templates/supertagging/render/relations/default.html: -------------------------------------------------------------------------------- 1 | RELATION DEFAULT: {{ obj }} -------------------------------------------------------------------------------- /supertagging/templates/supertagging/render/tagged_items/default.html: -------------------------------------------------------------------------------- 1 | TAGGED ITEM DEFAULT: {{ obj }} -------------------------------------------------------------------------------- /supertagging/templates/supertagging/render/tagged_relations/default.html: -------------------------------------------------------------------------------- 1 | TAGGED RELATION ITEM DEFAULT: {{ obj }} -------------------------------------------------------------------------------- /supertagging/templates/supertagging/render/tags/default.html: -------------------------------------------------------------------------------- 1 | TAG DEFAULT {{ obj }} -------------------------------------------------------------------------------- /supertagging/templatetags/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/callowayproject/django-supertagging/9b7d70343c2ff72e8f6dc971f6b873e1777ecc6c/supertagging/templatetags/__init__.py -------------------------------------------------------------------------------- /supertagging/tests.py: -------------------------------------------------------------------------------- 1 | """Django snippet - http://www.djangosnippets.org/snippets/513/""" 2 | """Unit testing for this module.""" 3 | 4 | from django.test import TestCase 5 | from django.db import models 6 | from supertagging.fields import PickledObjectField 7 | 8 | class TestingModel(models.Model): 9 | pickle_field = PickledObjectField() 10 | 11 | class TestCustomDataType(str): 12 | pass 13 | 14 | class PickledObjectFieldTests(TestCase): 15 | def setUp(self): 16 | self.testing_data = ( 17 | {1:1, 2:4, 3:6, 4:8, 5:10}, 18 | 'Hello World', 19 | (1, 2, 3, 4, 5), 20 | [1, 2, 3, 4, 5], 21 | TestCustomDataType('Hello World'), 22 | ) 23 | return super(PickledObjectFieldTests, self).setUp() 24 | 25 | def testDataIntegriry(self): 26 | """Tests that data remains the same when saved to and fetched from the database.""" 27 | for value in self.testing_data: 28 | model_test = TestingModel(pickle_field=value) 29 | model_test.save() 30 | model_test = TestingModel.objects.get(id__exact=model_test.id) 31 | self.assertEquals(value, model_test.pickle_field) 32 | model_test.delete() 33 | 34 | def testLookups(self): 35 | """Tests that lookups can be performed on data once stored in the database.""" 36 | for value in self.testing_data: 37 | model_test = TestingModel(pickle_field=value) 38 | model_test.save() 39 | self.assertEquals(value, TestingModel.objects.get(pickle_field__exact=value).pickle_field) 40 | model_test.delete() 41 | --------------------------------------------------------------------------------