How to deal with .errors for Django API framework - django

I have the following codes:
models.py
class Device(models.Model):
hostname = models.CharField(max_length=50, unique = True)
ipaddr = models.GenericIPAddressField(protocol='ipv4', unique=True, verbose_name='mangement IP') ##Use for mgt_id_addr
date_added = models.DateTimeField(default=timezone.now)
def __str__(self):
return self.hostname
class DeviceDetail(models.Model):
SUBNET_CHOICES = (
('16','16'),
('17', '17'),
('18','18'),
('19','19'),
('20','20'),
('21', '21'),
('22', '22'),
('23', '23'),
('24', '24'),
('25', '25'),
('26', '26'),
('27', '27'),
('28', '28'),
('29', '29'),
('30', '30'),
)
DEV_MODS =(
('Catalyst 9606R', 'Catalyst 9606R'),
('C9300L-48T-4X', 'C9300L-48T-4X')
)
mgt_interface = models.CharField(max_length=50)
subnetmask = models.CharField(max_length=2, choices = SUBNET_CHOICES)
ssh_id = models.CharField(max_length=50)
ssh_pwd = models.CharField(max_length=50)
enable_secret = models.CharField(max_length=50)
dev_mod=models.CharField(max_length=50, choices = DEV_MODS) ##device_model replacement
DD2DKEY = models.ForeignKey(Device, on_delete=models.CASCADE) ##The key to link up the tables
def __str__(self):
return self.hostname
serializers.py
from rest_framework import serializers
from .models import Device, DeviceDetail
class DeviceSerializers(serializers.ModelSerializer):
class Meta:
model=Device
fields = '__all__'
class DeviceDetailSerializers(serializers.ModelSerializer):
class Meta:
model = DeviceDetail
fields = ['mgt_interface', 'subnetmask', 'ssh_id', 'ssh_pwd', 'enable_secret', 'dev_mod']
views.py
#api_view(['POST'])
def create_device(request):
device = Device()
devicedetail = DeviceDetail()
deviceserializer = DeviceSerializers(device, data = request.data)
devdserializer = DeviceDetailSerializers(devicedetail, data = request.data)
if deviceserializer.is_valid() and devdserializer.is_valid():
device_instance = deviceserializer.save()
devdserializer.save(DD2DKEY=device_instance)
results = {
"device":deviceserializer.data,
"device_details" : devdserializer.data,
}
return Response(results, status=status.HTTP_201_CREATED)
else:
errors = {
"device":deviceserializer.errors,
"device_details" : devdserializer.errors,
}
return Response(errors, status=status.HTTP_400_BAD_REQUEST)
I am facing the following error: AssertionError: You must call .is_valid() before accessing .errors.
How do i correct this to fixed the issue in case my codes enter the else condition so it will show the errors of the serializers? Because no matter what I still have to return a response if it failes

If deviceserializer.is_valid() fails, then the if condition will shortcircuit and thus not call devdserializer.is_valid(). You thus should ensure that it calls devdserializer.is_valid() as well:
if deviceserializer.is_valid() and devdserializer.is_valid():
device_instance = deviceserializer.save()
devdserializer.save(DD2DKEY=device_instance)
results = {
"device":deviceserializer.data,
"device_details" : devdserializer.data,
}
return Response(results, status=status.HTTP_201_CREATED)
else:
# ↓ ensure that is_valid() is called
devdserializer.is_valid()
errors = {
"device":deviceserializer.errors,
"device_details" : devdserializer.errors,
}
return Response(errors, status=status.HTTP_400_BAD_REQUEST)

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

201 Created - but no new object in SqLite database

Edit 25th Jan:
here's my model!
class rat(models.Model):
name = models.CharField(max_length=132, null =True)
body_colour = models.ForeignKey(BodyColour, on_delete=models.CASCADE, null = True, related_name='body_colour')
eye_colour = models.ForeignKey(EyeColour, on_delete=models.CASCADE, null = True, related_name='eye_colour')
user = models.ForeignKey(User, on_delete=models.CASCADE, null = True)
bio = models.TextField(null = True, blank = True)
born = models.DateField(auto_now_add=True)
image = models.ForeignKey(Image, on_delete=models.CASCADE, null = True, blank=True)
Adding rat.save() to the serializer gives me the following error: TypeError: int() argument must be a string, a bytes-like object or a real number, not 'dict'
I have a button that users can click on to add an object to their account. It's sent through django to my sqlite db, and in the console log there are no errors. It says "201 Created", and yet there is no new object in the database.
Someone else had the same problem as me, the solution was getting rid of some methods in the serializer, but they don't specify what they got rid off.
What's causing this?
Here is my serializer:
class RatSerializer(FlexFieldsModelSerializer, serializers.ModelSerializer):
name = serializers.CharField()
user = serializers.CharField(source='user.username', required=False)
userid = serializers.CharField(source='user.id', required=False)
body_colour = BodyColourSerializer()
eye_colour = EyeColourSerializer()
image = ImageSerializer(required=False)
class Meta:
model = rat
exclude = ['bio']
def create(self, data):
request = self.context.get("request")
user = request.user
return rat( name = data["name"],
body_colour = BodyColour(name=data["body_colour"]["name"]),
eye_colour = EyeColour(name=data["eye_colour"]["name"]),
image = Image(),
user = user)
My views:
class ratViewset(ModelViewSet, APIView):
serializer_class = RatSerializer
# queryset = rat.objects.all()
def get_queryset(self):
user = self.request.user
if user.is_anonymous:
return rat.objects.all()
return rat.objects.filter(user=user.id)
def post(self, request):
rat = request.data.get('rat')
# creates rat with the above data
serializer = RatSerializer(data=rat)
if serializer.is_valid(raise_exception=True):
serializer.save()
print(serializer.data, type(serializer.data))
return Response(serializer.data, status=status.HTTP_201_CREATED)
return Response(serializer.errors, status=status)
Grateful for any help!

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 api and django_filter problem

