I have an optional ImageField in my model with a default image. I am using Django Rest Framework for the model api. However when I try to post (post request outside the browser) without images I continue getting the error:No file was submitted. Check the encoding type on the form.
models.py
class Detector(models.Model):
average_image = models.ImageField(upload_to='average_image/',
default='average_image/default.png',
null=True, blank=True)
serializer.py
class DetectorSerializer(serializers.ModelSerializer):
class Meta:
model = Detector
fields = ('average_image')
views.py
class DetectorAPIList(generics.ListCreateAPIView):
serializer_class = DetectorSerializer
What am I missing?
Thanks for your time!
i hit the same issue, i had to explicitly mark my image field in the serializer as blank:
class DetectorSerializer(serializers.ModelSerializer):
average_image = serializers.ImageField(source='average_image', blank=True)
class Meta:
model = Detector
fields = ('average_image',)
It seems that rest framework is unable to grab it from model or something. After this i am able to POST data to the API using requests like this:
import requests
from requests.auth import HTTPBasicAuth
r = requests.post(
'http://localhost:8000/detectors/',
data={'some': 'data'},
auth=HTTPBasicAuth('user', 'password')
)
print r.text
And this is the response, as you can see it used the default from the model field definition:
{"average_image": "average_image/default.png"}
You can also try to POST with specified file:
r = requests.post(
'http://localhost:8000/detectors/',
files={'average_image': open('/path/to/image.jpg')},
data={'some': 'data'},
auth=HTTPBasicAuth('user', 'password')
)
print r.text
Hope this helps.
Related
I wanna change all fields of a json object except 'pk' in DRF. I just need to keep one json data. When adding a new data ,this one should override existing data. Is there a way to do it with django ?
my models.py
class ClientUser2(models.Model):
phone_number = models.CharField(max_length=20,unique=True)
name = models.CharField(max_length=100,blank=True)
status = models.IntegerField(default=1)
class ClientNameSerializer(serializers.HyperlinkedModelSerializer):
class Meta:
model = ClientUser2
fields = ('url','phone_number','name','status','pk')
my views.py
class ClientViewSet(viewsets.ModelViewSet):
"""
API endpoint that allows messages to be viewed or edited.
"""
queryset = ClientUser2.objects.all()
serializer_class = ClientNameSerializer
and it's my api root
api_root
If you want to be able to only retrieve and update models you can use RetrieveUpdateApiView
Reference : https://www.django-rest-framework.org/api-guide/generic-views/#retrieveupdateapiview
I have an image field in my Django model and I am trying to get absolute path of the image field output from Graphene so as to connect to my client.
class ProfileType(DjangoObjectType):
class Meta: model = Profile
def resolve_avatar(self, info, **kwargs):
print(info.context.build_absolute_uri(self.avatar))
I do not get an absolute file field path.
If Profile.avatar is ImageField you should use self.avatar.url instead of self.avatar:
info.context.build_absolute_uri(self.avatar.url)
So I got an answer to this and I want to make sure I post it someone else does not make the same mistake.
Here is what the code should look like
class ProfileType(DjangoObjectType):
class Meta:
model = Profile
avatar = graphene.String()
cover_photo = graphene.String()
def resolve_avatar(self, info):
return info.context.build_absolute_uri(self.avatar.url)
def resolve_cover_photo(self, info):
return info.context.build_absolute_uri(self.cover_photo.url)
When I upload a file through requests module it says no document submitted
models.py:
class Apidocument(models.Model):
iden = models.CharField(max_length=255)
document = models.FileField(upload_to='media/documents')
uploaded_at = models.DateTimeField(auto_now_add=True)
serializer.py:
class DataSerializer(serializers.ModelSerializer):
document = serializers.FileField(max_length=None,use_url =True)
class Meta():
model = Apidocument
fields = ('uploaded_at','document')
views.py:
class ApiViewSet(viewsets.ModelViewSet):
queryset = Apidocument.objects.all().order_by('-uploaded_at')
serializer_class = DataSerializer
files = {"file": ('b839', open('/home/user/b839.jpeg', 'rb'), 'multipart/form-data')}
resp = requests.post('http://localhost:8000/api/upload/', files=files)
Well, you are using a ModelSerializer and then defining a document field on the serializer, I think it's not required to specify document field on the serializer as ModelSerializer should include it anyways.
Also since you are using field name as document, it requires document key in the request associated with the file (at least that's how it is in xhr). So your requests object should look something like this:
files = {"document": ('b839', open('/home/user/b839.jpeg', 'rb'), 'multipart/form-data')}.
Hope this works.
I want to create entries in two tables (Log and Post) using the DRF Browseable API POST form.
The example below is contrived, but it outlines what I am trying to do.
class Post(models.Model):
info = models.CharField()
class Log(TimeStampedModel):
ip = models.GenericIPAddressField(('IP Address'))
name = models.CharField()
data = models.ForeignKey(Post)
I want to use the browseable API to submit a form to create a Log entry. Here are the serializers:
class PostSerializer(serializers.ModelSerializer):
class Meta:
model = Post
fields = ('info',)
class LogSerializer(serializers.ModelSerializer):
data = serializers.Field()
class Meta:
model = Log
fields = ('ip', 'name', 'data')
The problem with the above is that serializer.Field is read only so does not show up on the POST form. If I change it to CharField it shows up, but then I get an error because an instance of a Post is expected not just a field of the Post object.
Here are my views:
class LogMixin(object):
queryset = Log.objects.all()
serializer_class = LogSerializer
class LogList(LogMixin, ListCreateAPIView):
pass
class LogDetail(LogMixin, RetrieveUpdateDestroyAPIView):
pass
What's the correct way of doing this?
From what I can tell you want to create a nested Log object. There are 2 ways of doing this:
Send 2 POST Requests, One to create the Post, and the other to create the Log contained the received HTTP 200 data from the API.
(Django and best way) Send the data all in one POST and parse it server side. Django Rest Framework takes care of this for you.
I have changed your code so that it should work.
Source
class LogSerializer(serializers.ModelSerializer):
class Meta:
model = Log
fields = ('ip', 'name')
class PostSerializer(serializers.ModelSerializer):
log = LogSerializer()
class Meta:
model = Post
fields = ('info', 'log')
views.py
import generics
class PostCreateAPIView(generics.CreateAPIView):
model = Post
serializer_class = PostSerializer
Then you can send a POST Request containing 'info', 'ip', and 'name'.
This is a hacky way and the best way to use the nested serializer as stated above. But just to show another way I am posting it here.
# Add New Item
#api_view(('POST',))
def add_new_item(request):
request.data['areaname_name'] = request.data['item_areaname']
request.data['buildingname_name'] = request.data['item_buildingname']
item_serializer = TblItemSerializer(data=request.data)
area_name_serializer = TblAreanameSerializer(data=request.data)
building_name_serializer = TblBuildingnameSerializer(data=request.data)
response = []
if item_serializer.is_valid() & area_name_serializer.is_valid() & building_name_serializer.is_valid():
# Save To Item Table
item_serializer.save()
# Save Unique Values Into Areaname and Buildingname Tables
area_name_serializer.save()
building_name_serializer.save()
return Response(item_serializer.data, status=status.HTTP_201_CREATED)
else:
response.append(item_serializer.errors)
response.append(area_name_serializer.errors)
response.append(building_name_serializer.errors)
return Response(response, status=status.HTTP_400_BAD_REQUEST)
In the error response you could also use (depending on how you want to handle on client side)
merge = {**item_serializer.errors, **area_name_serializer.errors, **building_name_serializer.errors}
return Response(merge, status=status.HTTP_400_BAD_REQUEST)
I am trying to get GeoJSON response using django rest framework but facing issue
argument of type 'NoneType' is not iterable
This is my code
class NewPark(models.Model):
name = models.CharField(max_length=256)
geometry = models.GeometryField(srid=3857, null=True, blank=True)
objects = models.GeoManager()
class Meta:
db_table = u'new_park'
def __unicode__(self):
return '%s' % self.name
class NewParkSerializer(GeoFeatureModelSerializer):
class Meta:
model = NewPark
geo_field = "geometry"
fields = ('id', 'name', 'geometry')
class NewParkViewSet(viewsets.ModelViewSet):
def get_queryset(self):
queryset = NewPark.objects.all()
return queryset
When i change serialize type to 'erializers.GeoModelSerializer' then it is working, but i want GEOJSON response
I have searched about GeoFeatureModelSerializer but cannot find any example geo_field = "geometry". All example are about geo_field = "point"
Please help me to figure out this issue?
You might only have the above error in the browsable API, because the default djanog-rest-framework html template renderer does not work with the GeoJson format.
To test if that is the case, try to call your api endpoint requesting it in json format, i.e. /api/newpark.json or equivalently /api/newpark?format=json. This should show you geojson data, if it does your backend API is fine, and the problem is the browsable html form.
If you want a browsable API for your GeoJson endpoint, then you might need to change the html template used to render your API end point.