Why swagger loading so long time and not answer - python

enter image description here
views
#swagger_auto_schema(request_body=BoardDetailSerializer, operation_summary="update method")
def patch(self, request, pk):
board = self.get_object(pk)
serializer = BoardDetailSerializer(board, data=request.data, partial=True)
if serializer.is_valid():
serializer.update()
return Response(serializer.data, status=status.HTTP_200_OK)
return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
serializers
class BoardSerializer(serializers.Serializer):
id = serializers.IntegerField(read_only=True)
title = serializers.CharField(max_length=30)
background = serializers.ImageField(required=False, default=None)
def create(self, validated_data):
board = Board(
title=validated_data['title'],
background=validated_data['background'],
)
board.save()
return board
def to_representation(self, instance):
representation = super().to_representation(instance)
representation['column'] = ColumnSerializer(instance.column.all(), many=True, context=self.context).data
return representation
[
1. - ---
](https://i.stack.imgur.com/A4yjf.png)
Idk what to do. I removed the 'Partial = True', and restarted patch request many time, but this is not workin.

Related

Django : TypeError: int() argument must be a string, a bytes-like object or a number, not 'Driver'

When creating vehicle, in driver_id, I must pass an instance of an object Drive (so when I pass a number, I find an object with this ID in the serializer and pass it, because otherwise it would give an error that an instance needs to be passed).
But when I want to display information on some object vehicle/1/, it will give an error if this object has a driver_id field of an object instance, But when it is null, then everything is fine
Vehicle Model:
class Vehicle(models.Model):
driver_id = models.ForeignKey(Driver,
related_name='vehicles',
on_delete=models.PROTECT,
null=True,
blank=True)
make = models.CharField(max_length=255)
model = models.CharField(max_length=255, verbose_name='Model')
plate_number = models.CharField(max_length=255, verbose_name='Plate Number')
created_at = models.DateTimeField(auto_now_add=True, verbose_name='Created')
updated_at = models.DateTimeField(auto_now=True, verbose_name='Updated')
def __str__(self):
return self.model
URLs:
urlpatterns = [
path('vehicle/', VehicleListView.as_view()),
path('vehicle/<int:vehicle_id>/', VehicleView.as_view())
]
class VehicleListView(APIView):
def get(self, request):
vehicles = Vehicle.objects.all()
serializer = VehicleSerializer(vehicles, many=True)
return Response({"vehicles": serializer.data})
def post(self, request):
vehicles = request.data.get('vehicle')
serializer = VehicleSerializer(data=vehicles)
if serializer.is_valid(raise_exception=True):
vehicle_saved = serializer.save()
context = {
'success': f'Vehicle {vehicle_saved.plate_number} created successfully'
}
return Response(context)
class VehicleView(APIView):
def get(self, request, vehicle_id):
vehicle = Vehicle.objects.filter(id=vehicle_id)
serializer = VehicleSerializer(vehicle, many=True)
return Response({"vehicle": serializer.data})
def put(self, request, vehicle_id):
vehicle_saved = get_object_or_404(Vehicle.objects.all(), pk=vehicle_id)
data = request.data.get('vehicle')
serializer = VehicleSerializer(instance=vehicle_saved, data=data, partial=True)
if serializer.is_valid(raise_exception=True):
vehicle_saved = serializer.save()
return Response({
"success": f"Vehicle '{vehicle_saved.plate_number}' updated successfully"
})
def delete(self, request, vehicle_id):
vehicle = get_object_or_404(Vehicle.objects.all(), pk=vehicle_id)
vehicle.delete()
return Response({
"message": f"Vehicle with id `{vehicle_id}` has been deleted."
}, status=204)
class VehicleSerializer(serializers.Serializer):
driver_id = serializers.IntegerField(required=False)
make = serializers.CharField(max_length=255)
model = serializers.CharField(max_length=255)
plate_number = serializers.CharField(max_length=255)
def create(self, validated_data):
validated_data['driver_id'] = Driver.objects.get(id=validated_data['driver_id'])
return Vehicle.objects.create(**validated_data)
def update(self, instance, validated_data):
if "driver_id" in validated_data:
instance.driver_id = Driver.objects.get(id=validated_data['driver_id'])
instance.make = validated_data.get('make', instance.make)
instance.model = validated_data.get('model', instance.model)
instance.plate_number = validated_data.get('plate_number', instance.plate_number)
instance.save()
return instance
Driver Model:
class Driver(models.Model):
first_name = models.CharField(max_length=255, verbose_name='First Name')
last_name = models.CharField(max_length=255, verbose_name='Last Name')
created_at = models.DateTimeField(auto_now_add=True, verbose_name='Created')
updated_at = models.DateTimeField(auto_now=True, verbose_name='Updated')
def __str__(self):
return self.first_name
Driver Views:
class DriverView(APIView):
def get(self, request, driver_id):
driver = Driver.objects.filter(id=driver_id)
serializer = DriverSerializer(driver, many=True)
return Response({"driver": serializer.data})
def put(self, request, driver_id):
saved_driver = get_object_or_404(Driver.objects.all(), pk=driver_id)
data = request.data.get('driver')
serializer = DriverSerializer(instance=saved_driver, data=data, partial=True)
if serializer.is_valid(raise_exception=True):
saved_driver = serializer.save()
return Response({
"success": f"Driver '{saved_driver.first_name}' updated successfully"
})
def delete(self, request, driver_id):
driver = get_object_or_404(Driver.objects.all(), pk=driver_id)
driver.delete()
return Response({
"message": f"Driver with id `{driver_id}` has been deleted."
}, status=204)
class DriverListView(APIView):
def get(self, request):
qp = request.query_params
if not qp:
drivers = Driver.objects.all()
else:
created_gte, created_lte = 'created_at__gte', 'created_at__lte'
timezone = created_gte if created_gte in qp else created_lte
time = qp.get(timezone)
time = map(int, time.split('-')[::-1])
if timezone == created_gte:
drivers = Driver.objects.filter(created_at__gte=datetime(*time))
else:
drivers = Driver.objects.filter(created_at__lte=datetime(*time))
serializer = DriverSerializer(drivers, many=True)
return Response({"driver": serializer.data})
def post(self, request):
drivers = request.data.get('driver')
serializer = DriverSerializer(data=drivers)
if serializer.is_valid(raise_exception=True):
driver_saved = serializer.save()
return Response({
'success': f'Driver {driver_saved.first_name} created successfully'
})
Driver Serializer:
class DriverSerializer(serializers.Serializer):
first_name = serializers.CharField(max_length=255)
last_name = serializers.CharField(max_length=255)
def create(self, validated_data):
return Driver.objects.create(**validated_data)
def update(self, instance, validated_data):
instance.first_name = validated_data.get('first_name', instance.first_name)
instance.last_name = validated_data.get('last_name', instance.last_name)
instance.save()
return instance
Request:
"vehicle":
{
"driver_id": 1,
"make": "5000г",
"model": "Merc",
"plate_number": "AE 1111 AB"
}
}
Error Message:
TypeError: int() argument must be a string, a bytes-like object or a number, not 'Driver'
You need to pass the id of your object so replace all occurences of the following :
instance.driver_id = Driver.objects.get(id=validated_data['driver_id'])
by
instance.driver_id = Driver.objects.get(id=validated_data['driver_id']).id
Mate, you have got quite a few things confused )
For starters, this line in delete:
vehicle = get_object_or_404(Vehicle.objects.all(), pk=vehicle_id)
should be
vehicle = get_object_or_404(Vehicle, pk=vehicle_id)
objects.all() gets you a whole quesryset, which you don't need here.
Next, this line in create:
validated_data['driver_id'] = Driver.objects.get(id=validated_data['driver_id'])
You already have driver_id in request's data. That what the client of your API wants to delete. There's absolutely no reason to reassign values in that validated_data dict. What's worse, you're doing this:
load Driver model instance from db by using driver_id from the API call. OK, makes sense. What doesn't make sense is why you are substituting driver_id and id. If you need to mirror id into another field in the model, then at least don't mutate it. But my guess is, you don't need this driver_id at all.
Then you are taking the object looked up by id (in db) = drived_id (in the request), and you assigned that object to the key 'driver_id' inside the dict - and then attempt to create a new instance which you have just looked up! Now this makes no sense.

