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

[Bug] PATCH - GenericForeignKey relationship fails with "django.core.exceptions.FieldDoesNotExist: StudentSolution has no field named 'object_id'" #7

Open
Vadorequest opened this issue Mar 6, 2019 · 4 comments

Comments

@Vadorequest
Copy link

I have the following dynamic entity in one of my models:

# Dynamic relationship to either Org, Institution or Campus entities
  generic_owner_content_type = models.ForeignKey(
    ContentType,
    on_delete=models.CASCADE,  # TODO check if good thing
    limit_choices_to=(
      models.Q(app_label='tfp', model='org') |
      models.Q(app_label='tfp', model='institution') |
      models.Q(app_label='tfp', model='campus')
    ),
    # null=True,  # Allow a solution not to belong to any owner,
    # blank=True,
  )
  generic_owner_object_id = models.PositiveIntegerField()
  generic_owner_content_object = fields.GenericForeignKey(
    'generic_owner_content_type',
    'generic_owner_object_id'
  )

When I update the entity through the Jet Admin UI such as:
image

I get the following error on the backend logs:

[1551913953167] Jet view exception
[1551913953167] Traceback (most recent call last):
[1551913953167] File "/var/task/django/db/models/options.py", line 564, in get_field
[1551913953167] return self.fields_map[field_name]
[1551913953167] KeyError: 'object_id'
[1551913953167] During handling of the above exception, another exception occurred:
[1551913953167] Traceback (most recent call last):
[1551913953167] File "/var/task/jet_django/deps/rest_framework/views.py", line 480, in dispatch
[1551913953167] response = handler(request, *args, **kwargs)
[1551913953167] File "/var/task/jet_django/deps/rest_framework/mixins.py", line 84, in partial_update
[1551913953167] return self.update(request, *args, **kwargs)
[1551913953167] File "/var/task/jet_django/deps/rest_framework/mixins.py", line 69, in update
[1551913953167] serializer.is_valid(raise_exception=True)
[1551913953167] File "/var/task/jet_django/deps/rest_framework/serializers.py", line 236, in is_valid
[1551913953167] self._validated_data = self.run_validation(self.initial_data)
[1551913953167] File "/var/task/jet_django/deps/rest_framework/serializers.py", line 434, in run_validation
[1551913953167] value = self.to_internal_value(data)
[1551913953167] File "/var/task/jet_django/deps/rest_framework/serializers.py", line 488, in to_internal_value
[1551913953167] validated_value = field.run_validation(primitive_value)
[1551913953167] File "/var/task/jet_django/deps/rest_framework/fields.py", line 776, in run_validation
[1551913953167] return super(CharField, self).run_validation(data)
[1551913953167] File "/var/task/jet_django/deps/rest_framework/fields.py", line 524, in run_validation
[1551913953167] self.run_validators(value)
[1551913953167] File "/var/task/jet_django/deps/rest_framework/fields.py", line 538, in run_validators
[1551913953167] validator(value)
[1551913953167] File "/var/task/jet_django/deps/rest_framework/validators.py", line 79, in __call__
[1551913953167] queryset = self.filter_queryset(value, queryset)
[1551913953167] File "/var/task/jet_django/deps/rest_framework/validators.py", line 66, in filter_queryset
[1551913953167] return qs_filter(queryset, **filter_kwargs)
[1551913953167] File "/var/task/jet_django/deps/rest_framework/validators.py", line 31, in qs_filter
[1551913953167] return queryset.filter(**kwargs)
[1551913953167] File "/var/task/django/db/models/manager.py", line 82, in manager_method
[1551913953167] return getattr(self.get_queryset(), name)(*args, **kwargs)
[1551913953167] File "/var/task/django/db/models/query.py", line 844, in filter
[1551913953167] return self._filter_or_exclude(False, *args, **kwargs)
[1551913953167] File "/var/task/modeltranslation/manager.py", line 304, in _filter_or_exclude
[1551913953167] new_key = rewrite_lookup_key(self.model, key)
[1551913953167] File "/var/task/modeltranslation/manager.py", line 51, in rewrite_lookup_key
[1551913953167] fields_to_trans_models = get_fields_to_translatable_models(model)
[1551913953167] File "/var/task/modeltranslation/manager.py", line 141, in get_fields_to_translatable_models
[1551913953167] related_model = get_model_from_relation(f)
[1551913953167] File "/var/task/django/contrib/admin/utils.py", line 446, in get_model_from_relation
[1551913953167] return field.get_path_info()[-1].to_opts.model
[1551913953167] File "/var/task/django/contrib/contenttypes/fields.py", line 396, in get_path_info
[1551913953167] object_id_field = opts.get_field(self.object_id_field_name)
[1551913953167] File "/var/task/django/db/models/options.py", line 566, in get_field
[1551913953167] raise FieldDoesNotExist("%s has no field named '%s'" % (self.object_name, field_name))
[1551913953167] django.core.exceptions.FieldDoesNotExist: StudentSolution has no field named 'object_id'
[1551913953167] [ERROR] 2019-03-06T23:12:33.148Z 9a1e71e4-30ce-4e99-94b4-8d6f57257a74 Jet view exception
Traceback (most recent call last):
  File "/var/task/django/db/models/options.py", line 564, in get_field
  return self.fields_map[field_name]
