Discussion:
UniqueTogetherValidator does not work for 'simultaneous' creation of multiple instances
Clara Daia
2018-10-26 14:21:13 UTC
Permalink
Hello,

I have a view that can create multiple instances of a model at once. The
model has a unique_together constraint and I made a ModelSerializer based
on it, something like

class MyAttributeChangelog(models.Model):
parent = models.ForeignKey(ParentModel, on_delete=models.CASCADE)
start_datetime = models.DateTimeField()
...
class Meta:
ordering = ['start_datetime']
unique_together = ['start_datetime', 'installation']

class MyAttributeChangelogSerializer(serializers.ModelSerializer):
...
class Meta:
model = MyAttributeChangelog
fields = ('id', 'parent', 'start_datetime', ...)

The view receives a list of dicts and uses the serializer (with many=True)
to validate and save them. It works fine, except for the enforcement of the
unique_together constraint. In the following test I get a IntegrityError
rather than a bad request response, which was the expected:

def test_update_changelog_list_with_duplicate_datetimes(self):
"""
...
"""
parent = Parent.objects.get(...)

url = f'/api/parents/{parent.id}/my_attribute_changelog/'
data = [
{
'start_datetime': datetime(2018, 9, 20, 9, 30, 20,
tzinfo=timezone.get_current_timezone())
...
},
{
'start_datetime': datetime(2018, 9, 20, 9, 30, 20,
tzinfo=timezone.get_current_timezone())
...
}
]
response = self.client.post(url, data, format='json')

self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST)
...

I tried adding the UniqueTogetherValidator explicitly to the serializer
class, despite my understanding that it would be inferred from the Model,
but the error persists.

I know I can rather easily validate this in the view, iterating through the
items, but I think the validator should take care of that. Am I missing
something?

Best regards.
--
You received this message because you are subscribed to the Google Groups "Django REST framework" group.
To unsubscribe from this group and stop receiving emails from it, send an email to django-rest-framework+***@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.
Dipen bhatt
2018-10-29 10:58:56 UTC
Permalink
Hey there Clara,
Hope i am not too late, I created the exact scenario that you have
described but it is working perfectly fine with me.
Could you provide more of your source code, such as your view also.

My model:

class MyAttributeChangelog(models.Model):
# parent = models.ForeignKey(ParentModel, on_delete=models.CASCADE)
start_datetime = models.DateField()

installation = models.CharField(max_length=50)

def __str__(self):
return self.installation

class Meta:
ordering = ['start_datetime']
unique_together = ['start_datetime', 'installation']


My serializer


class MyAttributeChangelogSerializer(serializers.ModelSerializer):

class Meta:
model = MyAttributeChangelog
fields = ('__all__')


My viewset:


class ClaraView(viewsets.ViewSet):


def create(self, request):

ser = MyAttributeChangelogSerializer(data=request.data, many=True)

if ser.is_valid():
ser.save()
return Response(ser.data)
return Response("Invalid", status=HTTP_400_BAD_REQUEST)


I may have some wrong attribute specification.
Post by Clara Daia
Hello,
I have a view that can create multiple instances of a model at once. The
model has a unique_together constraint and I made a ModelSerializer based
on it, something like
parent = models.ForeignKey(ParentModel, on_delete=models.CASCADE)
start_datetime = models.DateTimeField()
...
ordering = ['start_datetime']
unique_together = ['start_datetime', 'installation']
...
model = MyAttributeChangelog
fields = ('id', 'parent', 'start_datetime', ...)
The view receives a list of dicts and uses the serializer (with many=True)
to validate and save them. It works fine, except for the enforcement of the
unique_together constraint. In the following test I get a IntegrityError
"""
...
"""
parent = Parent.objects.get(...)
url = f'/api/parents/{parent.id}/my_attribute_changelog/'
data = [
{
'start_datetime': datetime(2018, 9, 20, 9, 30, 20,
tzinfo=timezone.get_current_timezone())
...
},
{
'start_datetime': datetime(2018, 9, 20, 9, 30, 20,
tzinfo=timezone.get_current_timezone())
...
}
]
response = self.client.post(url, data, format='json')
self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST)
...
I tried adding the UniqueTogetherValidator explicitly to the serializer
class, despite my understanding that it would be inferred from the Model,
but the error persists.
I know I can rather easily validate this in the view, iterating through
the items, but I think the validator should take care of that. Am I missing
something?
Best regards.
--
You received this message because you are subscribed to the Google Groups
"Django REST framework" group.
To unsubscribe from this group and stop receiving emails from it, send an
For more options, visit https://groups.google.com/d/optout.
--
You received this message because you are subscribed to the Google Groups "Django REST framework" group.
To unsubscribe from this group and stop receiving emails from it, send an email to django-rest-framework+***@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.
Clara Daia
2018-10-29 12:30:34 UTC
Permalink
Hello, Dipen

Thank you for taking the time to help me. I had changed the names of the
model's fields in an attempt to make the relations clearer but ended up
making it more confusing, I suppose haha.

The unique_together relationship was supposed to be between the
'start_datetime' and the 'parent' fields:

class MyAttributeChangelog(models.Model):
start_datetime = models.DateField()

parent = models.ForeignKey(ParentModel, on_delete=models.CASCADE)

def __str__(self):
return self.installation

class Meta:
ordering = ['start_datetime']
unique_together = ['start_datetime', 'parent']

Perhaps the fact that 'parent' is a FK is key to why I'm getting the error?

This is my view code, with the provisional validation of the unique_together
constraint:

class MyChangelogViewSet(mixins.ListModelMixin, viewsets.GenericViewSet):
lookup_field = 'id'
queryset = MyChangelog.objects.all()
serializer_class = MyChangelogSerializer

def get_queryset(self):
return MyChangelog.objects.filter(parent=self.kwargs['parent_id'])

def get_serializer(self, *args, **kwargs):
if isinstance(kwargs.get('data', {}), list):
kwargs['many'] = True

return super().get_serializer(*args, **kwargs)

# Perform a rollback in case of an error
@transaction.atomic
def create(self, request, *args, **kwargs):
data = request.data
if type(data) is list:
for item in data:
# Adds parent id from URL
item['parent'] = self.kwargs['parent_id']
else:
raise ParseError(detail='Must be a list')
serializer = self.get_serializer(data=data)
serializer.is_valid(raise_exception=True)

# Checks for duplicated datetimes
dts_set = set()
for item in serializer.validated_data:
if item['start_datetime'] in dts_set:
raise ValidationError(detail='start_datetime must be unique.')
else:
dts_set.add(item['start_datetime'])

self.get_queryset().delete()
serializer.save()

return Response(serializer.data, status=status.HTTP_201_CREATED)


I added that for to check for duplicated 'start_datetime's, and it works
because 'parent' is always the same (you can see that it is added to the
dicts inside the view, from the kwarg provided by drf-nested-routers).

I shall write a test for the serializer instead of the view to narrow the
error source down.
Post by Dipen bhatt
Hey there Clara,
Hope i am not too late, I created the exact scenario that you have
described but it is working perfectly fine with me.
Could you provide more of your source code, such as your view also.
# parent = models.ForeignKey(ParentModel, on_delete=models.CASCADE)
start_datetime = models.DateField()
installation = models.CharField(max_length=50)
return self.installation
ordering = ['start_datetime']
unique_together = ['start_datetime', 'installation']
My serializer
model = MyAttributeChangelog
fields = ('__all__')
ser = MyAttributeChangelogSerializer(data=request.data, many=True)
ser.save()
return Response(ser.data)
return Response("Invalid", status=HTTP_400_BAD_REQUEST)
I may have some wrong attribute specification.
Post by Clara Daia
Hello,
I have a view that can create multiple instances of a model at once. The
model has a unique_together constraint and I made a ModelSerializer based
on it, something like
parent = models.ForeignKey(ParentModel, on_delete=models.CASCADE)
start_datetime = models.DateTimeField()
...
ordering = ['start_datetime']
unique_together = ['start_datetime', 'installation']
...
model = MyAttributeChangelog
fields = ('id', 'parent', 'start_datetime', ...)
The view receives a list of dicts and uses the serializer (with many=True
) to validate and save them. It works fine, except for the enforcement
of the unique_together constraint. In the following test I get a
IntegrityError rather than a bad request response, which was the
"""
...
"""
parent = Parent.objects.get(...)
url = f'/api/parents/{parent.id}/my_attribute_changelog/'
data = [
{
'start_datetime': datetime(2018, 9, 20, 9, 30, 20,
tzinfo=timezone.get_current_timezone())
...
},
{
'start_datetime': datetime(2018, 9, 20, 9, 30, 20,
tzinfo=timezone.get_current_timezone())
...
}
]
response = self.client.post(url, data, format='json')
self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST)
...
I tried adding the UniqueTogetherValidator explicitly to the serializer
class, despite my understanding that it would be inferred from the Model,
but the error persists.
I know I can rather easily validate this in the view, iterating through
the items, but I think the validator should take care of that. Am I missing
something?
Best regards.
--
You received this message because you are subscribed to the Google Groups
"Django REST framework" group.
To unsubscribe from this group and stop receiving emails from it, send an
For more options, visit https://groups.google.com/d/optout.
--
You received this message because you are subscribed to the Google Groups
"Django REST framework" group.
To unsubscribe from this group and stop receiving emails from it, send an
For more options, visit https://groups.google.com/d/optout.
--
You received this message because you are subscribed to the Google Groups "Django REST framework" group.
To unsubscribe from this group and stop receiving emails from it, send an email to django-rest-framework+***@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.
Dipen bhatt
2018-10-29 16:10:21 UTC
Permalink
No Clara,
The unique together validator works even in the case of Primary Key. And by
looking at the view you have written, i am assuming you are pretty new to
DRF.
Some quick observations on your view:

1. Firstly, you dont need to check whether the data is a list or not. Thats
what DRF is supposed to do. If you put many = True in the serializer, then
DRF expects the data to be list otherwise it raises a validation error. If
many = True is not set then DRF expects it to be a dictionary and does all
the required validation.
2. Try to put parent id in the reques.data itself, that way you can use
serializer.is_valid() method to reduce your code to a mere 5 line code.
3. You dont have to check for duplicated datetimes and parent id, DRF
should check that for you. I tested the same scenario as yours and it's
working fine.

The updated mode:


class Parent(models.Model):
name = models.CharField(max_length=50)

def __str__(self):
return self.name


class MyAttributeChangelog(models.Model):
parent = models.ForeignKey(Parent, on_delete=models.CASCADE)
start_datetime = models.DateField()

installation = models.CharField(max_length=50)

def __str__(self):
return self.installation

class Meta:
ordering = ['start_datetime']
unique_together = ['start_datetime', 'parent']

And no changes in any other part of code.

And no need to write test for serializer. Tell me if what i have said works
for you, if not then we will dive deeper into your code.
And again Clara, don't take parent id from the url, try to send it directly
in the post data.

So that your request.data looks like:
[
{
"start_datetime": "2018-10-29",
"installation": "hello2",
"parent":3
}
]



Hope it helps.
Post by Clara Daia
Hello, Dipen
Thank you for taking the time to help me. I had changed the names of the
model's fields in an attempt to make the relations clearer but ended up
making it more confusing, I suppose haha.
The unique_together relationship was supposed to be between the
start_datetime = models.DateField()
parent = models.ForeignKey(ParentModel, on_delete=models.CASCADE)
return self.installation
ordering = ['start_datetime']
unique_together = ['start_datetime', 'parent']
Perhaps the fact that 'parent' is a FK is key to why I'm getting the error?
This is my view code, with the provisional validation of the
lookup_field = 'id'
queryset = MyChangelog.objects.all()
serializer_class = MyChangelogSerializer
return MyChangelog.objects.filter(parent=self.kwargs['parent_id'])
kwargs['many'] = True
return super().get_serializer(*args, **kwargs)
# Perform a rollback in case of an error
@transaction.atomic
data = request.data
# Adds parent id from URL
item['parent'] = self.kwargs['parent_id']
raise ParseError(detail='Must be a list')
serializer = self.get_serializer(data=data)
serializer.is_valid(raise_exception=True)
# Checks for duplicated datetimes
dts_set = set()
raise ValidationError(detail='start_datetime must be unique.')
dts_set.add(item['start_datetime'])
self.get_queryset().delete()
serializer.save()
return Response(serializer.data, status=status.HTTP_201_CREATED)
I added that for to check for duplicated 'start_datetime's, and it works
because 'parent' is always the same (you can see that it is added to the
dicts inside the view, from the kwarg provided by drf-nested-routers).
I shall write a test for the serializer instead of the view to narrow the
error source down.
Post by Dipen bhatt
Hey there Clara,
Hope i am not too late, I created the exact scenario that you have
described but it is working perfectly fine with me.
Could you provide more of your source code, such as your view also.
# parent = models.ForeignKey(ParentModel, on_delete=models.CASCADE)
start_datetime = models.DateField()
installation = models.CharField(max_length=50)
return self.installation
ordering = ['start_datetime']
unique_together = ['start_datetime', 'installation']
My serializer
model = MyAttributeChangelog
fields = ('__all__')
ser = MyAttributeChangelogSerializer(data=request.data, many=True)
ser.save()
return Response(ser.data)
return Response("Invalid", status=HTTP_400_BAD_REQUEST)
I may have some wrong attribute specification.
Post by Clara Daia
Hello,
I have a view that can create multiple instances of a model at once. The
model has a unique_together constraint and I made a ModelSerializer based
on it, something like
parent = models.ForeignKey(ParentModel, on_delete=models.CASCADE)
start_datetime = models.DateTimeField()
...
ordering = ['start_datetime']
unique_together = ['start_datetime', 'installation']
...
model = MyAttributeChangelog
fields = ('id', 'parent', 'start_datetime', ...)
The view receives a list of dicts and uses the serializer (with
many=True) to validate and save them. It works fine, except for the
enforcement of the unique_together constraint. In the following test I
get a IntegrityError rather than a bad request response, which was the
"""
...
"""
parent = Parent.objects.get(...)
url = f'/api/parents/{parent.id}/my_attribute_changelog/'
data = [
{
'start_datetime': datetime(2018, 9, 20, 9, 30, 20,
tzinfo=timezone.get_current_timezone())
...
},
{
'start_datetime': datetime(2018, 9, 20, 9, 30, 20,
tzinfo=timezone.get_current_timezone())
...
}
]
response = self.client.post(url, data, format='json')
self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST)
...
I tried adding the UniqueTogetherValidator explicitly to the serializer
class, despite my understanding that it would be inferred from the Model,
but the error persists.
I know I can rather easily validate this in the view, iterating through
the items, but I think the validator should take care of that. Am I missing
something?
Best regards.
--
You received this message because you are subscribed to the Google
Groups "Django REST framework" group.
To unsubscribe from this group and stop receiving emails from it, send
For more options, visit https://groups.google.com/d/optout.
--
You received this message because you are subscribed to the Google Groups
"Django REST framework" group.
To unsubscribe from this group and stop receiving emails from it, send an
For more options, visit https://groups.google.com/d/optout.
--
You received this message because you are subscribed to the Google Groups
"Django REST framework" group.
To unsubscribe from this group and stop receiving emails from it, send an
For more options, visit https://groups.google.com/d/optout.
--
You received this message because you are subscribed to the Google Groups "Django REST framework" group.
To unsubscribe from this group and stop receiving emails from it, send an email to django-rest-framework+***@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.
Clara Daia
2018-10-29 16:23:44 UTC
Permalink
I will not go into why I made the view that way, but I narrowed it down to
the serializer behavior. Look at this test case:

def test_validate_changelog_list_with_duplicated_items(self):
parent = Parent.objects.get(reference='some reference')

data = [
{
'start_datetime': datetime(2018, 10, 17, 9, 31, 20,
tzinfo=timezone.get_current_timezone()),
'parent': parent.id
},
{
'start_datetime': datetime(2018, 10, 17, 9, 31, 20,
tzinfo=timezone.get_current_timezone()),
'parent': parent.id
}
]

self.assertEqual(MyChangelogSerializer(data=data,
many=True).is_valid(), False)


Due to the unique_together constraint, the validation should fail, but I get
AssertionError: True != False.
Post by Dipen bhatt
No Clara,
The unique together validator works even in the case of Primary Key. And
by looking at the view you have written, i am assuming you are pretty new
to DRF.
1. Firstly, you dont need to check whether the data is a list or not.
Thats what DRF is supposed to do. If you put many = True in the serializer,
then DRF expects the data to be list otherwise it raises a validation
error. If many = True is not set then DRF expects it to be a dictionary and
does all the required validation.
2. Try to put parent id in the reques.data itself, that way you can use
serializer.is_valid() method to reduce your code to a mere 5 line code.
3. You dont have to check for duplicated datetimes and parent id, DRF
should check that for you. I tested the same scenario as yours and it's
working fine.
name = models.CharField(max_length=50)
return self.name
parent = models.ForeignKey(Parent, on_delete=models.CASCADE)
start_datetime = models.DateField()
installation = models.CharField(max_length=50)
return self.installation
ordering = ['start_datetime']
unique_together = ['start_datetime', 'parent']
And no changes in any other part of code.
And no need to write test for serializer. Tell me if what i have said
works for you, if not then we will dive deeper into your code.
And again Clara, don't take parent id from the url, try to send it
directly in the post data.
[
{
"start_datetime": "2018-10-29",
"installation": "hello2",
"parent":3
}
]
Hope it helps.
Post by Clara Daia
Hello, Dipen
Thank you for taking the time to help me. I had changed the names of the
model's fields in an attempt to make the relations clearer but ended up
making it more confusing, I suppose haha.
The unique_together relationship was supposed to be between the
start_datetime = models.DateField()
parent = models.ForeignKey(ParentModel, on_delete=models.CASCADE)
return self.installation
ordering = ['start_datetime']
unique_together = ['start_datetime', 'parent']
Perhaps the fact that 'parent' is a FK is key to why I'm getting the error?
This is my view code, with the provisional validation of the
lookup_field = 'id'
queryset = MyChangelog.objects.all()
serializer_class = MyChangelogSerializer
return MyChangelog.objects.filter(parent=self.kwargs['parent_id'])
kwargs['many'] = True
return super().get_serializer(*args, **kwargs)
# Perform a rollback in case of an error
@transaction.atomic
data = request.data
# Adds parent id from URL
item['parent'] = self.kwargs['parent_id']
raise ParseError(detail='Must be a list')
serializer = self.get_serializer(data=data)
serializer.is_valid(raise_exception=True)
# Checks for duplicated datetimes
dts_set = set()
raise ValidationError(detail='start_datetime must be unique.')
dts_set.add(item['start_datetime'])
self.get_queryset().delete()
serializer.save()
return Response(serializer.data, status=status.HTTP_201_CREATED)
I added that for to check for duplicated 'start_datetime's, and it works
because 'parent' is always the same (you can see that it is added to the
dicts inside the view, from the kwarg provided by drf-nested-routers).
I shall write a test for the serializer instead of the view to narrow the
error source down.
Post by Dipen bhatt
Hey there Clara,
Hope i am not too late, I created the exact scenario that you have
described but it is working perfectly fine with me.
Could you provide more of your source code, such as your view also.
# parent = models.ForeignKey(ParentModel, on_delete=models.CASCADE)
start_datetime = models.DateField()
installation = models.CharField(max_length=50)
return self.installation
ordering = ['start_datetime']
unique_together = ['start_datetime', 'installation']
My serializer
model = MyAttributeChangelog
fields = ('__all__')
ser = MyAttributeChangelogSerializer(data=request.data, many=True)
ser.save()
return Response(ser.data)
return Response("Invalid", status=HTTP_400_BAD_REQUEST)
I may have some wrong attribute specification.
Post by Clara Daia
Hello,
I have a view that can create multiple instances of a model at once.
The model has a unique_together constraint and I made a ModelSerializer
based on it, something like
parent = models.ForeignKey(ParentModel, on_delete=models.CASCADE)
start_datetime = models.DateTimeField()
...
ordering = ['start_datetime']
unique_together = ['start_datetime', 'installation']
...
model = MyAttributeChangelog
fields = ('id', 'parent', 'start_datetime', ...)
The view receives a list of dicts and uses the serializer (with
many=True) to validate and save them. It works fine, except for the
enforcement of the unique_together constraint. In the following test I
get a IntegrityError rather than a bad request response, which was the
"""
...
"""
parent = Parent.objects.get(...)
url = f'/api/parents/{parent.id}/my_attribute_changelog/'
data = [
{
'start_datetime': datetime(2018, 9, 20, 9, 30, 20,
tzinfo=timezone.get_current_timezone())
...
},
{
'start_datetime': datetime(2018, 9, 20, 9, 30, 20,
tzinfo=timezone.get_current_timezone())
...
}
]
response = self.client.post(url, data, format='json')
self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST)
...
I tried adding the UniqueTogetherValidator explicitly to the
serializer class, despite my understanding that it would be inferred from
the Model, but the error persists.
I know I can rather easily validate this in the view, iterating through
the items, but I think the validator should take care of that. Am I missing
something?
Best regards.
--
You received this message because you are subscribed to the Google
Groups "Django REST framework" group.
To unsubscribe from this group and stop receiving emails from it, send
For more options, visit https://groups.google.com/d/optout.
--
You received this message because you are subscribed to the Google
Groups "Django REST framework" group.
To unsubscribe from this group and stop receiving emails from it, send
For more options, visit https://groups.google.com/d/optout.
--
You received this message because you are subscribed to the Google Groups
"Django REST framework" group.
To unsubscribe from this group and stop receiving emails from it, send an
For more options, visit https://groups.google.com/d/optout.
--
You received this message because you are subscribed to the Google Groups
"Django REST framework" group.
To unsubscribe from this group and stop receiving emails from it, send an
For more options, visit https://groups.google.com/d/optout.
--
You received this message because you are subscribed to the Google Groups "Django REST framework" group.
To unsubscribe from this group and stop receiving emails from it, send an email to django-rest-framework+***@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.
Dipen bhatt
2018-10-29 18:43:34 UTC
Permalink
Ok, after looking at the source for UniqueTogetherValidator(UTV), the
problem is UTV checks for each individual instance you have supplied in the
list the uniqueness constraint against the existing object in the database.
I think that's why your test case is failing, as the UTV is returning true
because it is checking for each individual instance separately but when
trying to create the constraint is failing as expected.
This is probably a limitation of Unique Together Validator.
You may have to write your own logic for this bit.
Need to check more on this.
Regards
Post by Clara Daia
I will not go into why I made the view that way, but I narrowed it down to
parent = Parent.objects.get(reference='some reference')
data = [
{
'start_datetime': datetime(2018, 10, 17, 9, 31, 20,
tzinfo=timezone.get_current_timezone()),
'parent': parent.id
},
{
'start_datetime': datetime(2018, 10, 17, 9, 31, 20,
tzinfo=timezone.get_current_timezone()),
'parent': parent.id
}
]
self.assertEqual(MyChangelogSerializer(data=data, many=True).is_valid(), False)
Due to the unique_together constraint, the validation should fail, but I
get AssertionError: True != False.
Post by Dipen bhatt
No Clara,
The unique together validator works even in the case of Primary Key. And
by looking at the view you have written, i am assuming you are pretty new
to DRF.
1. Firstly, you dont need to check whether the data is a list or not.
Thats what DRF is supposed to do. If you put many = True in the serializer,
then DRF expects the data to be list otherwise it raises a validation
error. If many = True is not set then DRF expects it to be a dictionary and
does all the required validation.
2. Try to put parent id in the reques.data itself, that way you can use
serializer.is_valid() method to reduce your code to a mere 5 line code.
3. You dont have to check for duplicated datetimes and parent id, DRF
should check that for you. I tested the same scenario as yours and it's
working fine.
name = models.CharField(max_length=50)
return self.name
parent = models.ForeignKey(Parent, on_delete=models.CASCADE)
start_datetime = models.DateField()
installation = models.CharField(max_length=50)
return self.installation
ordering = ['start_datetime']
unique_together = ['start_datetime', 'parent']
And no changes in any other part of code.
And no need to write test for serializer. Tell me if what i have said
works for you, if not then we will dive deeper into your code.
And again Clara, don't take parent id from the url, try to send it
directly in the post data.
[
{
"start_datetime": "2018-10-29",
"installation": "hello2",
"parent":3
}
]
Hope it helps.
Post by Clara Daia
Hello, Dipen
Thank you for taking the time to help me. I had changed the names of the
model's fields in an attempt to make the relations clearer but ended up
making it more confusing, I suppose haha.
The unique_together relationship was supposed to be between the
start_datetime = models.DateField()
parent = models.ForeignKey(ParentModel, on_delete=models.CASCADE)
return self.installation
ordering = ['start_datetime']
unique_together = ['start_datetime', 'parent']
Perhaps the fact that 'parent' is a FK is key to why I'm getting the error?
This is my view code, with the provisional validation of the
lookup_field = 'id'
queryset = MyChangelog.objects.all()
serializer_class = MyChangelogSerializer
return MyChangelog.objects.filter(parent=self.kwargs['parent_id'])
kwargs['many'] = True
return super().get_serializer(*args, **kwargs)
# Perform a rollback in case of an error
@transaction.atomic
data = request.data
# Adds parent id from URL
item['parent'] = self.kwargs['parent_id']
raise ParseError(detail='Must be a list')
serializer = self.get_serializer(data=data)
serializer.is_valid(raise_exception=True)
# Checks for duplicated datetimes
dts_set = set()
raise ValidationError(detail='start_datetime must be unique.')
dts_set.add(item['start_datetime'])
self.get_queryset().delete()
serializer.save()
return Response(serializer.data, status=status.HTTP_201_CREATED)
I added that for to check for duplicated 'start_datetime's, and it
works because 'parent' is always the same (you can see that it is added
to the dicts inside the view, from the kwarg provided by
drf-nested-routers).
I shall write a test for the serializer instead of the view to narrow
the error source down.
Post by Dipen bhatt
Hey there Clara,
Hope i am not too late, I created the exact scenario that you have
described but it is working perfectly fine with me.
Could you provide more of your source code, such as your view also.
# parent = models.ForeignKey(ParentModel, on_delete=models.CASCADE)
start_datetime = models.DateField()
installation = models.CharField(max_length=50)
return self.installation
ordering = ['start_datetime']
unique_together = ['start_datetime', 'installation']
My serializer
model = MyAttributeChangelog
fields = ('__all__')
ser = MyAttributeChangelogSerializer(data=request.data, many=True)
ser.save()
return Response(ser.data)
return Response("Invalid", status=HTTP_400_BAD_REQUEST)
I may have some wrong attribute specification.
Post by Clara Daia
Hello,
I have a view that can create multiple instances of a model at once.
The model has a unique_together constraint and I made a ModelSerializer
based on it, something like
parent = models.ForeignKey(ParentModel, on_delete=models.CASCADE)
start_datetime = models.DateTimeField()
...
ordering = ['start_datetime']
unique_together = ['start_datetime', 'installation']
...
model = MyAttributeChangelog
fields = ('id', 'parent', 'start_datetime', ...)
The view receives a list of dicts and uses the serializer (with
many=True) to validate and save them. It works fine, except for the
enforcement of the unique_together constraint. In the following test
I get a IntegrityError rather than a bad request response, which was
"""
...
"""
parent = Parent.objects.get(...)
url = f'/api/parents/{parent.id}/my_attribute_changelog/'
data = [
{
'start_datetime': datetime(2018, 9, 20, 9, 30, 20,
tzinfo=timezone.get_current_timezone())
...
},
{
'start_datetime': datetime(2018, 9, 20, 9, 30, 20,
tzinfo=timezone.get_current_timezone())
...
}
]
response = self.client.post(url, data, format='json')
self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST)
...
I tried adding the UniqueTogetherValidator explicitly to the
serializer class, despite my understanding that it would be inferred from
the Model, but the error persists.
I know I can rather easily validate this in the view, iterating
through the items, but I think the validator should take care of that. Am I
missing something?
Best regards.
--
You received this message because you are subscribed to the Google
Groups "Django REST framework" group.
To unsubscribe from this group and stop receiving emails from it, send
For more options, visit https://groups.google.com/d/optout.
--
You received this message because you are subscribed to the Google
Groups "Django REST framework" group.
To unsubscribe from this group and stop receiving emails from it, send
For more options, visit https://groups.google.com/d/optout.
--
You received this message because you are subscribed to the Google
Groups "Django REST framework" group.
To unsubscribe from this group and stop receiving emails from it, send
For more options, visit https://groups.google.com/d/optout.
--
You received this message because you are subscribed to the Google Groups
"Django REST framework" group.
To unsubscribe from this group and stop receiving emails from it, send an
For more options, visit https://groups.google.com/d/optout.
--
You received this message because you are subscribed to the Google Groups
"Django REST framework" group.
To unsubscribe from this group and stop receiving emails from it, send an
For more options, visit https://groups.google.com/d/optout.
--
You received this message because you are subscribed to the Google Groups "Django REST framework" group.
To unsubscribe from this group and stop receiving emails from it, send an email to django-rest-framework+***@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.
Dipen bhatt
2018-10-29 19:12:26 UTC
Permalink
Some what like this maybe.


class MyAttributeChangelogListSerializer(serializers.ListSerializer):

def is_valid(self, raise_exception=False):

# Checks for duplicated datetimes
# PS: I used your logic and separated it from the view
dts_set = set()
for item in self.initial_data:
if item['start_datetime'] in dts_set:
raise ValidationError(detail='start_datetime must be unique.')
else:
dts_set.add(item['start_datetime'])

super().is_valid(raise_exception)



class MyAttributeChangelogSerializer(serializers.ModelSerializer):


class Meta:
model = MyAttributeChangelog
fields = ('__all__')
list_serializer_class = MyAttributeChangelogListSerializer
Post by Dipen bhatt
Ok, after looking at the source for UniqueTogetherValidator(UTV), the
problem is UTV checks for each individual instance you have supplied in the
list the uniqueness constraint against the existing object in the database.
I think that's why your test case is failing, as the UTV is returning true
because it is checking for each individual instance separately but when
trying to create the constraint is failing as expected.
This is probably a limitation of Unique Together Validator.
You may have to write your own logic for this bit.
Need to check more on this.
Regards
Post by Clara Daia
I will not go into why I made the view that way, but I narrowed it down
parent = Parent.objects.get(reference='some reference')
data = [
{
'start_datetime': datetime(2018, 10, 17, 9, 31, 20,
tzinfo=timezone.get_current_timezone()),
'parent': parent.id
},
{
'start_datetime': datetime(2018, 10, 17, 9, 31, 20,
tzinfo=timezone.get_current_timezone()),
'parent': parent.id
}
]
self.assertEqual(MyChangelogSerializer(data=data, many=True).is_valid(), False)
Due to the unique_together constraint, the validation should fail, but I
get AssertionError: True != False.
Post by Dipen bhatt
No Clara,
The unique together validator works even in the case of Primary Key. And
by looking at the view you have written, i am assuming you are pretty new
to DRF.
1. Firstly, you dont need to check whether the data is a list or not.
Thats what DRF is supposed to do. If you put many = True in the serializer,
then DRF expects the data to be list otherwise it raises a validation
error. If many = True is not set then DRF expects it to be a dictionary and
does all the required validation.
2. Try to put parent id in the reques.data itself, that way you can use
serializer.is_valid() method to reduce your code to a mere 5 line code.
3. You dont have to check for duplicated datetimes and parent id, DRF
should check that for you. I tested the same scenario as yours and it's
working fine.
name = models.CharField(max_length=50)
return self.name
parent = models.ForeignKey(Parent, on_delete=models.CASCADE)
start_datetime = models.DateField()
installation = models.CharField(max_length=50)
return self.installation
ordering = ['start_datetime']
unique_together = ['start_datetime', 'parent']
And no changes in any other part of code.
And no need to write test for serializer. Tell me if what i have said
works for you, if not then we will dive deeper into your code.
And again Clara, don't take parent id from the url, try to send it
directly in the post data.
[
{
"start_datetime": "2018-10-29",
"installation": "hello2",
"parent":3
}
]
Hope it helps.
Post by Clara Daia
Hello, Dipen
Thank you for taking the time to help me. I had changed the names of
the model's fields in an attempt to make the relations clearer but ended up
making it more confusing, I suppose haha.
The unique_together relationship was supposed to be between the
start_datetime = models.DateField()
parent = models.ForeignKey(ParentModel, on_delete=models.CASCADE)
return self.installation
ordering = ['start_datetime']
unique_together = ['start_datetime', 'parent']
Perhaps the fact that 'parent' is a FK is key to why I'm getting the error?
This is my view code, with the provisional validation of the
lookup_field = 'id'
queryset = MyChangelog.objects.all()
serializer_class = MyChangelogSerializer
return MyChangelog.objects.filter(parent=self.kwargs['parent_id'])
kwargs['many'] = True
return super().get_serializer(*args, **kwargs)
# Perform a rollback in case of an error
@transaction.atomic
data = request.data
# Adds parent id from URL
item['parent'] = self.kwargs['parent_id']
raise ParseError(detail='Must be a list')
serializer = self.get_serializer(data=data)
serializer.is_valid(raise_exception=True)
# Checks for duplicated datetimes
dts_set = set()
raise ValidationError(detail='start_datetime must be unique.')
dts_set.add(item['start_datetime'])
self.get_queryset().delete()
serializer.save()
return Response(serializer.data, status=status.HTTP_201_CREATED)
I added that for to check for duplicated 'start_datetime's, and it
works because 'parent' is always the same (you can see that it is
added to the dicts inside the view, from the kwarg provided by
drf-nested-routers).
I shall write a test for the serializer instead of the view to narrow
the error source down.
Post by Dipen bhatt
Hey there Clara,
Hope i am not too late, I created the exact scenario that you have
described but it is working perfectly fine with me.
Could you provide more of your source code, such as your view also.
# parent = models.ForeignKey(ParentModel, on_delete=models.CASCADE)
start_datetime = models.DateField()
installation = models.CharField(max_length=50)
return self.installation
ordering = ['start_datetime']
unique_together = ['start_datetime', 'installation']
My serializer
model = MyAttributeChangelog
fields = ('__all__')
ser = MyAttributeChangelogSerializer(data=request.data, many=True)
ser.save()
return Response(ser.data)
return Response("Invalid", status=HTTP_400_BAD_REQUEST)
I may have some wrong attribute specification.
Post by Clara Daia
Hello,
I have a view that can create multiple instances of a model at once.
The model has a unique_together constraint and I made a ModelSerializer
based on it, something like
parent = models.ForeignKey(ParentModel, on_delete=models.CASCADE)
start_datetime = models.DateTimeField()
...
ordering = ['start_datetime']
unique_together = ['start_datetime', 'installation']
...
model = MyAttributeChangelog
fields = ('id', 'parent', 'start_datetime', ...)
The view receives a list of dicts and uses the serializer (with
many=True) to validate and save them. It works fine, except for the
enforcement of the unique_together constraint. In the following test
I get a IntegrityError rather than a bad request response, which was
"""
...
"""
parent = Parent.objects.get(...)
url = f'/api/parents/{parent.id}/my_attribute_changelog/'
data = [
{
'start_datetime': datetime(2018, 9, 20, 9, 30, 20,
tzinfo=timezone.get_current_timezone())
...
},
{
'start_datetime': datetime(2018, 9, 20, 9, 30, 20,
tzinfo=timezone.get_current_timezone())
...
}
]
response = self.client.post(url, data, format='json')
self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST)
...
I tried adding the UniqueTogetherValidator explicitly to the
serializer class, despite my understanding that it would be inferred from
the Model, but the error persists.
I know I can rather easily validate this in the view, iterating
through the items, but I think the validator should take care of that. Am I
missing something?
Best regards.
--
You received this message because you are subscribed to the Google
Groups "Django REST framework" group.
To unsubscribe from this group and stop receiving emails from it,
For more options, visit https://groups.google.com/d/optout.
--
You received this message because you are subscribed to the Google
Groups "Django REST framework" group.
To unsubscribe from this group and stop receiving emails from it, send
For more options, visit https://groups.google.com/d/optout.
--
You received this message because you are subscribed to the Google
Groups "Django REST framework" group.
To unsubscribe from this group and stop receiving emails from it, send
For more options, visit https://groups.google.com/d/optout.
--
You received this message because you are subscribed to the Google
Groups "Django REST framework" group.
To unsubscribe from this group and stop receiving emails from it, send
For more options, visit https://groups.google.com/d/optout.
--
You received this message because you are subscribed to the Google Groups
"Django REST framework" group.
To unsubscribe from this group and stop receiving emails from it, send an
For more options, visit https://groups.google.com/d/optout.
--
You received this message because you are subscribed to the Google Groups "Django REST framework" group.
To unsubscribe from this group and stop receiving emails from it, send an email to django-rest-framework+***@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.
Clara Daia
2018-10-31 12:37:54 UTC
Permalink
Thank you for your help Dipen. Do you think this is, "conceptually"
speaking, something the serializer should deal with by default? I was
thinking about creating an issue on the DRF Github.
Post by Dipen bhatt
Some what like this maybe.
# Checks for duplicated datetimes
# PS: I used your logic and separated it from the view
dts_set = set()
raise ValidationError(detail='start_datetime must be unique.')
dts_set.add(item['start_datetime'])
super().is_valid(raise_exception)
model = MyAttributeChangelog
fields = ('__all__')
list_serializer_class = MyAttributeChangelogListSerializer
Post by Dipen bhatt
Ok, after looking at the source for UniqueTogetherValidator(UTV), the
problem is UTV checks for each individual instance you have supplied in the
list the uniqueness constraint against the existing object in the database.
I think that's why your test case is failing, as the UTV is returning
true because it is checking for each individual instance separately but
when trying to create the constraint is failing as expected.
This is probably a limitation of Unique Together Validator.
You may have to write your own logic for this bit.
Need to check more on this.
Regards
Post by Clara Daia
I will not go into why I made the view that way, but I narrowed it down
parent = Parent.objects.get(reference='some reference')
data = [
{
'start_datetime': datetime(2018, 10, 17, 9, 31, 20,
tzinfo=timezone.get_current_timezone()),
'parent': parent.id
},
{
'start_datetime': datetime(2018, 10, 17, 9, 31, 20,
tzinfo=timezone.get_current_timezone()),
'parent': parent.id
}
]
self.assertEqual(MyChangelogSerializer(data=data, many=True).is_valid(), False)
Due to the unique_together constraint, the validation should fail, but
I get AssertionError: True != False.
Post by Dipen bhatt
No Clara,
The unique together validator works even in the case of Primary Key.
And by looking at the view you have written, i am assuming you are pretty
new to DRF.
1. Firstly, you dont need to check whether the data is a list or not.
Thats what DRF is supposed to do. If you put many = True in the serializer,
then DRF expects the data to be list otherwise it raises a validation
error. If many = True is not set then DRF expects it to be a dictionary and
does all the required validation.
2. Try to put parent id in the reques.data itself, that way you can use
serializer.is_valid() method to reduce your code to a mere 5 line code.
3. You dont have to check for duplicated datetimes and parent id, DRF
should check that for you. I tested the same scenario as yours and it's
working fine.
name = models.CharField(max_length=50)
return self.name
parent = models.ForeignKey(Parent, on_delete=models.CASCADE)
start_datetime = models.DateField()
installation = models.CharField(max_length=50)
return self.installation
ordering = ['start_datetime']
unique_together = ['start_datetime', 'parent']
And no changes in any other part of code.
And no need to write test for serializer. Tell me if what i have said
works for you, if not then we will dive deeper into your code.
And again Clara, don't take parent id from the url, try to send it
directly in the post data.
[
{
"start_datetime": "2018-10-29",
"installation": "hello2",
"parent":3
}
]
Hope it helps.
Post by Clara Daia
Hello, Dipen
Thank you for taking the time to help me. I had changed the names of
the model's fields in an attempt to make the relations clearer but ended up
making it more confusing, I suppose haha.
The unique_together relationship was supposed to be between the
start_datetime = models.DateField()
parent = models.ForeignKey(ParentModel, on_delete=models.CASCADE)
return self.installation
ordering = ['start_datetime']
unique_together = ['start_datetime', 'parent']
Perhaps the fact that 'parent' is a FK is key to why I'm getting the error?
This is my view code, with the provisional validation of the
lookup_field = 'id'
queryset = MyChangelog.objects.all()
serializer_class = MyChangelogSerializer
return MyChangelog.objects.filter(parent=self.kwargs['parent_id'])
kwargs['many'] = True
return super().get_serializer(*args, **kwargs)
# Perform a rollback in case of an error
@transaction.atomic
data = request.data
# Adds parent id from URL
item['parent'] = self.kwargs['parent_id']
raise ParseError(detail='Must be a list')
serializer = self.get_serializer(data=data)
serializer.is_valid(raise_exception=True)
# Checks for duplicated datetimes
dts_set = set()
raise ValidationError(detail='start_datetime must be unique.')
dts_set.add(item['start_datetime'])
self.get_queryset().delete()
serializer.save()
return Response(serializer.data, status=status.HTTP_201_CREATED)
I added that for to check for duplicated 'start_datetime's, and it
works because 'parent' is always the same (you can see that it is
added to the dicts inside the view, from the kwarg provided by
drf-nested-routers).
I shall write a test for the serializer instead of the view to narrow
the error source down.
Em seg, 29 de out de 2018 às 09:00, Dipen bhatt <
Post by Dipen bhatt
Hey there Clara,
Hope i am not too late, I created the exact scenario that you have
described but it is working perfectly fine with me.
Could you provide more of your source code, such as your view also.
# parent = models.ForeignKey(ParentModel, on_delete=models.CASCADE)
start_datetime = models.DateField()
installation = models.CharField(max_length=50)
return self.installation
ordering = ['start_datetime']
unique_together = ['start_datetime', 'installation']
My serializer
model = MyAttributeChangelog
fields = ('__all__')
ser = MyAttributeChangelogSerializer(data=request.data, many=True)
ser.save()
return Response(ser.data)
return Response("Invalid", status=HTTP_400_BAD_REQUEST)
I may have some wrong attribute specification.
Post by Clara Daia
Hello,
I have a view that can create multiple instances of a model at once.
The model has a unique_together constraint and I made a ModelSerializer
based on it, something like
parent = models.ForeignKey(ParentModel, on_delete=models.CASCADE)
start_datetime = models.DateTimeField()
...
ordering = ['start_datetime']
unique_together = ['start_datetime', 'installation']
...
model = MyAttributeChangelog
fields = ('id', 'parent', 'start_datetime', ...)
The view receives a list of dicts and uses the serializer (with
many=True) to validate and save them. It works fine, except for the
enforcement of the unique_together constraint. In the following
test I get a IntegrityError rather than a bad request response,
"""
...
"""
parent = Parent.objects.get(...)
url = f'/api/parents/{parent.id}/my_attribute_changelog/'
data = [
{
'start_datetime': datetime(2018, 9, 20, 9, 30, 20,
tzinfo=timezone.get_current_timezone())
...
},
{
'start_datetime': datetime(2018, 9, 20, 9, 30, 20,
tzinfo=timezone.get_current_timezone())
...
}
]
response = self.client.post(url, data, format='json')
self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST)
...
I tried adding the UniqueTogetherValidator explicitly to the
serializer class, despite my understanding that it would be inferred from
the Model, but the error persists.
I know I can rather easily validate this in the view, iterating
through the items, but I think the validator should take care of that. Am I
missing something?
Best regards.
--
You received this message because you are subscribed to the Google
Groups "Django REST framework" group.
To unsubscribe from this group and stop receiving emails from it,
For more options, visit https://groups.google.com/d/optout.
--
You received this message because you are subscribed to the Google
Groups "Django REST framework" group.
To unsubscribe from this group and stop receiving emails from it,
For more options, visit https://groups.google.com/d/optout.
--
You received this message because you are subscribed to the Google
Groups "Django REST framework" group.
To unsubscribe from this group and stop receiving emails from it, send
For more options, visit https://groups.google.com/d/optout.
--
You received this message because you are subscribed to the Google
Groups "Django REST framework" group.
To unsubscribe from this group and stop receiving emails from it, send
For more options, visit https://groups.google.com/d/optout.
--
You received this message because you are subscribed to the Google
Groups "Django REST framework" group.
To unsubscribe from this group and stop receiving emails from it, send
For more options, visit https://groups.google.com/d/optout.
--
You received this message because you are subscribed to the Google Groups
"Django REST framework" group.
To unsubscribe from this group and stop receiving emails from it, send an
For more options, visit https://groups.google.com/d/optout.
--
You received this message because you are subscribed to the Google Groups "Django REST framework" group.
To unsubscribe from this group and stop receiving emails from it, send an email to django-rest-framework+***@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.
Dipen bhatt
2018-10-31 14:34:38 UTC
Permalink
No i don't think so. Because this is the first I came across such use case.
I think this is why they have created Listserializer with the ability to
customise validation according to your needs. I believe they cannot cover
every possible use case.
Hope it helps.
Best Regards.
Dipendra Bhatt
Post by Clara Daia
Thank you for your help Dipen. Do you think this is, "conceptually"
speaking, something the serializer should deal with by default? I was
thinking about creating an issue on the DRF Github.
Post by Dipen bhatt
Some what like this maybe.
# Checks for duplicated datetimes
# PS: I used your logic and separated it from the view
dts_set = set()
raise ValidationError(detail='start_datetime must be unique.')
dts_set.add(item['start_datetime'])
super().is_valid(raise_exception)
model = MyAttributeChangelog
fields = ('__all__')
list_serializer_class = MyAttributeChangelogListSerializer
Post by Dipen bhatt
Ok, after looking at the source for UniqueTogetherValidator(UTV), the
problem is UTV checks for each individual instance you have supplied in the
list the uniqueness constraint against the existing object in the database.
I think that's why your test case is failing, as the UTV is returning
true because it is checking for each individual instance separately but
when trying to create the constraint is failing as expected.
This is probably a limitation of Unique Together Validator.
You may have to write your own logic for this bit.
Need to check more on this.
Regards
Post by Clara Daia
I will not go into why I made the view that way, but I narrowed it down
parent = Parent.objects.get(reference='some reference')
data = [
{
'start_datetime': datetime(2018, 10, 17, 9, 31, 20,
tzinfo=timezone.get_current_timezone()),
'parent': parent.id
},
{
'start_datetime': datetime(2018, 10, 17, 9, 31, 20,
tzinfo=timezone.get_current_timezone()),
'parent': parent.id
}
]
self.assertEqual(MyChangelogSerializer(data=data, many=True).is_valid(), False)
Due to the unique_together constraint, the validation should fail, but
I get AssertionError: True != False.
Post by Dipen bhatt
No Clara,
The unique together validator works even in the case of Primary Key.
And by looking at the view you have written, i am assuming you are pretty
new to DRF.
1. Firstly, you dont need to check whether the data is a list or not.
Thats what DRF is supposed to do. If you put many = True in the serializer,
then DRF expects the data to be list otherwise it raises a validation
error. If many = True is not set then DRF expects it to be a dictionary and
does all the required validation.
2. Try to put parent id in the reques.data itself, that way you can
use serializer.is_valid() method to reduce your code to a mere 5 line code.
3. You dont have to check for duplicated datetimes and parent id, DRF
should check that for you. I tested the same scenario as yours and it's
working fine.
name = models.CharField(max_length=50)
return self.name
parent = models.ForeignKey(Parent, on_delete=models.CASCADE)
start_datetime = models.DateField()
installation = models.CharField(max_length=50)
return self.installation
ordering = ['start_datetime']
unique_together = ['start_datetime', 'parent']
And no changes in any other part of code.
And no need to write test for serializer. Tell me if what i have said
works for you, if not then we will dive deeper into your code.
And again Clara, don't take parent id from the url, try to send it
directly in the post data.
[
{
"start_datetime": "2018-10-29",
"installation": "hello2",
"parent":3
}
]
Hope it helps.
Post by Clara Daia
Hello, Dipen
Thank you for taking the time to help me. I had changed the names of
the model's fields in an attempt to make the relations clearer but ended up
making it more confusing, I suppose haha.
The unique_together relationship was supposed to be between the
start_datetime = models.DateField()
parent = models.ForeignKey(ParentModel, on_delete=models.CASCADE)
return self.installation
ordering = ['start_datetime']
unique_together = ['start_datetime', 'parent']
Perhaps the fact that 'parent' is a FK is key to why I'm getting the error?
This is my view code, with the provisional validation of the
lookup_field = 'id'
queryset = MyChangelog.objects.all()
serializer_class = MyChangelogSerializer
return MyChangelog.objects.filter(parent=self.kwargs['parent_id'])
kwargs['many'] = True
return super().get_serializer(*args, **kwargs)
# Perform a rollback in case of an error
@transaction.atomic
data = request.data
# Adds parent id from URL
item['parent'] = self.kwargs['parent_id']
raise ParseError(detail='Must be a list')
serializer = self.get_serializer(data=data)
serializer.is_valid(raise_exception=True)
# Checks for duplicated datetimes
dts_set = set()
raise ValidationError(detail='start_datetime must be unique.')
dts_set.add(item['start_datetime'])
self.get_queryset().delete()
serializer.save()
return Response(serializer.data, status=status.HTTP_201_CREATED)
I added that for to check for duplicated 'start_datetime's, and it
works because 'parent' is always the same (you can see that it is
added to the dicts inside the view, from the kwarg provided by
drf-nested-routers).
I shall write a test for the serializer instead of the view to narrow
the error source down.
Em seg, 29 de out de 2018 às 09:00, Dipen bhatt <
Post by Dipen bhatt
Hey there Clara,
Hope i am not too late, I created the exact scenario that you have
described but it is working perfectly fine with me.
Could you provide more of your source code, such as your view also.
# parent = models.ForeignKey(ParentModel, on_delete=models.CASCADE)
start_datetime = models.DateField()
installation = models.CharField(max_length=50)
return self.installation
ordering = ['start_datetime']
unique_together = ['start_datetime', 'installation']
My serializer
model = MyAttributeChangelog
fields = ('__all__')
ser = MyAttributeChangelogSerializer(data=request.data, many=True)
ser.save()
return Response(ser.data)
return Response("Invalid", status=HTTP_400_BAD_REQUEST)
I may have some wrong attribute specification.
Post by Clara Daia
Hello,
I have a view that can create multiple instances of a model at
once. The model has a unique_together constraint and I made a
ModelSerializer based on it, something like
parent = models.ForeignKey(ParentModel,
on_delete=models.CASCADE)
start_datetime = models.DateTimeField()
...
ordering = ['start_datetime']
unique_together = ['start_datetime', 'installation']
...
model = MyAttributeChangelog
fields = ('id', 'parent', 'start_datetime', ...)
The view receives a list of dicts and uses the serializer (with
many=True) to validate and save them. It works fine, except for
the enforcement of the unique_together constraint. In the
following test I get a IntegrityError rather than a bad request
"""
...
"""
parent = Parent.objects.get(...)
url = f'/api/parents/{parent.id}/my_attribute_changelog/'
data = [
{
'start_datetime': datetime(2018, 9, 20, 9, 30, 20,
tzinfo=timezone.get_current_timezone())
...
},
{
'start_datetime': datetime(2018, 9, 20, 9, 30, 20,
tzinfo=timezone.get_current_timezone())
...
}
]
response = self.client.post(url, data, format='json')
self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST)
...
I tried adding the UniqueTogetherValidator explicitly to the
serializer class, despite my understanding that it would be inferred from
the Model, but the error persists.
I know I can rather easily validate this in the view, iterating
through the items, but I think the validator should take care of that. Am I
missing something?
Best regards.
--
You received this message because you are subscribed to the Google
Groups "Django REST framework" group.
To unsubscribe from this group and stop receiving emails from it,
.
For more options, visit https://groups.google.com/d/optout.
--
You received this message because you are subscribed to the Google
Groups "Django REST framework" group.
To unsubscribe from this group and stop receiving emails from it,
For more options, visit https://groups.google.com/d/optout.
--
You received this message because you are subscribed to the Google
Groups "Django REST framework" group.
To unsubscribe from this group and stop receiving emails from it,
For more options, visit https://groups.google.com/d/optout.
--
You received this message because you are subscribed to the Google
Groups "Django REST framework" group.
To unsubscribe from this group and stop receiving emails from it, send
For more options, visit https://groups.google.com/d/optout.
--
You received this message because you are subscribed to the Google
Groups "Django REST framework" group.
To unsubscribe from this group and stop receiving emails from it, send
For more options, visit https://groups.google.com/d/optout.
--
You received this message because you are subscribed to the Google Groups
"Django REST framework" group.
To unsubscribe from this group and stop receiving emails from it, send an
For more options, visit https://groups.google.com/d/optout.
--
You received this message because you are subscribed to the Google Groups
"Django REST framework" group.
To unsubscribe from this group and stop receiving emails from it, send an
For more options, visit https://groups.google.com/d/optout.
--
You received this message because you are subscribed to the Google Groups "Django REST framework" group.
To unsubscribe from this group and stop receiving emails from it, send an email to django-rest-framework+***@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.
Loading...