django api how upload multiple images

I tried many times, but I just register the last one
im my model
class PropertyImage(models.Model):
property = models.ForeignKey(Property, default=None, on_delete=models.CASCADE,)
images = models.ImageField(upload_to=upload, null=True, blank=True)
def __str__(self):
return str(self.images)
serializer
class PropertyImageSerializers (serializers.ModelSerializer):
class Meta:
model = PropertyImage
#fields =('name','')
fields = '__all__'
my class view handler the post request, I tried to user method FOR to loop all images and save
view
def post(self, request, *args, **kwargs):
property_id = request.data['property']
form_data = {}
for images in request.FILES.getlist('images'):
form_data['property']= property_id
form_data['images']=images
print(form_data)
serializer = PropertyImageSerializers(data=form_data)
if serializer.is_valid():
serializer.save()
return Response(serializer.data, status=status.HTTP_201_CREATED)
return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
the for not give me the loop, does't matter how many images I send
I get this error message: AttributeError: 'PropertyImageSerializers'
object has no attribute 'property' but im my model you can see I have
the property
property is not an attribute of the PropertyImageSerializers class, that's why AttributeError
I think you will find your answer here
Update:
You can do it like this
def post(self, request, *args, **kwargs):
property_id = request.data['property']
form_data = {}
form_data['property']= property_id
success = True
response = []
for images in request.FILES.getlist('images'):
form_data['images']=images
print(form_data)
serializer = PropertyImageSerializers(data=form_data)
if serializer.is_valid():
serializer.save()
response.append(serializer.data)
else:
success = False
if success:
return Response(response, status=status.HTTP_201_CREATED)
return Response(response,status=status.HTTP_400_BAD_REQUEST)

