Skip to content

Nh3charfield and nh3textfield #52

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 7 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ classifiers = [
dependencies = [
"django>=3.2",
"nh3",
"typing-extensions",
]

urls.Changelog = "https://github.com/marksweb/django-nh3/blob/main/CHANGELOG.rst"
Expand Down
43 changes: 34 additions & 9 deletions src/django_nh3/models.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
from __future__ import annotations

import warnings
from collections.abc import Callable
from typing import Any

Expand All @@ -9,11 +8,12 @@
from django.db.models import Expression, Model
from django.forms import Field as FormField
from django.utils.safestring import mark_safe
from typing_extensions import deprecated

from . import forms


class Nh3Field(models.TextField):
class Nh3FieldMixin:
def __init__(
self,
attributes: dict[str, set[str]] = {},
Expand Down Expand Up @@ -42,28 +42,28 @@ def formfield(
"""Makes the field for a ModelForm"""

# If field doesn't have any choices add kwargs expected by Nh3Field.
if not self.choices:
if not self.choices: # type: ignore[attr-defined]
kwargs.update(
{
"max_length": self.max_length,
"max_length": self.max_length, # type: ignore[attr-defined]
"attributes": self.nh3_options.get("attributes"),
"attribute_filter": self.nh3_options.get("attribute_filter"),
"clean_content_tags": self.nh3_options.get("clean_content_tags"),
"link_rel": self.nh3_options.get("link_rel"),
"strip_comments": self.nh3_options.get("strip_comments"),
"tags": self.nh3_options.get("tags"),
"required": not self.blank,
"required": not self.blank, # type: ignore[attr-defined]
}
)

return super().formfield(form_class=form_class, **kwargs)
return super().formfield(form_class=form_class, **kwargs) # type: ignore[misc]

def pre_save(self, model_instance: Model, add: bool) -> Any:
data = getattr(model_instance, self.attname)
data = getattr(model_instance, self.attname) # type: ignore[attr-defined]
if data is None:
return data
clean_value = nh3.clean(data, **self.nh3_options) if data else ""
setattr(model_instance, self.attname, mark_safe(clean_value))
setattr(model_instance, self.attname, mark_safe(clean_value)) # type: ignore[attr-defined]
return clean_value

def from_db_value(
Expand All @@ -77,3 +77,28 @@ def from_db_value(
# Values are sanitised before saving, so any value returned from the DB
# is safe to render unescaped.
return mark_safe(value)


class Nh3TextField(Nh3FieldMixin, models.TextField):
pass


class Nh3CharField(Nh3FieldMixin, models.CharField):
pass


@deprecated("Use Nh3TextField instead")
class Nh3Field(Nh3FieldMixin, models.TextField):
"""
.. deprecated:: 0.2.0
Use :class:`Nh3TextField` instead.
"""

def __init__(self, *args, **kwargs) -> None: # type: ignore[no-untyped-def]
warnings.warn(
"Nh3Field is deprecated and will be removed in a future version. "
"Use Nh3TextField instead.",
DeprecationWarning,
stacklevel=2,
)
super().__init__(*args, **kwargs)
40 changes: 40 additions & 0 deletions tests/forms.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
from django.forms import ModelForm

from .models import (
Nh3CharFieldContent,
Nh3CharFieldNullableContent,
Nh3TextFieldContent,
Nh3TextFieldNullableContent,
)


class Nh3CharFieldContentModelForm(ModelForm):
"""NH3 test model form"""

class Meta:
model = Nh3CharFieldContent
fields = ["content"]


class Nh3CharFieldNullableContentModelForm(ModelForm):
"""NH3 test model form"""

class Meta:
model = Nh3CharFieldNullableContent
fields = ["choice"]


class Nh3TextFieldContentModelForm(ModelForm):
"""NH3 test model form"""

class Meta:
model = Nh3TextFieldContent
fields = ["content"]


class Nh3TextFieldNullableContentModelForm(ModelForm):
"""NH3 test model form"""

class Meta:
model = Nh3TextFieldNullableContent
fields = ["choice"]
81 changes: 73 additions & 8 deletions tests/migrations/0001_initial.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ class Migration(migrations.Migration):

operations = [
migrations.CreateModel(
name="Nh3Content",
name="Nh3CharFieldContent",
fields=[
(
"id",
Expand All @@ -22,16 +22,46 @@ class Migration(migrations.Migration):
verbose_name="ID",
),
),
("content", django_nh3.models.Nh3Field()),
("blank_field", django_nh3.models.Nh3Field(blank=True)),
("content", django_nh3.models.Nh3CharField(max_length=1000)),
(
"blank_field",
django_nh3.models.Nh3CharField(blank=True, max_length=1000),
),
(
"null_field",
django_nh3.models.Nh3Field(blank=True, null=True),
django_nh3.models.Nh3CharField(
blank=True, null=True, max_length=1000
),
),
],
),
migrations.CreateModel(
name="Nh3NullableContent",
name="Nh3TextFieldContent",
fields=[
(
"id",
models.BigAutoField(
auto_created=True,
primary_key=True,
serialize=False,
verbose_name="ID",
),
),
("content", django_nh3.models.Nh3TextField(max_length=1000)),
(
"blank_field",
django_nh3.models.Nh3TextField(blank=True, max_length=1000),
),
(
"null_field",
django_nh3.models.Nh3TextField(
blank=True, null=True, max_length=1000
),
),
],
),
migrations.CreateModel(
name="Nh3CharFieldNullableContent",
fields=[
(
"id",
Expand All @@ -44,11 +74,46 @@ class Migration(migrations.Migration):
),
(
"choice",
django_nh3.models.Nh3Field(
choices=[("f", "first choice"), ("s", "second choice")]
django_nh3.models.Nh3CharField(
blank=True,
choices=[("f", "first choice"), ("s", "second choice")],
max_length=1000,
),
),
(
"content",
django_nh3.models.Nh3CharField(
blank=True, null=True, max_length=1000
),
),
],
),
migrations.CreateModel(
name="Nh3TextFieldNullableContent",
fields=[
(
"id",
models.BigAutoField(
auto_created=True,
primary_key=True,
serialize=False,
verbose_name="ID",
),
),
(
"choice",
django_nh3.models.Nh3TextField(
blank=True,
choices=[("f", "first choice"), ("s", "second choice")],
max_length=1000,
),
),
(
"content",
django_nh3.models.Nh3TextField(
blank=True, null=True, max_length=1000
),
),
("content", django_nh3.models.Nh3Field(blank=True, null=True)),
],
),
]
41 changes: 41 additions & 0 deletions tests/models.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
from django.db import models

from django_nh3.models import Nh3CharField, Nh3TextField


class Nh3CharFieldContent(models.Model):
"""NH3 test model"""

content = Nh3CharField(
strip_comments=True,
max_length=1000,
)
blank_field = Nh3CharField(blank=True, max_length=1000)
null_field = Nh3CharField(blank=True, null=True, max_length=1000)


class Nh3CharFieldNullableContent(models.Model):
"""NH3 test model"""

CHOICES = (("f", "first choice"), ("s", "second choice"))
choice = Nh3CharField(choices=CHOICES, blank=True, max_length=1000)
content = Nh3CharField(blank=True, null=True, max_length=1000)


class Nh3TextFieldContent(models.Model):
"""NH3 test model"""

content = Nh3TextField(
strip_comments=True,
max_length=1000,
)
blank_field = Nh3TextField(blank=True, max_length=1000)
null_field = Nh3TextField(blank=True, null=True, max_length=1000)


class Nh3TextFieldNullableContent(models.Model):
"""NH3 test model"""

CHOICES = (("f", "first choice"), ("s", "second choice"))
choice = Nh3TextField(choices=CHOICES, blank=True, max_length=1000)
content = Nh3TextField(blank=True, null=True, max_length=1000)
Loading