Open VasiliyRusin opened 5 years ago
Hello @VasiliyRusin. We update nested instances if pk or id are provided. Please double-check that you are passing pk or id field into the nested serializers.
I have id
field but after save I have a new id. Also, PATCH needs the whole object to update it.
More information about this problem
class Name(models.Model):
string = models.TextField()
item = models.ForeignKey('Genre', on_delete=models.CASCADE, related_name='names', blank=True, null=True)
class Genre(models.Model):
pass
class GenreNameSerializer(serializers.ModelSerializer):
class Meta:
model = Name
fields = ('id', 'string')
class GenreSerializer(WritableNestedModelSerializer):
names = GenreNameSerializer(many=True)
class Meta:
model = Genre
My current Genre
{
"id": 3,
"names": [
{
"id": 29,
"string": "Genre3221221"
}
],
}
And after PATCH:
{
"id": 3,
"names": [
{
"id": 30,
"string": "Genre"
}
]
}
You have a new ID after you make patch query with nested id?
GET
{
"id": 3,
"names": [
{
"id": 29,
"string": "Genre3221221"
}
],
}
PATCH (with the following body)
{
"id": 3,
"names": [
{
"id": 29,
"string": "Genre updated"
}
],
}
GET
{
"id": 3,
"names": [
{
"id": 29,
"string": "Genre updated"
}
],
}
You have a new ID after you make patch query with nested id?
Yes. Then I send JSON with PATCH
{
"id": 3,
"names": [
{
"id": 29,
"string": "Genre updated"
}
],
}
GET is
{
"id": 3,
"names": [
{
"id": 30,
"string": "Genre updated"
}
]
}
@VasiliyRusin Please, share all your code and how you use it. It seems you use in an incorrect way.
I created a test with:
class Name(models.Model):
string = models.TextField()
item = models.ForeignKey('Genre', on_delete=models.CASCADE, related_name='names', blank=True, null=True)
class Genre(models.Model):
pass
class GenreNameSerializer(serializers.ModelSerializer):
class Meta:
model = Name
fields = ('id', 'string')
class GenreSerializer(WritableNestedModelSerializer):
names = GenreNameSerializer(many=True)
class Meta:
model = Genre
fields = ('id', 'names')
...
def test_issue_86(self):
serializer = serializers.GenreSerializer(data={
'names': [
{
'string': 'Genre'
}
]
})
self.assertTrue(serializer.is_valid())
instance = serializer.save()
print(serializer.data)
update_serailizer = serializers.GenreSerializer(instance=instance, data={'id': instance.pk, 'names': [
{
'id': instance.names.first().pk,
'string': 'Genre changed'
}
]})
self.assertTrue(update_serializer.is_valid())
update_serializer.save()
print(update_serializer.data)
Output:
----------------------------------------------------------------------------- Captured stdout call ------------------------------------------------------------------------------
{'names': [OrderedDict([('id', 1), ('string', u'Genre')])], 'id': 1}
{'names': [OrderedDict([('id', 1), ('string', u'Genre changed')])], 'id': 1}
@VasiliyRusin See commit for details https://github.com/beda-software/drf-writable-nested/commit/af86b7514d66130bd6b1cebfceead49debb2d273
Maybe a problem is that Name
model use InheritanceManager
from django-model-utils. Is drf-writable-nested compatible with django-model-utils?
@VasiliyRusin I don't know about compatibility with 3rd party packages. Could you please check your code without InheritanceManager?
It seems it crashes with inheritance tables. I'm not absolutely sure why this error was thrown the only now.
Log below if it can help
IntegrityError: UNIQUE constraint failed: genre_genrel10nstring.l10nstring_ptr_id
The above exception was the direct cause of the following exception:
Traceback (most recent call last):
File "/home/vasiliyrusin/.local/share/virtualenvs/onyama_backend-L3ZWsIo3/lib/python3.6/site-packages/django/core/handlers/exception.py", line 34, in inner
response = get_response(request)
File "/home/vasiliyrusin/.local/share/virtualenvs/onyama_backend-L3ZWsIo3/lib/python3.6/site-packages/django/core/handlers/base.py", line 115, in _get_response
response = self.process_exception_by_middleware(e, request)
File "/home/vasiliyrusin/.local/share/virtualenvs/onyama_backend-L3ZWsIo3/lib/python3.6/site-packages/django/core/handlers/base.py", line 113, in _get_response
response = wrapped_callback(request, *callback_args, **callback_kwargs)
File "/home/vasiliyrusin/.local/share/virtualenvs/onyama_backend-L3ZWsIo3/lib/python3.6/site-packages/django/views/decorators/csrf.py", line 54, in wrapped_view
return view_func(*args, **kwargs)
File "/home/vasiliyrusin/.local/share/virtualenvs/onyama_backend-L3ZWsIo3/lib/python3.6/site-packages/rest_framework/viewsets.py", line 114, in view
return self.dispatch(request, *args, **kwargs)
File "/home/vasiliyrusin/.local/share/virtualenvs/onyama_backend-L3ZWsIo3/lib/python3.6/site-packages/rest_framework/views.py", line 497, in dispatch
response = self.handle_exception(exc)
File "/home/vasiliyrusin/.local/share/virtualenvs/onyama_backend-L3ZWsIo3/lib/python3.6/site-packages/rest_framework/views.py", line 457, in handle_exception
self.raise_uncaught_exception(exc)
File "/home/vasiliyrusin/.local/share/virtualenvs/onyama_backend-L3ZWsIo3/lib/python3.6/site-packages/rest_framework/views.py", line 468, in raise_uncaught_exception
raise exc
File "/home/vasiliyrusin/.local/share/virtualenvs/onyama_backend-L3ZWsIo3/lib/python3.6/site-packages/rest_framework/views.py", line 494, in dispatch
response = handler(request, *args, **kwargs)
File "/home/vasiliyrusin/.local/share/virtualenvs/onyama_backend-L3ZWsIo3/lib/python3.6/site-packages/rest_framework/mixins.py", line 82, in partial_update
return self.update(request, *args, **kwargs)
File "/home/vasiliyrusin/.local/share/virtualenvs/onyama_backend-L3ZWsIo3/lib/python3.6/site-packages/rest_framework/mixins.py", line 68, in update
self.perform_update(serializer)
File "/home/vasiliyrusin/.local/share/virtualenvs/onyama_backend-L3ZWsIo3/lib/python3.6/site-packages/rest_framework/mixins.py", line 78, in perform_update
serializer.save()
File "/home/vasiliyrusin/.local/share/virtualenvs/onyama_backend-L3ZWsIo3/lib/python3.6/site-packages/drf_writable_nested/mixins.py", line 220, in save
return super(BaseNestedModelSerializer, self).save(**kwargs)
File "/home/vasiliyrusin/.local/share/virtualenvs/onyama_backend-L3ZWsIo3/lib/python3.6/site-packages/rest_framework/serializers.py", line 208, in save
self.instance = self.update(self.instance, validated_data)
File "/home/vasiliyrusin/.local/share/virtualenvs/onyama_backend-L3ZWsIo3/lib/python3.6/site-packages/drf_writable_nested/mixins.py", line 277, in update
self.update_or_create_reverse_relations(instance, reverse_relations)
File "/home/vasiliyrusin/.local/share/virtualenvs/onyama_backend-L3ZWsIo3/lib/python3.6/site-packages/drf_writable_nested/mixins.py", line 175, in update_or_create_reverse_relations
related_instance = serializer.save(**save_kwargs)
File "/home/vasiliyrusin/.local/share/virtualenvs/onyama_backend-L3ZWsIo3/lib/python3.6/site-packages/rest_framework/serializers.py", line 213, in save
self.instance = self.create(validated_data)
File "/home/vasiliyrusin/.local/share/virtualenvs/onyama_backend-L3ZWsIo3/lib/python3.6/site-packages/rest_framework/serializers.py", line 932, in create
instance = ModelClass._default_manager.create(**validated_data)
File "/home/vasiliyrusin/.local/share/virtualenvs/onyama_backend-L3ZWsIo3/lib/python3.6/site-packages/django/db/models/manager.py", line 82, in manager_method
return getattr(self.get_queryset(), name)(*args, **kwargs)
File "/home/vasiliyrusin/.local/share/virtualenvs/onyama_backend-L3ZWsIo3/lib/python3.6/site-packages/django/db/models/query.py", line 422, in create
obj.save(force_insert=True, using=self.db)
File "/home/vasiliyrusin/.local/share/virtualenvs/onyama_backend-L3ZWsIo3/lib/python3.6/site-packages/django/db/models/base.py", line 741, in save
force_update=force_update, update_fields=update_fields)
File "/home/vasiliyrusin/.local/share/virtualenvs/onyama_backend-L3ZWsIo3/lib/python3.6/site-packages/django/db/models/base.py", line 779, in save_base
force_update, using, update_fields,
File "/home/vasiliyrusin/.local/share/virtualenvs/onyama_backend-L3ZWsIo3/lib/python3.6/site-packages/django/db/models/base.py", line 870, in _save_table
result = self._do_insert(cls._base_manager, using, fields, update_pk, raw)
File "/home/vasiliyrusin/.local/share/virtualenvs/onyama_backend-L3ZWsIo3/lib/python3.6/site-packages/django/db/models/base.py", line 908, in _do_insert
using=using, raw=raw)
File "/home/vasiliyrusin/.local/share/virtualenvs/onyama_backend-L3ZWsIo3/lib/python3.6/site-packages/django/db/models/manager.py", line 82, in manager_method
return getattr(self.get_queryset(), name)(*args, **kwargs)
File "/home/vasiliyrusin/.local/share/virtualenvs/onyama_backend-L3ZWsIo3/lib/python3.6/site-packages/django/db/models/query.py", line 1186, in _insert
return query.get_compiler(using=using).execute_sql(return_id)
File "/home/vasiliyrusin/.local/share/virtualenvs/onyama_backend-L3ZWsIo3/lib/python3.6/site-packages/django/db/models/sql/compiler.py", line 1335, in execute_sql
cursor.execute(sql, params)
File "/home/vasiliyrusin/.local/share/virtualenvs/onyama_backend-L3ZWsIo3/lib/python3.6/site-packages/django/db/backends/utils.py", line 99, in execute
return super().execute(sql, params)
File "/home/vasiliyrusin/.local/share/virtualenvs/onyama_backend-L3ZWsIo3/lib/python3.6/site-packages/django/db/backends/utils.py", line 67, in execute
return self._execute_with_wrappers(sql, params, many=False, executor=self._execute)
File "/home/vasiliyrusin/.local/share/virtualenvs/onyama_backend-L3ZWsIo3/lib/python3.6/site-packages/django/db/backends/utils.py", line 76, in _execute_with_wrappers
return executor(sql, params, many, context)
File "/home/vasiliyrusin/.local/share/virtualenvs/onyama_backend-L3ZWsIo3/lib/python3.6/site-packages/django/db/backends/utils.py", line 84, in _execute
return self.cursor.execute(sql, params)
File "/home/vasiliyrusin/.local/share/virtualenvs/onyama_backend-L3ZWsIo3/lib/python3.6/site-packages/django/db/utils.py", line 89, in __exit__
raise dj_exc_value.with_traceback(traceback) from exc_value
File "/home/vasiliyrusin/.local/share/virtualenvs/onyama_backend-L3ZWsIo3/lib/python3.6/site-packages/django/db/backends/utils.py", line 84, in _execute
return self.cursor.execute(sql, params)
File "/home/vasiliyrusin/.local/share/virtualenvs/onyama_backend-L3ZWsIo3/lib/python3.6/site-packages/django/db/backends/sqlite3/base.py", line 383, in execute
return Database.Cursor.execute(self, query, params)
Just chiming in,
TLDR; Creating/deleting nested elements with put
requests works as intended.
JSON
PUT
{
"fbid": 1,
"evaluation_spec": {
"filters": [
{
"value": [
"1",
"2"
],
"field": "mobile_app_purchase_roas",
"operator": "IN_RANGE",
"id": "136"
}
],
"evaluation_type": "SCHEDULE"
},
"status": "ENABLED",
"name": "rule 1"
}
Result: AdRuleEvaluationSpecFilter object (136)
PUT
{
"value": [
"1",
"2"
],
"field": "mobile_app_purchase_roas",
"operator": "IN_RANGE",
"id": "135"
Result: AdRuleEvaluationSpecFilter object (137)
PUT
{
"value": [
"1",
"2"
],
"field": "mobile_app_purchase_roas",
"operator": "IN_RANGE",
Result: AdRuleEvaluationSpecFilter object (138)
First of all, it's not an issue. It just questions about the realization of this package. This package creates newly nested every "update". Is any reason why you don't update nested fields by "pk" or "id" if it provided?