How to update multiple records at once (bulk update) in django API

I need to update categories in many Article in one request.
In ArticleViewSet I have:
def get_serializer_class(self):
if self.action in ['partial_update', 'update']:
return ArticlePostSerializer
return ArticleSerializer
So ArticlePostSerializer need to be changed.
This is my serializers code:
class ArticleShortCategorySerializer(serializers.ModelSerializer):
class Meta:
model = Category
fields = 'id', 'name'
class ArticleSerializer(serializers.ModelSerializer):
categories = serializers.SerializerMethodField()
def get_categories(self, obj):
return ArticleShortCategorySerializer(obj.categories, many=True).data
class Meta:
model = Article
read_only_fields = 'id'
fields = ('categories', 'text') + read_only_fields
class ArticlePostSerializer(serializers.ModelSerializer):
class Meta:
model = Article
fields = 'id', 'categories', 'text'
I tried to add:
class ArticlePostListSerializer(serializers.ListSerializer):
and
class Meta:
list_serializer_class = ArticlePostListSerializer
But it doen't work.
How to change this code to do multiple update.
My json request
{
[id: 90, categories: [10,12,14]],
[id: 93, categories: [10,12,14]],
[id: 95, categories: [10,12,14]]
}
Here is sample of CreateMixins OR UpdateMixins you requested.
======================= VIEW ================================
class OrderCreate(mixins.CreateModelMixin,viewsets.GenericViewSet):
pagination_class = None
def get_queryset(self):
return []
def get_serializer_class(self):
return serializers.OrderSerializer
======================= Serializer =============================
class OrderDetailSerializer(serializers.ModelSerializer):
class Meta:
model = crm_models.OrderDetail
fields = (
'product',
'quantity',
'rate_per_unit',
'order_quantity'
)
class OrderSerializer(serializers.ModelSerializer):
order_details = OrderDetailSerializer(many = True)
class Meta:
model = crm_models.OrderMaster
fields = (
'order',
'invoice_number',
'client',
'beat_check',
'target_customer',
'order_editor_client_employee',
'order_marked',
'order_saved',
'edit_marked',
'edit_saved',
'adhoc',
'order_details'
)
def create(self, validated_data,*args,**kwargs):
ordersdetails_data = validated_data.pop('order_details')
user = None
request = self.context.get("request")
if request and hasattr(request, "user"):
user = request.user
validated_data['client'] = user.client
validated_data['order_editor_client_employee'] = user
validated_data['adhoc'] = validated_data['adhoc'] if 'adhoc' in validated_data else False
orderObj = super(OrderSerializer, self).create(validated_data,*args,**kwargs)
orderdetails = []
for details in ordersdetails_data:
orderdetails.append(crm_models.OrderDetail(
product= details['product'],
quantity = details['quantity'],
rate_per_unit = details['rate_per_unit'],
order_quantity = details['order_quantity'],
order = orderObj
))
crm_models.OrderDetail.objects.bulk_create(orderdetails)
return orderObj
In Update view function name would be changed to update, you can find more documentation http://www.django-rest-framework.org/api-guide/generic-views/#createmodelmixin
I found K. Moe's answer to this question: Django Rest Framework POST Update if existing or create much easier to understand and implement. You only need to add a create method in the serializer and use mixins.CreateModelMixin, generics.GenericAPIView in the view. Then you can use a POST request, instead of PUT/PATCH. It allows to create AND update data stored in your database. My code for the view:
class ZipCodeList(mixins.CreateModelMixin, generics.GenericAPIView):
def post(self, request, format=None):
is_many = isinstance(request.data, list)
if is_many:
serializer = ZipCodeSerializer(data=request.data, many=True)
if serializer.is_valid():
serializer.save()
return Response(serializer.data, status=status.HTTP_201_CREATED)
return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
else:
serializer = ZipCodeSerializer(data=request.data)
if serializer.is_valid():
serializer.save()
return Response(serializer.data, status=status.HTTP_201_CREATED)
return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
#Greg Holst, why so much duplication? Why not:
class ZipCodeList(mixins.CreateModelMixin, generics.GenericAPIView):
def post(self, request, format=None):
serializer = ZipCodeSerializer(data=request.data, many=isinstance(request.data, list))
if serializer.is_valid():
serializer.save()
return Response(serializer.data, status=status.HTTP_201_CREATED)
return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
Anyway, that only worked for me for creating new objects, didn't work to create-or-update in one sweep (it kept telling me these objects already exist), so this is what I did:
class ContributorSyncListAPIView(ListAPIView):
permission_classes = (isSuperUserPermission,)
allowed_methods = ("GET", "PUT")
lookup_field = "airtable_id"
serializer_class = ContributorSyncSerializer # Doesn't get used in Put, just in Get.
model = Contributor
def get_queryset(self):
return self.model.objects.all()
def put(self, request, format=None):
objects = list(request.data)
# objects is a list of OrderedDicts
try:
for o in objects:
try:
instance = self.model.objects.get(
**{self.lookup_field: o.get(self.lookup_field)}
)
for key, value in o.items():
setattr(instance, key, value)
except self.model.DoesNotExist:
instance = self.model(**o)
instance.save()
return Response(objects, status=status.HTTP_200_OK)
except Exception as e:
return Response({"detail": str(e)}, status=status.HTTP_400_BAD_REQUEST)
Note my code above is very light on validation just because it was for a process of syncing models from one environment to another by a superuser, different environments with an identical codebase; so the assumption was the data had already been validated when the data was entered into the first environment. For any other purpose you'd want to validate more. But this is what I had to do to handle a list of objects that may need to be created or updating, on an object-by-object basis.

