Skip to content

Commit

Permalink
edits
Browse files Browse the repository at this point in the history
  • Loading branch information
timgraham committed Jan 5, 2025
1 parent 14af7cb commit 879330b
Show file tree
Hide file tree
Showing 7 changed files with 92 additions and 62 deletions.
2 changes: 1 addition & 1 deletion .pre-commit-config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ repos:
hooks:
- id: rstcheck
additional_dependencies: [sphinx]
args: ["--ignore-directives=fieldlookup", "--ignore-roles=lookup"]
args: ["--ignore-directives=fieldlookup,setting", "--ignore-roles=lookup,setting"]

# We use the Python version instead of the original version which seems to require Docker
# https://github.com/koalaman/shellcheck-precommit
Expand Down
6 changes: 2 additions & 4 deletions django_mongodb/forms/array.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,11 @@
from itertools import chain

from django import forms
from django.contrib.postgres.validators import (
ArrayMaxLengthValidator,
ArrayMinLengthValidator,
)
from django.core.exceptions import ValidationError
from django.utils.translation import gettext_lazy as _

from django_mongodb.validators import ArrayMaxLengthValidator, ArrayMinLengthValidator

from ..utils import prefix_validation_error


Expand Down
6 changes: 3 additions & 3 deletions django_mongodb/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -68,9 +68,9 @@ def prefix_validation_error(error, prefix, code, params):
if error.error_list == [error]:
error_params = error.params or {}
return ValidationError(
# We can't simply concatenate messages since they might require
# their associated parameters to be expressed correctly which
# is not something `format_lazy` does. For example, proxied
# Messages can't simply be concatenated since they might require
# their associated parameters to be expressed correctly which is
# not something format_lazy() does. For example, proxied
# ngettext calls require a count parameter and are converted
# to an empty string if they are missing it.
message=format_lazy(
Expand Down
18 changes: 18 additions & 0 deletions django_mongodb/validators.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
from django.core.validators import MaxLengthValidator, MinLengthValidator
from django.utils.translation import ngettext_lazy


class ArrayMaxLengthValidator(MaxLengthValidator):
message = ngettext_lazy(
"List contains %(show_value)d item, it should contain no more than %(limit_value)d.",
"List contains %(show_value)d items, it should contain no more than %(limit_value)d.",
"show_value",
)


class ArrayMinLengthValidator(MinLengthValidator):
message = ngettext_lazy(
"List contains %(show_value)d item, it should contain no fewer than %(limit_value)d.",
"List contains %(show_value)d items, it should contain no fewer than %(limit_value)d.",
"show_value",
)
5 changes: 5 additions & 0 deletions docs/source/_ext/djangodocs.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,3 +4,8 @@ def setup(app):
rolename="lookup",
indextemplate="pair: %s; field lookup type",
)
app.add_crossref_type(
directivename="setting",
rolename="setting",
indextemplate="pair: %s; setting",
)
7 changes: 7 additions & 0 deletions docs/source/forms.rst
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,13 @@ Stores an :class:`~bson.objectid.ObjectId`.
This field handles arrays by reproducing the underlying field a fixed
number of times.

The template for this widget is located in
``django_mongodb/templates/mongodb/widgets``. Don't forget to configure
template loading appropriately, for example, by using a
:class:`~django.template.backends.django.DjangoTemplates` engine with
:setting:`APP_DIRS=True <TEMPLATES-APP_DIRS>` and ``"django_mongodb"`` in
:setting:`INSTALLED_APPS`.

.. attribute:: base_field

This is a required argument. It specifies the form field to be
Expand Down
110 changes: 56 additions & 54 deletions tests/model_fields_/test_arrayfield.py
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,34 @@ class MyModel(models.Model):
instance = MyModel(field=value)
self.assertEqual(instance.get_field_display(), display)

def test_deconstruct(self):
field = ArrayField(models.IntegerField())
name, path, args, kwargs = field.deconstruct()
new = ArrayField(*args, **kwargs)
self.assertEqual(type(new.base_field), type(field.base_field))
self.assertIsNot(new.base_field, field.base_field)

def test_deconstruct_with_size(self):
field = ArrayField(models.IntegerField(), size=3)
name, path, args, kwargs = field.deconstruct()
new = ArrayField(*args, **kwargs)
self.assertEqual(new.size, field.size)

def test_deconstruct_args(self):
field = ArrayField(models.CharField(max_length=20))
name, path, args, kwargs = field.deconstruct()
new = ArrayField(*args, **kwargs)
self.assertEqual(new.base_field.max_length, field.base_field.max_length)

def test_subclass_deconstruct(self):
field = ArrayField(models.IntegerField())
name, path, args, kwargs = field.deconstruct()
self.assertEqual(path, "django_mongodb.fields.ArrayField")

field = ArrayFieldSubclass()
name, path, args, kwargs = field.deconstruct()
self.assertEqual(path, "model_fields_.models.ArrayFieldSubclass")


class SaveLoadTests(TestCase):
def test_integer(self):
Expand Down Expand Up @@ -613,53 +641,41 @@ class MyModel(models.Model):
self.assertEqual(MyModel._meta.get_field("field").check(), [])


@isolate_apps("model_fields_")
class MigrationsTests(TransactionTestCase):
available_apps = ["model_fields_"]

def test_deconstruct(self):
field = ArrayField(models.IntegerField())
name, path, args, kwargs = field.deconstruct()
new = ArrayField(*args, **kwargs)
self.assertEqual(type(new.base_field), type(field.base_field))
self.assertIsNot(new.base_field, field.base_field)

def test_deconstruct_with_size(self):
field = ArrayField(models.IntegerField(), size=3)
name, path, args, kwargs = field.deconstruct()
new = ArrayField(*args, **kwargs)
self.assertEqual(new.size, field.size)

def test_deconstruct_args(self):
field = ArrayField(models.CharField(max_length=20))
name, path, args, kwargs = field.deconstruct()
new = ArrayField(*args, **kwargs)
self.assertEqual(new.base_field.max_length, field.base_field.max_length)

def test_subclass_deconstruct(self):
field = ArrayField(models.IntegerField())
name, path, args, kwargs = field.deconstruct()
self.assertEqual(path, "django_mongodb.fields.ArrayField")

field = ArrayFieldSubclass()
name, path, args, kwargs = field.deconstruct()
self.assertEqual(path, "model_fields_.models.ArrayFieldSubclass")

@override_settings(
MIGRATION_MODULES={
"model_fields_": "model_fields_.array_default_migrations",
}
)
def test_adding_field_with_default(self):
# See #22962
class IntegerArrayDefaultModel(models.Model):
field = ArrayField(models.IntegerField(), size=None)

table_name = "model_fields__integerarraydefaultmodel"
with connection.cursor() as cursor:
self.assertNotIn(table_name, connection.introspection.table_names(cursor))
call_command("migrate", "model_fields_", verbosity=0)
with connection.cursor() as cursor:
self.assertIn(table_name, connection.introspection.table_names(cursor))
self.assertNotIn(table_name, connection.introspection.table_names(None))
# Create collection
call_command("migrate", "model_fields_", "0001", verbosity=0)
self.assertIn(table_name, connection.introspection.table_names(None))
obj = IntegerArrayDefaultModel.objects.create(field=[1, 2, 3])
# Add `field2 to IntegerArrayDefaultModel.
call_command("migrate", "model_fields_", "0002", verbosity=0)

class UpdatedIntegerArrayDefaultModel(models.Model):
field = ArrayField(models.IntegerField(), size=None)
field_2 = ArrayField(models.IntegerField(), default=[], size=None)

class Meta:
db_table = "model_fields__integerarraydefaultmodel"

obj = UpdatedIntegerArrayDefaultModel.objects.get()
# The default is populated on existing documents.
self.assertEqual(obj.field_2, [])
# Cleanup.
call_command("migrate", "model_fields_", "zero", verbosity=0)
with connection.cursor() as cursor:
self.assertNotIn(table_name, connection.introspection.table_names(cursor))
self.assertNotIn(table_name, connection.introspection.table_names(None))

@override_settings(
MIGRATION_MODULES={
Expand All @@ -669,7 +685,7 @@ def test_adding_field_with_default(self):
def test_adding_arrayfield_with_index(self):
table_name = "model_fields__chartextarrayindexmodel"
call_command("migrate", "model_fields_", verbosity=0)
# All fields should have regular indexes.
# All fields should have indexes.
indexes = [
c["columns"][0]
for c in connection.introspection.get_constraints(None, table_name).values()
Expand Down Expand Up @@ -779,11 +795,7 @@ class AdminUtilsTests(SimpleTestCase):

def test_array_display_for_field(self):
array_field = ArrayField(models.IntegerField())
display_value = display_for_field(
[1, 2],
array_field,
self.empty_value,
)
display_value = display_for_field([1, 2], array_field, self.empty_value)
self.assertEqual(display_value, "1, 2")

def test_array_with_choices_display_for_field(self):
Expand All @@ -794,17 +806,7 @@ def test_array_with_choices_display_for_field(self):
([1, 2], "2nd choice"),
],
)

display_value = display_for_field(
[1, 2],
array_field,
self.empty_value,
)
display_value = display_for_field([1, 2], array_field, self.empty_value)
self.assertEqual(display_value, "2nd choice")

display_value = display_for_field(
[99, 99],
array_field,
self.empty_value,
)
display_value = display_for_field([99, 99], array_field, self.empty_value)
self.assertEqual(display_value, self.empty_value)

0 comments on commit 879330b

Please sign in to comment.