#33307 closed Uncategorized (invalid)
Model got both positional and keyword arguments for field 'id'.
| Reported by: | אורי | Owned by: | nobody |
|---|---|---|---|
| Component: | Database layer (models, ORM) | Version: | 4.0 |
| Severity: | Normal | Keywords: | |
| Cc: | אורי | Triage Stage: | Unreviewed |
| Has patch: | no | Needs documentation: | no |
| Needs tests: | no | Patch needs improvement: | no |
| Easy pickings: | no | UI/UX: | no |
Description (last modified by )
Hi, I got failed tests with Django==4.0rc1 and I suspect this is related to Django. The tests pass with Django==3.2.9.
Here is one of the failed tests (on Windows, with Python 3.8):
======================================================================
ERROR: test_user_can_read_chat_with_a_blocker (speedy.core.messages.tests.test_views.ChatDetailViewTestCase)
----------------------------------------------------------------------
Traceback (most recent call last):
File "speedy\core\messages\tests\test_views.py", line 78, in test_user_can_read_chat_with_a_blocker
self.client.login(username=self.user_1.slug, password=tests_settings.USER_PASSWORD)
File ".venv_3.8\lib\site-packages\django\test\client.py", line 604, in login
user = authenticate(**credentials)
File ".venv_3.8\lib\site-packages\django\views\decorators\debug.py", line 42, in sensitive_variables_wrapper
return func(*func_args, **func_kwargs)
File ".venv_3.8\lib\site-packages\django\contrib\auth\__init__.py", line 76, in authenticate
user = backend.authenticate(request, **credentials)
File ".venv_3.8\lib\site-packages\django\contrib\auth\backends.py", line 42, in authenticate
user = UserModel._default_manager.get_by_natural_key(username)
File "speedy\core\accounts\managers.py", line 37, in get_by_natural_key
return self.distinct().get(Q(username=normalize_username(username=username)) | Q(email_addresses__email=username))
File ".venv_3.8\lib\site-packages\django\db\models\query.py", line 435, in get
num = len(clone)
File ".venv_3.8\lib\site-packages\django\db\models\query.py", line 262, in __len__
self._fetch_all()
File ".venv_3.8\lib\site-packages\django\db\models\query.py", line 1356, in _fetch_all
self._prefetch_related_objects()
File ".venv_3.8\lib\site-packages\django\db\models\query.py", line 841, in _prefetch_related_objects
prefetch_related_objects(self._result_cache, *self._prefetch_related_lookups)
File ".venv_3.8\lib\site-packages\django\db\models\query.py", line 1760, in prefetch_related_objects
obj_list, additional_lookups = prefetch_one_level(
File ".venv_3.8\lib\site-packages\django\db\models\query.py", line 1902, in prefetch_one_level
all_related_objects = list(rel_qs)
File ".venv_3.8\lib\site-packages\django\db\models\query.py", line 280, in __iter__
self._fetch_all()
File ".venv_3.8\lib\site-packages\django\db\models\query.py", line 1354, in _fetch_all
self._result_cache = list(self._iterable_class(self))
File ".venv_3.8\lib\site-packages\django\db\models\query.py", line 69, in __iter__
obj = model_cls.from_db(db, init_list, row[model_fields_start:model_fields_end])
File ".venv_3.8\lib\site-packages\django\db\models\base.py", line 519, in from_db
new = cls(*values)
File "speedy\core\uploads\models.py", line 31, in __init__
super().__init__(*args, **kwargs)
File ".venv_3.8\lib\site-packages\django\db\models\base.py", line 446, in __init__
raise TypeError(
TypeError: Image() got both positional and keyword arguments for field 'id'.
======================================================================
Our repository is open source at https://github.com/speedy-net/speedy-net
This might be related to our models:
import os
from django.db import models
from django.utils.translation import gettext_lazy as _
from speedy.core.base.models import TimeStampedModel
from speedy.core.base.fields import RegularUDIDField
from speedy.core.base.utils import generate_regular_udid
from .utils import uuid_dir
class File(TimeStampedModel):
id = RegularUDIDField()
owner = models.ForeignKey(to='accounts.Entity', verbose_name=_('owner'), on_delete=models.SET_NULL, blank=True, null=True)
file = models.FileField(verbose_name=_('file'), upload_to=uuid_dir)
is_stored = models.BooleanField(verbose_name=_('is stored'), default=False)
size = models.PositiveIntegerField(verbose_name=_('file size'), default=0)
@property
def basename(self):
return os.path.basename(self.file.name)
class Meta:
verbose_name = _('file')
verbose_name_plural = _('uploaded files')
ordering = ('-date_created',)
def __init__(self, *args, **kwargs):
if (not (kwargs.get('id'))):
kwargs['id'] = generate_regular_udid()
super().__init__(*args, **kwargs)
def __str__(self):
return '{} (owner={})'.format(self.basename, self.owner)
def save(self, *args, **kwargs):
self.size = self.file.size
return super().save(*args, **kwargs)
def store(self):
self.is_stored = True
self.save(update_fields={'is_stored', 'size'})
class Image(File):
visible_on_website = models.BooleanField(verbose_name=_('visible on website'), default=False)
aws_image_moderation_time = models.DateTimeField(verbose_name=_('AWS image moderation time'), blank=True, null=True)
aws_facial_analysis_time = models.DateTimeField(verbose_name=_('AWS facial analysis time'), blank=True, null=True)
aws_raw_image_moderation_results = models.JSONField(verbose_name=_('AWS raw image moderation results'), blank=True, null=True)
aws_raw_facial_analysis_results = models.JSONField(verbose_name=_('AWS raw facial analysis results'), blank=True, null=True)
number_of_faces = models.PositiveSmallIntegerField(verbose_name=_('number of faces'), blank=True, null=True)
class Meta:
verbose_name = _('images')
verbose_name_plural = _('uploaded images')
ordering = ('-date_created',)
from django.conf import settings as django_settings
from django.db import models
from django.utils.translation import gettext_lazy as _
from .utils import generate_regular_udid, generate_small_udid
from . import validators as speedy_core_base_validators
# Never use this class directly. Only use inherited classes below.
class UDIDField(models.CharField):
class Meta:
abstract = True
def __init__(self, *args, **kwargs):
given_kwargs = kwargs
defaults = {
'verbose_name': _('ID'),
'primary_key': True,
'db_index': True,
'unique': True,
}
kwargs = defaults
kwargs.update(given_kwargs)
super().__init__(*args, **kwargs)
class SmallUDIDField(UDIDField):
id_generator = staticmethod(generate_small_udid)
def __init__(self, *args, **kwargs):
given_kwargs = kwargs
defaults = {
'max_length': django_settings.SMALL_UDID_LENGTH,
'validators': [speedy_core_base_validators.small_udid_validator],
}
kwargs = defaults
kwargs.update(given_kwargs)
super().__init__(*args, **kwargs)
class RegularUDIDField(UDIDField):
id_generator = staticmethod(generate_regular_udid)
def __init__(self, *args, **kwargs):
given_kwargs = kwargs
defaults = {
'max_length': django_settings.REGULAR_UDID_LENGTH,
'validators': [speedy_core_base_validators.regular_udid_validator],
}
kwargs = defaults
kwargs.update(given_kwargs)
super().__init__(*args, **kwargs)
Change History (7)
comment:1 by , 4 years ago
| Description: | modified (diff) |
|---|
comment:2 by , 4 years ago
| Cc: | added |
|---|
comment:3 by , 4 years ago
comment:4 by , 4 years ago
| Component: | Uncategorized → Database layer (models, ORM) |
|---|---|
| Resolution: | → invalid |
| Status: | new → closed |
Thanks for the report. It's an intended change, see 73b1b225ce1a3318d4478f90cc0db0a260aba3aa and #22640. This error was added to prevent misconfigurations when values for the same fields are passed in args and kwargs as in your case. I'd recommend moving this logic to the save().
follow-up: 6 comment:5 by , 4 years ago
What is the case of starting an instance with an id in args? Is it a real id or just None? I think we need the id to be set before calling save(), we use the id for generating the file name and if it's just None in args then we need to generate it.
comment:6 by , 4 years ago
Replying to אורי:
What is the case of starting an instance with an id in args? Is it a real id or just
None? I think we need the id to be set before callingsave(), we use the id for generating the file name and if it's justNonein args then we need to generate it.
When calling get() an instance is initialize with id from the database, so previously id in kwargs was ignored, e.g.
>>> x = File.objects.create()
>>> x.id
98176428171628647286
>>> x = File.objects.get() # <- Here your code generates another "id" that was ignored
>>> # super().__init__() was called with File('98176428171628647286', id='some_other_id')
>>> x.id
98176428171628647286
I see the line (31) is related to the following method:
def __init__(self, *args, **kwargs): if (not (kwargs.get('id'))): kwargs['id'] = generate_regular_udid() super().__init__(*args, **kwargs)However, this works with Django<=3.2.9.