confusion on which serializer to use to update user profile

I have a profile model for user to update. I want to have a rest api for that. I have a profile model which is too big than usual. I am working to update the user profile but I am having confusion on which serializer should i use to update the profile. Here is what i have done till now
I created the serializer for user and user profile.
class ProfileSerializer(serializers.ModelSerializer):
class Meta:
model = Profile
fields = ('token', 'user','current_location', 'permanent_location', 'dob',
'about_me', 'gender_status', 'create_profile_for', 'marital_status',
'height', 'weight', 'body_type', 'complexion',)
class UserSerializer(serializers.ModelSerializer):
profile = ProfileSerializer(required=True)
class Meta:
model = User
fields = ('id', 'profile', 'username', 'email', 'first_name', 'last_name',)
def update(self, instance, validated_data):
# instance = super(UserSerializer, self).update(validated_data)
profile_data = validated_data.pop('profile')
#updating user data
instance.first_name = validated_data.get('first_name', instance.first_name)
instance.last_name = validated_data.get('last_name', instance.last_name)
instance.email = validated_data.get('first_name', instance.email)
#updating profile data
if not instance.profile:
Profile.objects.create(user=instance, **profile_data)
instance.profile.current_location = profile_data.get('current_location', instance.profile.current_location)
instance.profile.permanent_location = profile_data.get('permanent_location', instance.profile.permanent_location)
instance.profile.weight = profile_data.get('weight', instance.profile.weight)
instance.profile.height = profile_data.get('height', instance.profile.height)
instance.profile.about_me = profile_data.get('about_me', instance.profile.about_me)
instance.profile.create_profile_for = profile_data.get('create_profile_for', instance.profile.create_profile_for)
instance.profile.body_type = profile_data.get('body_type', instance.profile.body_type)
instance.save()
return instance
This is my view
class UserProfile(APIView):
serializer_class = UserSerializer
def get(self, request, token=None, format=None):
"""
Returns a list of profile of user
"""
reply={}
try:
profile_instance = Profile.objects.filter(user=self.request.user)
if token:
profile = profile_instance.get(token=token)
reply['data'] = self.serializer_class(profile).data
else:
reply['data'] = self.serializer_class(profile_instance, many=True).data
except:
reply['data']=[]
return Response(reply, status.HTTP_200_OK)
def post(self, request, token=None, format=None):
"""
update a profile
"""
profile=None
if not token is None:
try:
profile = Profile.objects.get(user=request.user, token=token)
except Profile.DoesNotExist:
return error.RequestedResourceNotFound().as_response()
except:
return error.UnknownError().as_response()
serialized_data = self.serializer_class(profile, data=request.data, partial=True)
reply={}
if not serialized_data.is_valid():
return error.ValidationError(serialized_data.errors).as_response()
else:
profile = serialized_data.save(user=request.user)
reply['data']=self.serializer_class(profile, many=False).data
return Response(reply, status.HTTP_200_OK)
How should i handle my user profile update?
Updated my UserSerializer with update function
UPDATE with Dean Christian Armada solution
class UserProfile(APIView):
serializer_class = ProfileSerializer
def get(self, request, token=None, format=None):
"""
Returns a list of profile of user
"""
reply={}
try:
profile_instance = Profile.objects.filter(user=self.request.user)
if token:
profile = profile_instance.get(token=token)
reply['data'] = self.serializer_class(profile).data
else:
reply['data'] = self.serializer_class(profile_instance, many=True).data
except:
reply['data']=[]
return Response(reply, status.HTTP_200_OK)
def put(self, request, token=None, *args, **kwargs):
"""
update a profile
"""
print('token', token)
if token:
try:
profile = Profile.objects.get(token=token)
except:
return Response(status=status.HTTP_400_BAD_REQUEST)
serialized_data = self.serializer_class(profile, data=request.data)
reply={}
if serialized_data.is_valid():
profile = serialized_data.save(user=request.user)
reply['data'] = self.serializer_class(profile, many=False).data
return Response(reply, status.HTTP_200_OK)
else:
return Response(serialized_data.errors, status.HTTP_400_BAD_REQUEST)
With your code, i get This QueryDict instance is immutable error
It's a standard to use the PUT request method for updating in your current code and situation it is better to use the ProfileSerializer since it has more fields. Also, the way I see it you only have three fields in the User object that can be changed and those three fields I assume is rarely changed.
views.py
def put(self, request, *args, **kwargs):
"""
update a profile
"""
data = request.data
print data
try:
profile = Profile.objects.get(token=data.get('token'))
except:
return Response(status=status.HTTP_400_BAD_REQUEST)
serializer = self.serializer_class(profile, data=request.data)
if serializer.is_valid():
serializer.save()
return Response(serializer.data, status.HTTP_200_OK)
else:
return Response(serializer.errors,
status.HTTP_400_BAD_REQUEST)
serializers.py
class ProfileSerializer(serializers.ModelSerializer):
user = serializers.PrimaryKeyRelatedField(read_only=True)
class Meta:
model = Profile
fields = ('user', 'height', 'weight', 'token')
def to_internal_value(self, data):
first_name = data.pop('first_name', None)
last_name = data.pop('last_name', None)
data = super(ProfileSerializer, self).to_internal_value(data)
data['first_name'] = first_name
data['last_name'] = last_name
return data
def update(self, instance, validated_data):
first_name = validated_data.pop('first_name', None)
last_name = validated_data.pop('last_name', None)
user_inst_fields = {}
if first_name:
user_inst_fields['first_name'] = first_name
if last_name:
user_inst_fields['last_name'] = last_name
if user_inst_fields:
User.objects.update_or_create(pk=instance.user.id,
defaults=user_inst_fields)
profile, created = Profile.objects.update_or_create(
token=instance.token, defaults=validated_data)
return profile
Simply just set the user to read only for it to avoid validation

