#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 , 3 years ago
Description: | modified (diff) |
---|
comment:2 by , 3 years ago
Cc: | added |
---|
comment:3 by , 3 years ago
comment:4 by , 3 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 , 3 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 , 3 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 justNone
in 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:
However, this works with Django<=3.2.9.