KeyError: 'object_id'

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "/var/task/jet_django/deps/rest_framework/views.py", line 480, in dispatch
  response = handler(request, *args, **kwargs)
  File "/var/task/jet_django/deps/rest_framework/mixins.py", line 84, in partial_update
  return self.update(request, *args, **kwargs)
  File "/var/task/jet_django/deps/rest_framework/mixins.py", line 69, in update
  serializer.is_valid(raise_exception=True)
  File "/var/task/jet_django/deps/rest_framework/serializers.py", line 236, in is_valid
  self._validated_data = self.run_validation(self.initial_data)
  File "/var/task/jet_django/deps/rest_framework/serializers.py", line 434, in run_validation
  value = self.to_internal_value(data)
  File "/var/task/jet_django/deps/rest_framework/serializers.py", line 488, in to_internal_value
  validated_value = field.run_validation(primitive_value)
  File "/var/task/jet_django/deps/rest_framework/fields.py", line 776, in run_validation
  return super(CharField, self).run_validation(data)
  File "/var/task/jet_django/deps/rest_framework/fields.py", line 524, in run_validation
  self.run_validators(value)
  File "/var/task/jet_django/deps/rest_framework/fields.py", line 538, in run_validators
  validator(value)
  File "/var/task/jet_django/deps/rest_framework/validators.py", line 79, in __call__
  queryset = self.filter_queryset(value, queryset)
  File "/var/task/jet_django/deps/rest_framework/validators.py", line 66, in filter_queryset
  return qs_filter(queryset, **filter_kwargs)
  File "/var/task/jet_django/deps/rest_framework/validators.py", line 31, in qs_filter
  return queryset.filter(**kwargs)
  File "/var/task/django/db/models/manager.py", line 82, in manager_method
  return getattr(self.get_queryset(), name)(*args, **kwargs)
  File "/var/task/django/db/models/query.py", line 844, in filter
  return self._filter_or_exclude(False, *args, **kwargs)
  File "/var/task/modeltranslation/manager.py", line 304, in _filter_or_exclude
  new_key = rewrite_lookup_key(self.model, key)
  File "/var/task/modeltranslation/manager.py", line 51, in rewrite_lookup_key
  fields_to_trans_models = get_fields_to_translatable_models(model)
  File "/var/task/modeltranslation/manager.py", line 141, in get_fields_to_translatable_models
  related_model = get_model_from_relation(f)
  File "/var/task/django/contrib/admin/utils.py", line 446, in get_model_from_relation
  return field.get_path_info()[-1].to_opts.model
  File "/var/task/django/contrib/contenttypes/fields.py", line 396, in get_path_info
  object_id_field = opts.get_field(self.object_id_field_name)
  File "/var/task/django/db/models/options.py", line 566, in get_field
  raise FieldDoesNotExist("%s has no field named '%s'" % (self.object_name, field_name))
django.core.exceptions.FieldDoesNotExist: StudentSolution has no field named 'object_id'

I do not experience this issue when I use the Django Admin interface.


Solution

Renaming the model fields to the following fixed the issue:

# Dynamic relationship to either Org, Institution or Campus entities
  # XXX https://simpleisbetterthancomplex.com/tutorial/2016/10/13/how-to-use-generic-relations.html
  #  Do not rename "object_id", Jet Admin failed to update field when used a different variable name for some reason
  content_type = models.ForeignKey(
    ContentType,
    on_delete=models.CASCADE,  # TODO check if good thing
    limit_choices_to=(
      models.Q(app_label='tfp', model='org') |
      models.Q(app_label='tfp', model='institution') |
      models.Q(app_label='tfp', model='campus')
    ),
    # null=True,  # Allow a solution not to belong to any owner,
    # blank=True,
  )
  object_id = models.PositiveIntegerField()
  content_object = fields.GenericForeignKey(
    'content_type',
    'object_id'
  )

I guess something is hardcoded on the jet-django package and it doesn't handle custom model variable for dynamic relationships. I only have one in my case so it's not blocking, just annoying, but this should be fixed.

@Vadorequest
Copy link
Author

Note that this may actually be the right way to do it, I've not tested it yet though:
https://docs.djangoproject.com/en/2.1/ref/contrib/contenttypes/#generic-relations-in-admin

@danielhammer
Copy link

danielhammer commented Jun 2, 2019

+1
I can confirm this issue. Same happening when calling a genericforeignkey object via manage.py shell.

In my case I had two genericforeignkeys in one model, both defined by using individual attribute names (e.g. "x_content_type" instead of "content_type", "x_object_id" instead of "object_id").

Workaround:
Define at least one genericforeignkey by using the default attribute names "content_type" and "object_id" and everything works magically.

@Satcheel
Copy link

Satcheel commented Mar 3, 2023

I am also facing this issue still.
For limited things that I have tried - seems like GenericRelation is causing the problem (which is required if I want to filter my based on GenericForeignKey).

Getting the generic fk entity itself is working after filtering even if object_id is not the name.
So I think GenericRelation is the problem

@Satcheel
Copy link

Satcheel commented Mar 3, 2023

Regarding the above comment, sorry if this doesn't belong here.
I am using normal django only. Not sure what jet-django is. But seems like the same issue.
Redirect to the correct issue if there is one.

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

No branches or pull requests

3 participants