doableware / djongo

Django and MongoDB database connector
https://www.djongomapper.com
GNU Affero General Public License v3.0
1.86k stars 351 forks source link

ArrayReferenceField not working with Rest Framework #651

Open MiltosD opened 1 year ago

MiltosD commented 1 year ago

One line description of the issue

I use Django 4.1.4 with djangorestframework 3.14.0 and drf_writable_nested 0.7.0 in order for rest framework to accept nested objects in POST

For a given model field I tried it as ManyToManyField and it works as expected. However, when I replace it with ArrayReferenceField, POST requests do not work.

Python Script

```python class Person(models.Model): surname = models.CharField(max_length=200) given_name = models.CharField(max_length=200) objects = models.DjongoManager() class Record(models.Model): curator = models.ArrayReferenceField( to=Person, blank=True, null=True ) objects = models.DjongoManager() class PersonSerializer(serializers.ModelSerializer): class Meta: model = Person fields = '__all__' class RecordSerializer(WritableNestedModelSerializer): class Meta: model = Record fields = '__all__' curator = PersonSerializer(many=True, required=False, allow_null=True) ``` #### REQUEST ```curl curl --location --request POST 'http://127.0.0.1:8000/api/registry/record/' \ --header 'Content-Type: application/json' \ --header 'Cookie: csrftoken=some_token' \ --data-raw '{ "curator": [ { "surname": "Doe", "given_name": "John" } ] }' ```` #### Traceback Internal Server Error: /api/registry/metadata_record/ Traceback (most recent call last): File "/home/mdel/venv/elrc_share4/lib/python3.8/site-packages/rest_framework/serializers.py", line 962, in create instance = ModelClass._default_manager.create(**validated_data) File "/home/mdel/venv/elrc_share4/lib/python3.8/site-packages/django/db/models/manager.py", line 85, in manager_method return getattr(self.get_queryset(), name)(*args, **kwargs) File "/home/mdel/venv/elrc_share4/lib/python3.8/site-packages/django/db/models/query.py", line 669, in create obj = self.model(**kwargs) File "/home/mdel/venv/elrc_share4/lib/python3.8/site-packages/django/db/models/base.py", line 565, in __init__ raise TypeError( **TypeError: Person() got unexpected keyword arguments: 'curator'** During handling of the above exception, another exception occurred: Traceback (most recent call last): File "/home/mdel/venv/elrc_share4/lib/python3.8/site-packages/django/core/handlers/exception.py", line 55, in inner response = get_response(request) File "/home/mdel/venv/elrc_share4/lib/python3.8/site-packages/django/core/handlers/base.py", line 197, in _get_response response = wrapped_callback(request, *callback_args, **callback_kwargs) File "/home/mdel/venv/elrc_share4/lib/python3.8/site-packages/django/views/decorators/csrf.py", line 54, in wrapped_view return view_func(*args, **kwargs) File "/home/mdel/venv/elrc_share4/lib/python3.8/site-packages/rest_framework/viewsets.py", line 125, in view return self.dispatch(request, *args, **kwargs) File "/home/mdel/venv/elrc_share4/lib/python3.8/site-packages/rest_framework/views.py", line 509, in dispatch response = self.handle_exception(exc) File "/home/mdel/venv/elrc_share4/lib/python3.8/site-packages/rest_framework/views.py", line 469, in handle_exception self.raise_uncaught_exception(exc) File "/home/mdel/venv/elrc_share4/lib/python3.8/site-packages/rest_framework/views.py", line 480, in raise_uncaught_exception raise exc File "/home/mdel/venv/elrc_share4/lib/python3.8/site-packages/rest_framework/views.py", line 506, in dispatch response = handler(request, *args, **kwargs) File "/home/mdel/venv/elrc_share4/lib/python3.8/site-packages/rest_framework/mixins.py", line 19, in create self.perform_create(serializer) File "/home/mdel/venv/elrc_share4/lib/python3.8/site-packages/rest_framework/mixins.py", line 24, in perform_create serializer.save() File "/home/mdel/venv/elrc_share4/lib/python3.8/site-packages/drf_writable_nested/mixins.py", line 229, in save return super(BaseNestedModelSerializer, self).save(**kwargs) File "/home/mdel/venv/elrc_share4/lib/python3.8/site-packages/rest_framework/serializers.py", line 212, in save self.instance = self.create(validated_data) File "/home/mdel/venv/elrc_share4/lib/python3.8/site-packages/drf_writable_nested/mixins.py", line 255, in create self.update_or_create_reverse_relations(instance, reverse_relations) File "/home/mdel/venv/elrc_share4/lib/python3.8/site-packages/drf_writable_nested/mixins.py", line 185, in update_or_create_reverse_relations related_instance = serializer.save(**save_kwargs) File "/home/mdel/venv/elrc_share4/lib/python3.8/site-packages/rest_framework/serializers.py", line 212, in save self.instance = self.create(validated_data) File "/home/mdel/venv/elrc_share4/lib/python3.8/site-packages/rest_framework/serializers.py", line 981, in create raise TypeError(msg) **TypeError: Got a `TypeError` when calling `Person.objects.create()`. This may be because you have a writable field on the serializer class that is not a valid argument to `Person.objects.create()`. You may need to make the field read-only, or override the GenericPersonSerializer.create() method to handle this correctly.** Original exception was: Traceback (most recent call last): File "/home/mdel/venv/elrc_share4/lib/python3.8/site-packages/rest_framework/serializers.py", line 962, in create instance = ModelClass._default_manager.create(**validated_data) File "/home/mdel/venv/elrc_share4/lib/python3.8/site-packages/django/db/models/manager.py", line 85, in manager_method return getattr(self.get_queryset(), name)(*args, **kwargs) File "/home/mdel/venv/elrc_share4/lib/python3.8/site-packages/django/db/models/query.py", line 669, in create obj = self.model(**kwargs) File "/home/mdel/venv/elrc_share4/lib/python3.8/site-packages/django/db/models/base.py", line 565, in __init__ raise TypeError( **TypeError: Person() got unexpected keyword arguments: 'curator'**
MiltosD commented 1 year ago

I also tried to do curator = models.ForeignKey(...) and remove many=True from RecordSerializer, just to make sure that drf_writable_nested package works. It does and the object and relation in created as expected. It seems to me that ArrayReferenceField, which I suppose is just a list of ForeignKey, cannot be properly handled by rest framework...

Tried curator = models.ForeignKey(...) and curator = PersonSerializer(many=True, required=False, allow_null=True) in RecordSerializer and got the same error. I think that Rest Framework assumes that a ForeignKey field cannot be in an array, following relational db design.