I have problem with rest_framework.viewsets.ReadOnlyModelViewSet.
class ProductFilter(filters.FilterSet):
meat_type = filters.CharFilter(lookup_expr='slug__iexact')
category = filters.CharFilter(lookup_expr='slug__iexact')
class Meta:
model = Product
fields = {
'price': ['gte', 'lte'],
}
ordering_fields = ['price', ]
class ProductViewSet(viewsets.ReadOnlyModelViewSet):
queryset = Product.objects.all()
serializer_class = ProductSerializer
filterset_class = ProductFilter
#action(methods=['get'], detail=False)
def get_products(self, request):
products = self.get_queryset().order_by('-created')
serializer = self.get_serializer_class()(products, many=True)
print('SHOW IT')
if len(products) == 0:
return Response(status=status.HTTP_204_NO_CONTENT)
return Response(serializer.data, status=status.HTTP_200_OK)
My problem is that print in get_products not work, but code give good result with filters objects. My urls:
router = routers.DefaultRouter()
router.register('', views.ProductViewSet)
urlpatterns = [
path('shop/', include(router.urls))
]
Tests:
class TestViews(TestCase):
def setUp(self):
self.client = Client()
self.url = "/api/shop/"
self.search_url = "/api/shop/?price__lte={}&price__gte={}&meat_type={}&category={}"
self.category1 = Category.objects.create(name='cattest1',
slug='cattest1')
self.category2 = Category.objects.create(name='cattest2',
slug='cattest2')
self.meat_type1 = MeatType.objects.create(name='meattest1',
slug='meattest1')
self.meat_type2 = MeatType.objects.create(name='meattest2',
slug='meattest2')
self.product1 = Product.objects.create(category=self.category1,
meat_type=self.meat_type2,
name='prodtest1',
slug='prodtest1',
price=50)
self.product2 = Product.objects.create(category=self.category1,
meat_type=self.meat_type1,
name='prodtest2',
slug='prodtest2',
price=75)
self.product3 = Product.objects.create(category=self.category2,
meat_type=self.meat_type2,
name='prodtest3',
slug='prodtest3',
price=20)
self.product4 = Product.objects.create(category=self.category2,
meat_type=self.meat_type1,
name='prodtest4',
slug='prodtest4',
price=150)
def test_get_products_all(self):
response = self.client.get(self.url)
self.assertEqual(200, response.status_code)
self.assertEqual(4, len(response.data))
def test_get_products_no_content(self):
Product.objects.all().delete()
response = self.client.get(self.url)
self.assertEqual(204, response.status_code)
def test_product_greater_than(self):
response = self.client.get(self.search_url.format(
"", "55", "", ""
))
self.assertEqual(200, response.status_code)
self.assertEqual(2, len(response.data))
Test test_get_products_no_content fail with error:
assertionError: 204 != 200.
Somebody have any idea?
Thanks for any answer
Magnus
EDIT
Created this function, is pass good data to filter.
DICT {'price__lte': '50', 'price__gte': '100', 'meat_type': 'wieprzowina'}
But I have problem when I put it as filter argument. Got error:
invalid literal for int() with base 10: 'wieprzowina'. It try to change string to number, but I dont know why.
def get_queryset(self):
filter_params = self.request.query_params
filter_params_dict = {k: str(v) for (k, v) in filter_params.dict().items()
if v is not None and str(v) != ""}
print('DICT', filter_params_dict)
queryset = Product.objects.filter(**filter_params_dict)
return queryset
EDIT 2:
class Product(models.Model):
category = models.ForeignKey(Category,
related_name='products',
on_delete=models.CASCADE)
meat_type = models.ForeignKey(MeatType,
on_delete=models.CASCADE)
name = models.CharField(max_length=150,
db_index=True)
slug = models.SlugField(max_length=150,
db_index=True)
image = models.ImageField(upload_to='products/%Y/%m/%d',
default='no-image.png')
description = models.TextField(blank=True)
price = models.DecimalField(max_digits=10, decimal_places=2)
available = models.BooleanField(default=True)
created = models.DateTimeField(auto_now_add=True)
updated = models.DateTimeField(auto_now=True)
class Meta:
ordering = ('price',)
index_together = (('id', 'slug'),)
def __str__(self):
return self.name
def get_absolute_url(self):
return reverse('shop:detail',
args=[self.category.slug, self.id, self.slug])
You are using the incorrect url ,you should use this url for your custom action:
/api/shop/get_products/
The url you are using i.e /api/shop/ will call the default list action of the viewset not your custom action and thats why you are getting 200 status code always
You can read more about viewset here:
ViewSets

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)