doableware/djongo

No validation with Django >= 3.2.x

MiltosD opened this issue · 1 comments

One line description of the issue

Since Django 3.2.1 a check has been added to prevent instantiation of an abstract model. This seems to have broken the validation of a model instance with an EmbeddedField

django/db/models/base.py

# django/db/models/base.py

class Model(metaclass=ModelBase):

    def __init__(self, *args, **kwargs):
        # Alias some things as locals to avoid repeat global lookups
        cls = self.__class__
        opts = self._meta
        _setattr = setattr
        _DEFERRED = DEFERRED
        if opts.abstract:
            raise TypeError('Abstract models cannot be instantiated.')

Example

from django.core.validators import URLValidator
from djongo import models

class Address(models.Model):
    city = models.CharField(max_length=50)
    homepage = models.URLField(validators=[URLValidator])
    class Meta:
        abstract=True

class Entry(models.Model):
    _id = models.ObjectIdField()
    address = models.EmbeddedField(model_container=Address)

from entities.models import Entry
e = Entry(address={'city': 'New York', 'homepage': 'http://mypage.com'})
e.clean_fields()

Traceback

Traceback (most recent call last):
File "/usr/lib/python3.8/code.py", line 90, in runcode
exec(code, self.locals)
File "", line 1, in
File "site-packages/django/db/models/base.py", line 1497, in clean_fields
setattr(self, f.attname, f.clean(raw_value, self))
File "site-packages/django/db/models/fields/init.py", line 754, in clean
value = self.to_python(value)
File "site-packages/djongo/models/fields.py", line 261, in to_python
value = self._value_thru_container(value)
File "site-packages/djongo/models/fields.py", line 182, in _value_thru_container
inst = self.model_container(**value)
File "site-packages/django/db/models/base.py", line 465, in init
raise TypeError("Abstract models cannot be instantiated.")
TypeError: Abstract models cannot be instantiated.

I managed to instantiate by declaring the model as managed = False in the Meta class and leaving abstract to False. What this does, is that it actually creates a migration operation for the model but does not create the collection, which, effectively is the same behavior as setting abstract = True. However, according to the Django docs, the purpose of managed = False is different, so I'm seeing this as a temporary solution...