django rest framework url arguments with patch not working

Edit
I suspect the whole problem with my UpdateApiView is with the url. No matter how I change it, will return 404.
url(r'verify-phone/(?P<phone_id>^\d+)$', view.VerifyPhone.as_view(), name='verify-phone'),
it returns
{
"detail": "Not found."
}
[18/Apr/2016 01:39:02] "PATCH /api/verify-phone/phone_id=00980 HTTP/1.1" 404 4941
Why?
views.py
class VerifyPhone(generics.UpdateAPIView):
permission_classes = (AllowAny,)
serializer_class = serializers.VerifyPhoneSerializer
allowed_methods = ['PATCH']
lookup_field = 'phone_id'
def get_queryset(self):
phone_id = self.request.query_params.get('phone_id', None)
queryset = User.objects.filter(phone_id=phone_id)
return queryset
def update(self, request, *args, **kwargs):
print('inside update')
print(request.data)
partial = kwargs.pop('partial', False)
instance = self.get_object()
print(instance)
serializer = self.get_serializer(instance, data=request.data, partial=partial)
print(serializer)
serializer.is_valid(raise_exception=True)
self.perform_update(serializer)
print('done perform update')
return Response(serializer.data)
serializers.py
class VerifyPhoneSerializer(serializers.ModelSerializer):
regex = r'\d+'
verification_code = serializers.RegexField(regex, max_length=7, min_length=7, allow_blank=False)
phone_id = serializers.HyperlinkedRelatedField(view_name='verify-phone', lookup_field='phone_id', read_only=True)
class Meta:
model = User
fields = ('verification_code', 'phone_id')
def validate(self, data):
verification = api.tokens.verify(data['phone_id'], data['verification_code'])
if verification.response.status_code != 200:
raise serializers.ValidationError("Invalid verification code.")
return data
def update(self, instance, validated_data):
instance.phone_number_validated = True
instance.save()
return instance
Second question Is this correct to get phone_id from the views?
phone_id = serializers.HyperlinkedRelatedField(view_name='verify-phone', lookup_field='phone_id', read_only=True)
Looking at your api url def, I think you should call:
/api/verify-phone/00980
instead of
/api/verify-phone/phone_id=00980
I also think something is wrong with the url def itself (the ^ before \d):
url(r'verify-phone/(?P<phone_id>^\d+)$', view.VerifyPhone.as_view(), name='verify-phone')
should be
url(r'verify-phone/(?P<phone_id>\d+)$', view.VerifyPhone.as_view(), name='verify-phone')
or
url(r'verify-phone/(?P<phone_id>\d{5})$', view.VerifyPhone.as_view(), name='verify-phone')

Categories