Quick reminder what is frisor

Frisor is a web application in Python/Django which is just a box for interesting urls. When using untrusted network I don’t want to login anywhere to save interesting content I found. More about this is here: Introduction to frisor.

This week I introduced tags for my urls. As I didn’t want to reinvent a wheel again, I decided to use some Django library for tagging. More about my experiences in next part of this post.

Frisor on github: firsor repo.

Currently autocompletion of adding tag in my application looks like this: screenshot

Libraries for tagging in Django

What do I want from tagging library:

  • easy autocomplete
  • select2 widget as input for tags
  • not too complicated schema in database
  • maintained code repository

There are a few libraries for tagging in Django:

  • django-tagging
  • django-taggit
  • django-tagulous

All of them just suck, maybe the last one not so much as the rest of them.

Why django-tagging sucks?

It has a bit complicated database schema - for me it was too generic. They say that’s enough to add tagging.registry.register function in model.py to register a model for tagging:

    # models.py
    from django.db import models

    from tagging.registry import register

    class Url(models.Model):
        url = models.URLField()
        publish_date = models.DateTimeField(auto_now=True)
        title = models.CharField(max_length=200)
        nick = models.CharField(max_length=200)

    register(Url)  # register an Url model for tagging

After creating and running migrations (because it’s a change in model it’s quite obvious we have to do that) it created many tables in database: tagging_taggeditem and tagging_tag. The first table is quite generic and consist four rows, the second one has only tags:

    sqlite> select * from tagging_taggeditem;
    id          object_id   content_type_id  tag_id
    ----------  ----------  ---------------  ----------
    1           3           1                1
    2           3           1                2
    3           5           1                3
    4           5           1                4
    5           6           1                5
    6           6           1                6
    sqlite> select * from tagging_tag;
    id          name
    ----------  ----------
    1           house
    2           thing
    3           like
    4           tags
    5           github
    6           python

The design here looks like this: we have one table - tagging_taggeditem for all tagged objects - there are three foreign keys: object_id (for an actual id of item we want to tag), content_type_id (to check from which table we should get this item) and tag_id (id of tag in corresponding tag table).

Quite complicated, isn’t it? I definitely don’t need that, especially without builtin autocomplete.

I tried to add autocompletion with another library, but I found out that django-taggit is more recommended for this feature.

The other thing is that the last commit in the repository of django-tagging was about 6 months ago. I’m using the newest version of Django, so for me it’s important to use maintained libraries - that was the last reason to decide against it.

Why django-taggit sucks?

Setting django-taggit up was quite easy - registering mechanism in models is a bit different, but overall installation process was the same (add to apps, register tags in model, add field to form). It doesn’t have builtin autocomplete, so I decided to try django-taggit-autocomplete, but it didn’t go well with Django 1.10. So it was time to find another autocomplete library - the most promising was django-autocomplete-light.

Don’t use django-autocomplete-light, just don’t

It has an outdated documentation, the nightmare starts from imports to not existing components, for example I wanted to use some nice looking widget for tags in my forms, but it happens that they’ve removed it! Examples in documentation doesn’t work with current version of their library. But the thing which was the worst - they’ve clearly written:

Python 2.7, 3.4, Django 1.8+ support

No, as expected - they don’t support Django 1.10: the urls.py file they provide is not valid for this version. So, no. No django-autocomplete-light for me.

Last try - django-tagulous

I was quite desperate, I’ve almost decided to write my own tagging. Actually, the design is quite simple - create a many-to-many relation in database, provide select2 widget to form, do autocompletion (so create an endpoint which searches for tags in database and returns a list for current autocomplete query), but implementation is time consuming.

I decided to try with the last library - django-tagulous, at documentation page it’s written that it’s much simpler than other libraries for tagging and it has autocompletion. Actually it all happen to be true and after setting it up, it works like a charm. But setting it up wasn’t so easy - I’m not sure about a reason, but in documentation there is no word about how to provide javascript’s and styles in templates for tagging. I had to do this by hand by just putting necessary scripts in head of my html and use $ python manage.py collectstatic mechanism. In documentation and example application they mention special template tag for this, but it didn’t work for me.

Some thoughts

I think I could use all that time I spent for looking and trying tagging libraries, for implementation of my own tagging. Probably it would be more educative and interesting. Of course I would reinvent a wheel again, but maybe in this case it would be less costly. Usually I’m against approach for writing own versions of something which exists, but maybe that should depend on a case. So, today I’ve learned that sometimes it’s just faster to do something from the beginning than rely on others work.

What are your thoughts? Let me know in comments!

Leave a Comment