Skip to content
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

add ArrayField #197

Open
wants to merge 24 commits into
base: main
Choose a base branch
from
Open

add ArrayField #197

wants to merge 24 commits into from

Conversation

timgraham
Copy link
Collaborator

@timgraham timgraham commented Dec 10, 2024

Based on django.contrib.postgres.fields.ArrayField.

@timgraham timgraham force-pushed the arrayfield branch 2 times, most recently from e7088d1 to 6338305 Compare December 13, 2024 01:53
@timgraham timgraham force-pushed the arrayfield branch 4 times, most recently from 6a97c8e to 8a7d407 Compare January 1, 2025 15:03
Comment on lines +29 to +30
Specifies the underlying data type and behavior for the array. It
should be an instance of a subclass of
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm assuming we cannot confirm embedded models until after the embedded model PR is merged.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I plan to merge this first, then return to EMF and decide what to do.

django_mongodb/base.py Outdated Show resolved Hide resolved
Copy link
Collaborator

@Jibola Jibola left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Left some clarifying questions and comments here. Since this is mirroring PostgreSQL.ArrayField I think i'll spend more time on the documentation and the testing the next go-around. So far so good!

Comment on lines 116 to 122
if isinstance(value, list | tuple):
# Workaround for https://code.djangoproject.com/ticket/35982
if isinstance(self.base_field, DecimalField):
return [self.base_field.get_db_prep_save(i, connection) for i in value]
return [self.base_field.get_db_prep_value(i, connection, prepared=False) for i in value]
return value
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I see the ticket is now marked as resolved and the change will now work with get_db_prep_value. Is this fix now a part of 5.1 or we still need to hold onto this workaround?

Copy link
Collaborator Author

@timgraham timgraham Jan 4, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's fixed in Django 5.2. (This PR still targets Django 5.0.)

Comment on lines 248 to 258
"$eq": [
{
"$cond": {
"if": {"$eq": [lhs_mql, None]},
"then": False,
"else": {"$setIsSubset": [value, lhs_mql]},
}
},
True,
]
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

could we not use $all here?
Here's the equivalent:

{ "$all": value }

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I tried it but where does lhs_mql go? return {lhs_mql: {"$all": value}} gives, for example, {'$match': {'$expr': {'$field': {'$all': [{'$literal': 2}]}}}} but MongoDB reports "Unrecognized expression '$field'". I think $all can only be used for find, not in aggregate.

super().__init__(**kwargs)
if min_length is not None:
self.min_length = min_length
self.validators.append(ArrayMinLengthValidator(int(min_length)))
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this can come as anything other than int | None I or is this just an easy way to raise a type validation with int casting?

Copy link
Collaborator Author

@timgraham timgraham Jan 4, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I guess so. This doesn't look like typical Django code. As I recall, this code was merged a bit hastily as part of a massive PR during a sprint in 2014 without my careful review. I haven't reviewed the forms side of this PR carefully yet, and while doing so, I'll remove these casts (and probably propose they be removed upstream as well, considering there are no test failures without them).

edit: upon further examination, it was copied from CharField, and yes, it's for type validation: https://code.djangoproject.com/ticket/20440

Comment on lines 65 to 81
def validate(self, value):
super().validate(value)
errors = []
for index, item in enumerate(value):
try:
self.base_field.validate(item)
except ValidationError as error:
errors.append(
prefix_validation_error(
error,
prefix=self.error_messages["item_invalid"],
code="item_invalid",
params={"nth": index + 1},
)
)
if errors:
raise ValidationError(errors)
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks like the validate functions here share a lot with the field class version. Any chance we could make a low-pri task for a mixin class?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There are subtle differences. For example, the signature of validate() is different between form fields and model fields.

I wouldn't advise using mixins to share functionality between model fields and form fields because django.forms and django.db.models (and this project's corresponding modules) are loosely coupled.

django_mongodb/forms/array.py Outdated Show resolved Hide resolved
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants