Getting error related to django model arrayfield - django

When trying to access serialized.data, throws error for type models.ArrayField, but is successfully stored in mongodb.
models.py
class testStep(models.Model):
number = models.PositiveSmallIntegerField(max_length=100)
payload = models.JSONField(blank=True)
header = models.JSONField(blank=False)
assertors = models.EmbeddedField(model_container=assertStep, blank=True)
class Meta:
abstract = True
class test(models.Model):
_id = models.ObjectIdField(primary_key=True)
appId = models.ForeignKey(application, on_delete=models.PROTECT)
name = models.TextField(blank=False, unique=True)
step = models.ArrayField(model_container=step, blank=True, default=list)
serializers.py
class testStepSerializer(serializers.ModelSerializer):
class Meta:
model = models.testCase
fields = '__all__'
read_only_fields = ['dateCreated', 'dateUpdated', ]
def update(self, instance, validated_data):
instance.testStep = validated_data.get('testStep', instance.testStep)
instance.save()
return instance
views.py
def put(self, request, testCaseId, format=None):
tcDetails = self.getTcDetails(testCaseId)
reqData = request.data.copy()
if serialized.is_valid():
serialized.save()
return Response(json.loads(json_util.dumps(serialized.data)), status=status.HTTP_200_OK)
trace back:
line 355, in value_to_string
post_dict = self._obj_thru_fields('value_to_string', container_obj)
File "C:\Users\XYZ\AppData\Local\Programs\Python\Python37-32\lib\site-packages\djongo\models\fields.py",
line 177, in _obj_thru_fields
processed_value[field.attname] = getattr(field, func_name)(obj, *other_args)
File "C:\Users\XYZ\AppData\Local\Programs\Python\Python37-32\lib\site-packages\djongo\models\fields.py",
line 201, in value_to_string
raise TypeError(f'Type: {type(value)} cannot be serialized')
TypeError: Type: <class 'NoneType'> cannot be serialized
update
when i comment out
"assertors = models.EmbeddedField(model_container=assertStep, blank=True)"
i am not seeing this error. Why is this causing error?

Related

Graphene/Django mutations return null

I created the following model in my django app:
class Post(models.Model):
title = models.CharField(max_length=125, unique=True)
slug_title = models.SlugField(max_length=255, unique=True)
body = models.TextField()
published_date = models.DateTimeField(auto_now_add=True)
author = models.ForeignKey(User, on_delete=models.CASCADE)
status = models.BooleanField(default=False)
class Meta:
ordering = ['-published_date']
def __str__(self):
return self.title
def save(self, *args, **kwargs):
self.slug_title = slugify(self.title)
super(Post, self).save(*args, **kwargs)
I want to be able to use an API to do POST/GET requests later on, so I decided to use graphene-django. Everything is installed properly and working.
As per the tutorials, I created my schema.py file as follow:
# define schema
class PostType(DjangoObjectType):
class Meta:
model = Post
fields = ('title', 'body', 'author', 'published_date', 'status', 'slug_title')
class UserType(DjangoObjectType):
class Meta:
model = get_user_model()
class PostInput(graphene.InputObjectType):
title = graphene.String()
slug_title = graphene.String()
body = graphene.String()
author = graphene.Int()
published_date = graphene.DateTime()
status=graphene.Boolean()
class CreatePost(graphene.Mutation):
class Arguments:
input = PostInput(required=True)
post = graphene.Field(PostType)
#classmethod
def mutate(cls, root, info, input):
post = Post()
post.title = input.title
post.slug_title = input.slug_title
post.body = input.body
post.author = input.author
post.published_date = input.published_date
post.status = input.status
post.save()
return CreatePost(post=post)
class Query(graphene.ObjectType):
all_posts = graphene.List(PostType)
author_by_username = graphene.Field(UserType, username=graphene.String())
posts_by_author = graphene.List(PostType, username=graphene.String())
posts_by_slug = graphene.List(PostType, slug=graphene.String())
def resolve_all_posts(root, info):
return Post.objects.all()
def resolve_author_by_username(root, info, username):
return User.objects.get(username=username)
def resolve_posts_by_author(root, info, username):
return Post.objects.filter(author__username=username)
def resolve_posts_by_slug(root, info, slug):
return Post.objects.filter(slug_title=slug)
class Mutation(graphene.ObjectType):
create_post=CreatePost.Field()
schema = graphene.Schema(query=Query, mutation=Mutation)
The query part is working as expected, but my mutation section doesn't seem to be working. When I try to create a mutation, I get the below:
{
"data": {
"create_post": {
"post": null
}
}
}
I created a quick test to see if any errors would output when I run the mutation, but everything seems ok there.
def test_mutation_1(self):
response = self.query(
'''
mutation {
createPost(input:{
title:"Test Title",
body:"Test body",
author:1,
publishedDate:"2016-07-20T17:30:15+05:30",
status:false
})
{
post {
title
}
}
}
'''
)
self.assertResponseNoErrors(response)
I get no error messages.
Any help would be appreciated!
The error: errors=[GraphQLError('Cannot assign "1": "Post.author" must be a "User" instance.'
The solution: Alter my CreatePost class to the following:
post.author = User.objects.get(pk=input.author_id)
Instead of:
post.author = input.author_id

Django rest framework test does not create instances in test database

I'm having an issue in DRF tests when creating instance of a model, the status code in response is 'HTTP_201_CREATED' but the instance it self does not exist in the testing db.
here is my model :
class Item(SafeDeleteModel):
owner = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.CASCADE, verbose_name=_("Owner"))
name = models.CharField(_("Name"), max_length=150)
category = TreeForeignKey('merssis.ItemCategory', on_delete=models.SET_NULL, null=True, verbose_name=_("Category"))
fixed_price = models.FloatField(_("Fixed price"), default=0)
main_pic = ProcessedImageField(verbose_name=_("Main picture"), upload_to='item_pics', processors=[ItemWatermarker()],format='JPEG')
main_pic_thumbnail = ImageSpecField(source='main_pic',
processors=[ResizeToFill(384, 256)],
format='JPEG',
options={'quality': 100})
geo_location = models.PointField(srid=4326, null=True, blank=True, verbose_name=_("Geolocation"))
_safedelete_policy = SOFT_DELETE_CASCADE
def __str__(self):
return self.name
Serializer :
class ItemCreateSerializer(GeoFeatureModelSerializer):
PRICE_TYPE_CHOICES = (
('fixed', _('Fixed') ),
('open', _('Open') ),
)
owner = serializers.HiddenField(default=serializers.CurrentUserDefault())
price_type = serializers.ChoiceField(choices=PRICE_TYPE_CHOICES)
category = serializers.PrimaryKeyRelatedField(queryset=ItemCategory.objects.all(), many=False)#ItemCategorySerializer(many=False)
main_pic = serializers.ImageField(use_url='item_pics')
def validate(self, data):
user = self.context['request'].user
geo_data = data.get('geo_location')
#Validate fixed price value
if data['price_type'] == 'fixed':
if data.get('fixed_price') == None or int(data.get('fixed_price')) <= 0:
raise serializers.ValidationError({"fixed_price" :INVALIDE_PRICE_ERROR})
#Price type is open should explicitly set fixed price to 0
if data['price_type'] == 'open':
data['fixed_price'] = 0
#Validate geo_location
#geo_location post data form ====> {"type":"Point", "coordinates":[37.0625,-95.677068]}
if geo_data:
if not validate_in_country_location(user, geo_data):
raise serializers.ValidationError({"geo_location":OUTSIDE_COUNTRY_MSG})
return data
def create(self, validated_data):
#Remove price_type value since it is not a field in the model
#We used to determine th price type on the serializer only
validated_data.pop('price_type')
return Item(**validated_data)
class Meta:
model = Item
geo_field = 'geo_location'
fields = ( 'owner',
'name',
'price_type',
'category',
'fixed_price',
'main_pic',
'geo_location',
)
The view :
class ItemCreateAPIView(CreateAPIView):
queryset = Item.objects.all()
serializer_class = ItemCreateSerializer
permission_classes = [permissions.IsAuthenticated]
def perform_create(self, serializer, *args, **kwargs):
self.check_object_permissions(self.request, self.request.user)
serializer.save()
The test case :
class ItemTestCase(APITestCase):
def test_create_new_item(self):
"""
Testing Add new item functionality
"""
self.client_1 = APIClient()
self.user_1 = create_new_user(email='tester1#gmail.com', username='tester_1', password='qsdf654654', gender='male')
self.client_1.login(username='tester_1',password='qsdf654654')
image_file = create_test_image()
category = ItemCategory.objects.create(name='SomeCat')
new_item_data = {
'name': 'New Item',
'price_type' : 'open',
'category': str(category.pk),
'main_pic': image_file,
}
response = self.client_1.post(url, new_item_data, format='multipart')
items = Item.objects.filter(name='New Item')
print(response.status_code)
self.assertEqual( response.status_code, status.HTTP_201_CREATED)
self.assertEqual( items.count(), 1)
and when i run the test i get '201' printed in console AND AssertionError: 0 != 1
i'm fvkin confused
In the serializer create() the object was never saved so change:
return Item(**validated_data)
to:
return Item.objects.create(**validated_data) # create the object

Django Rest Framework multiple image Upload: Expected a dictionary, but got InMemoryUploadedFile

I'm trying to create an API to upload multiple images per session, I'm using the Django REST Framework. This is the error that I get in Postman:
{
"images": {
"0": {
"non_field_errors": [
"Invalid data. Expected a dictionary, but got InMemoryUploadedFile."
]
}
}
}
models.py with 2 tables
class PostSession(models.Model):
class Meta:
verbose_name = 'session'
verbose_name_plural = 'sessions'
name = models.CharField(
max_length=255,
)
class PostImage(models.Model):
class Meta:
verbose_name = 'photo'
verbose_name_plural = 'photos'
name = models.ForeignKey(
to=PostSession,
on_delete=models.CASCADE,
null=True,
blank=True,
)
file = models.ImageField(
upload_to='photos',
)
serializers.py
class PostImageRetrieveSerializer(serializers.ModelSerializer):
class Meta:
model = PostImage
fields = '__all__'
class PostImageUpdateSerializer(serializers.Serializer):
"""
This class for validate and save child items purpose
"""
name = serializers.CharField(required=False, allow_null=True, allow_blank=True, )
file = serializers.ImageField(required=True, allow_null=False, allow_empty_file=False, )
def create(self, validated_data):
session_name = validated_data.get('name')
image_file = validated_data.get('file')
if session_name and isinstance(session_name, str):
session, _ = PostSession.objects.get_or_create(name=session_name, )
else:
session = None
instance = PostImage.objects.create(
name=session,
file=image_file,
)
return self.update(
instance=instance,
validated_data=validated_data,
)
def update(self, instance, validated_data):
instance.save()
return instance
class PostUploadSerializer(serializers.Serializer):
images = serializers.ListField(
child=PostImageUpdateSerializer(required=True, allow_null=False, many=False, ),
required=True,
allow_null=False,
allow_empty=False,
)
def validate(self, attrs):
images_list = attrs.get('images')
if not isinstance(images_list, list):
raise exceptions.ValidationError(detail={
'images': ['`images` field must be a list of dict object!', ],
})
return attrs
def save_many(self):
images_list = self.validated_data.get('images')
post_image_instances = []
for image_obj in images_list:
try:
post_image_serializer = PostImageSerializer(
context=self.context,
data=image_obj,
many=False,
)
post_image_serializer.is_valid(raise_exception=True, )
post_image = post_image_serializer.save()
post_image_instances.append(post_image)
except:
# TODO: Remove previous saved instances if needed (inside `post_image_instances`)?
pass
return post_image_instances
def create(self, validated_data):
pass
def update(self, instance, validated_data):
pass
viewsets.py
class PostViewSet(viewsets.GenericViewSet):
parser_classes = [parsers.MultiPartParser, parsers.JSONParser, ]
serializer_class = PostImageRetrieveSerializer
queryset = PostImage.objects.all()
#action(methods=['POST', ], detail=False, serializer_class=PostUploadSerializer, )
def upload_images(self, request, *args, **kwargs):
upload_serializer = PostUploadSerializer(
context={'request': request, },
data=request.data,
many=False,
)
upload_serializer.is_valid(raise_exception=True, )
post_image_instances = upload_serializer.save_many()
serializer = self.get_serializer(
post_image_instances,
many=True,
)
return response.Response(
data=serializer.data,
status=status.HTTP_200_OK,
)
The Idea is that the API can create a session with multiple images.
https://gist.github.com/cokelopez/a98ee5569991b6555ecd216764c193ec

django: Displaying database errors when debug = False

I am using Django Rest Framework to perform get() post() on existing database. In the models, I haven't defined any primary or foreign key relations as these constraints are handled at database level. When I have debug = True in the settings.py file, the database level errors with traceback get displayed. However, when debug = False, I wish to display the errors in the response.
eg: error message:
IntegrityError at /dqf_api/ReceiptLog/
(1062, "Duplicate entry 'ede pivot-dummy-ede_case_76-ede pivot command 76' for key 'PRIMARY'")
When debug = True, this is displayed. When debug = False, how do I catch this error and display it?
EDIT : Including code modules
models.py
class TestCaseCommandRun(models.Model):
# fields ..Doesn't have id field as the database doesn't have it
class Meta:
managed = False
db_table = 'test_case_command_run'
unique_together = (('team_name', 'suite_name', 'suite_run_id', 'case_name', 'command_name'),)
class TestCaseCommandRunResults(models.Model):
# fields ..Doesn't have id field as the database doesn't have it
class Meta:
managed = False
db_table = 'test_case_command_run_results'
unique_together = (('suite_run_id', 'command_run_id', 'rule_name', 'result_id'),)
views.py
class TestCaseCommandRunViewSet(viewsets.ModelViewSet):
queryset = models.TestCaseCommandRunViewSet.objects.values('team_name','suite_name','suite_run_id', 'case_name','command_name','command_run_id','run_start','run_end','result','run_status')
serializer_class = serializers.TestCaseCommandRunViewSet
class TestCaseCommandRunResultsViewSet(viewsets.ModelViewSet):
queryset = models.TestCaseCommandRunResultsViewSet.objects.values('suite_run_id','command_run_id','rule_name', 'result_id',
'result','expected_values','actual_values','report_values','extended_values')
serializer_class = serializers.TestCaseCommandRunResultsViewSet
class ReceiptLogViewSet(CreateAPIView):
serializer_class = serializers.ReceiptLogSerializer.ReceiptLogSerializerClass
serializers.py
class TestCaseCommandRunResultsViewSet(serializers.ModelSerializer):
class Meta:
model = models.TestCaseCommandRunResultsViewSet
fields = ['suite_run_id','command_run_id','rule_name', 'result_id','result','expected_values','actual_values','report_values','extended_values']
class TestCaseCommandRunSerializer(serializers.ModelSerializer):
class Meta:
model = models.TestCaseCommandRunSerializer
fields = ['team_name','suite_name','suite_run_id', 'case_name','command_name','command_run_id','run_start','run_end','result','run_status']
class ReceiptLogSerializerClass(serializers.Serializer):
team_name = serializers.CharField(max_length=30)
suite_name = serializers.CharField(max_length=100)
suite_run_id = serializers.CharField(max_length=50,required=False, allow_blank=True, default=datetime.now().strftime('%Y%m%d%H%M%S'))
case_name = serializers.CharField(max_length=50)
command_name = serializers.CharField(max_length=50)
command_run_id = serializers.CharField(max_length=50,required=False, allow_blank=True, default='Not Applicable')
run_start = serializers.DateTimeField(default=datetime.now, required=False)
run_end = serializers.DateTimeField(default=datetime.now, required=False)
result = serializers.CharField(max_length=10, default='Not Applicable')
run_status = serializers.CharField(max_length=10)
rule_name = serializers.CharField( max_length=50, required=False, allow_blank=True, default='Not Applicable')
expected_values = serializers.CharField(max_length=200, allow_blank=True)
actual_values = serializers.CharField(max_length=200, allow_blank=True)
report_values = serializers.CharField(max_length=200, allow_blank=True)
extended_values = serializers.CharField(max_length=200, allow_blank=True)
def create(self, validated_data):
team_name = validated_data.get('team_name', None)
suite_name = validated_data.get('suite_name', None)
suite_run_id = validated_data.get('suite_run_id', None)
case_name = validated_data.get('case_name', None)
command_name = validated_data.get('command_name', None)
command_run_id = validated_data.get('command_run_id', None)
run_start = validated_data.get('run_start', None)
run_end = validated_data.get('run_end', None)
result = validated_data.get('result', None)
run_status = validated_data.get('run_status', None)
rule_name = validated_data.get('rule_name', None)
expected_values = validated_data.get('expected_values', None)
actual_values = validated_data.get('actual_values', None)
report_values = validated_data.get('report_values', None)
extended_values = validated_data.get('extended_values', None)
test_case_command_run_data = {
'team_name': team_name,
'suite_name': suite_name,
'suite_run_id': suite_run_id,
'case_name': case_name,
'command_name': command_name,
'command_run_id': command_run_id,
'run_start': run_start,
'run_end': run_end,
'result': result,
'run_status': run_status
}
TestCaseCommandRunSerializer.create(TestCaseCommandRunSerializer(), validated_data=test_case_command_run_data)
test_case_command_run_result_data = {
'suite_run_id': suite_run_id,
'command_run_id': command_run_id,
'rule_name': rule_name,
'result_id': self.result_id,
'result': result,
'expected_values': expected_values,
'actual_values': actual_values,
'report_values': report_values,
'extended_values': extended_values,
}
TestCaseCommandRunResultsSerializer.create(TestCaseCommandRunResultsSerializer(), validated_data=test_case_command_run_result_data)
self.result_id += 1
return validated_data
urls.py
router = routers.DefaultRouter()
router.register(r'test_case_command_runs', views.TestCaseCommandRunViewSet)
router.register(r'test_case_command_run_results', views.TestCaseCommandRunResultsViewSet)
urlpatterns = [
url(r'^dqf_api/', include(router.urls)),
url(r'^dqf_api/ReceiptLog/', views.ReceiptLogView.ReceiptLogViewSet.as_view(), name='ReceiptLog')]
EDIT: code Fix
Added this to serializers.py
def create(self, validated_data):
try:
return super().create(validated_data)
except IntegrityError as e:
error_msg = "IntegrityError occurred while creating entry in test_case_command_run_result model. Detailed Error: %s" %e
raise serializers.ValidationError(error_msg)
Maybe try something like this:
if serializer.is_valid():
serializer.save()
return Response("success")
else:
return Response(serialzier.errors)
Using a try catch statement
In views.py
class TestCaseCommandRunViewSet(viewsets.ModelViewSet):
try:
queryset = models.TestCaseCommandRunViewSet.objects.values('team_name','suite_name','suite_run_id', 'case_name','command_name','command_run_id','run_start','run_end','result','run_status')
serializer_class = serializers.TestCaseCommandRunViewSet
return Response("working")
except Exception as e:
return Response(e)
class TestCaseCommandRunResultsViewSet(viewsets.ModelViewSet):
try:
queryset = models.TestCaseCommandRunResultsViewSet.objects.values('suite_run_id','command_run_id','rule_name','result_id','result','expected_values','actual_values','report_values','extended_values')
serializer_class = serializers.TestCaseCommandRunResultsViewSet
retutn Response("Working")
except Exception as e:
return Response(e)
class ReceiptLogViewSet(CreateAPIView):
try:
serializer_class = serializers.ReceiptLogSerializer.ReceiptLogSerializerClass
return Response("working")
except Exception as e:
return Response(e)

How to send extra parameters to the serializer, not included in the model?

I need to send parameters to the serializer that do not exist in the model, so the serializer delete this data
I also have a nested serializer with a custom .create() function
This is the request data sended by the frontend ajax.
request data = {'data': [{'usuario': 269, 'coworkers': [328, 209], 'inicio': '2019-01-24T23:30:43.926Z', 'estado': 'progress', 'operacion': {'orden': 24068, 'proceso': 'ALEZADO FINAL-TORNO CNC T7 1'}}, {'usuario': 269, 'coworkers': [208, 212], 'inicio': '2019-01-24T23:30:43.926Z', 'estado': 'progress', 'operacion': {'orden': 24067, 'proceso': 'ALEZADO FINAL-TORNO CNC T7 1'}}]}
Model:
class TiempoOperacion(models.Model):
inicio = models.DateTimeField(blank=True, null=True)
fin = models.DateTimeField(blank=True, null=True)
operacion = models.ForeignKey(Operacion, related_name='tiempos', on_delete=models.CASCADE)
cantidad = models.IntegerField(default=0)
usuario = models.CharField(max_length=40)
motivo_pausa = models.CharField(max_length=140, default=None, null=True)
estado = models.CharField(
max_length=15,
choices=TASKS_STATUS_CHOICES,
default=UNACTION,
)
Viewset:
class TiempoOperacionViewSet(CustomViewSet):
model_class = TiempoOperacion
serializer_class = TiempoOperacionSerializer
pagination_class = SmallResultsSetPagination
order_by = '-inicio'
def create(self, request):
datos = request.data.get('listorders') if 'listorders' in request.data else request.data
tiemposerializer = self.serializer_class(data=datos, many=True, fields=('coworkers', 'operacion'))
if tiemposerializer.is_valid():
tiemposerializer.save()
return Response(tiemposerializer.data)
else:
return Response(tiemposerializer.errors, status=status.HTTP_400_BAD_REQUEST)
Serializer:
class TiempoOperacionSerializer(serializers.ModelSerializer):
operacion = OperacionSerializer()
class Meta:
model = TiempoOperacion
fields = '__all__'
def create(self, validate_data):
operacion_data = validate_data.pop('operacion')
print (f"\n\n validate_data : {validate_data} \n\n")
if not operacion_data:
raise ValidationError({
'operacion': 'This field object is required.'
})
coworkers = validate_data.get('coworkers')
query_operaciones = Operacion.objects.filter(**operacion_data)[:1]
if query_operaciones.count() > 0:
operacion = query_operaciones[0]
else:
operacion = Operacion.objects.create(**operacion_data)
tiempo_obj = validate_data
tiempo = TiempoOperacion.objects.create(operacion=operacion, **tiempo_obj)
if coworkers:
tiempos_list = []
for coworker in coworkers:
tiempo_obj.update({'usuario': coworker})
tiempos_list.append(TiempoOperacion(operacion=operacion, **tiempo_obj))
tiempos = TiempoOperacion.objects.bulk_create(tiempos_list)
return tiempo
I hope to get coworkers in create serialize function
But I only have:
validate_data : {'inicio': datetime.datetime(2019, 1, 24, 18, 12, 25, 251000, tzinfo=<DstTzInfo 'America/Bogota' -05-1 day, 19:00:00 STD>), 'usuario': '269', 'estado': 'progress'}
Re-write the to_internal_value function
class TiempoOperacionSerializer(serializers.ModelSerializer):
operacion = OperacionSerializer()
class Meta:
model = TiempoOperacion
fields = '__all__'
def create(self, validate_data):
operacion_data = validate_data.pop('operacion')
if not operacion_data:
raise ValidationError({
'operacion': 'This field object is required.'
})
coworkers = validate_data.pop('coworkers')
query_operaciones = Operacion.objects.filter(**operacion_data)[:1]
if query_operaciones.count() > 0:
operacion = query_operaciones[0]
else:
operacion = Operacion.objects.create(**operacion_data)
tiempo_obj = validate_data
tiempo = TiempoOperacion.objects.create(operacion=operacion, **tiempo_obj)
if coworkers:
tiempos_list = []
for coworker in coworkers:
tiempo_obj.update({'usuario': coworker})
tiempos_list.append(TiempoOperacion(operacion=operacion, **tiempo_obj))
tiempos = TiempoOperacion.objects.bulk_create(tiempos_list)
return tiempo
#This function rewrite the value validated_data mentioned in above function
def to_internal_value(self, data):
if not "coworkers" in data:
data['coworkers'] = []
return data