Skip to main content

HTML, choices and tags

HTMLField​

A text field for HTML content. Content is sanitized on save, so every value stored through the field is clean — no matter how the instance gets saved.

from blueprint.fields import HTMLField


class Article(models.Model):
body = HTMLField()


article = Article(body="<p>Hi</p><script>alert(1)</script>")
article.save()
article.body # "<p>Hi</p>"

The default sanitizer​

The built-in sanitizer (blueprint.sanitizers.sanitize_html, powered by nh3) keeps a CMS-friendly allowlist of tags (headings, text, lists, links, images, tables, audio/video) and safe attributes (class, href, src, alt, title, sizes, and a few more), allows only the http, https, mailto and tel URL schemes, adds rel="noopener noreferrer" to links, and strips comments and everything else — including the content of script and style tags.

Customizing the sanitizer​

Two levels of customization, both resolved lazily:

Project-wide — set BLUEPRINT["HTML_SANITIZER"] in your Django settings to a callable or a dotted import path:

# settings.py
BLUEPRINT = {
"HTML_SANITIZER": "myapp.text.sanitize",
}

Per field — pass sanitizer to an individual field; it wins over the project-wide setting. Use a module-level function (not a lambda), because the sanitizer is serialized into your migrations:

from blueprint.fields import HTMLField


class Article(models.Model):
# myapp.text.sanitize_upper is a module-level function
body = HTMLField(sanitizer="myapp.text.sanitize_upper")

To opt out of sanitizing entirely — for example when you sanitize on input through your editor — point the sanitizer at a passthrough function:

def passthrough(value):
return value


BLUEPRINT = {"HTML_SANITIZER": passthrough}

MultipleChoiceField​

A JSON array field with a fixed set of allowed values. Options can be passed as a mapping or an iterable of pairs; values outside the options are rejected by the field's validator.

from blueprint.fields import MultipleChoiceField


class Page(models.Model):
sections = MultipleChoiceField(
options={"hero": "Hero", "grid": "Grid", "cta": "Call to action"}
)


page = Page(sections=["hero", "grid"]) # valid
page = Page(sections=["hero", "oops"]) # ValidationError

Defaults to an empty list and blank=True. The options are part of the field's serialized form, so changing them produces a migration.

TagField​

A JSON array field for tags. Any string is a valid tag — the field has no opinion on their shape. On save it trims surrounding whitespace and drops duplicates and tags that end up empty.

from blueprint.fields import TagField


class Article(models.Model):
tags = TagField()


article = Article(tags=["Django", " web dev ", "Django", " "])
article.save()
article.tags # ["Django", "web dev"]

Defaults to an empty list and blank=True.

HashTagField​

A JSON array field for hashtags, built on TagField. Values are normalized to hashtag form on save: lowercased, all whitespace and # signs removed, duplicates dropped and empty results discarded.

from blueprint.fields import HashTagField


class Article(models.Model):
hashtags = HashTagField()


article = Article(hashtags=["#DjangoCon", " New York ", "djangocon"])
article.save()
article.hashtags # ["djangocon", "newyork"]

Defaults to an empty list and blank=True.