I am trying to upload both text data and a file to django server using angular for the front-end,
here is my models in django
#models.py
class UploadChapter(models.Model):
chapter_number = models.CharField(max_length=50, choices=chapters)
chapter_file = models.FileField(upload_to="files")
student = models.ForeignKey(User,on_delete=models.CASCADE)
supervisor = models.ForeignKey(Supervisor, on_delete=models.CASCADE)
status = models.CharField(max_length=100, choices=status, default="Pending")
def __str__(self):
return f'{self.student} - {self.chapter_number}'
for the serializer I wrote this code
#serializers.py
class UploadChapterSerializer(serializers.ModelSerializer):
class Meta:
model = UploadChapter
fields = ['chapter_number', 'chapter_file', 'student', 'supervisor', 'status']
and for the views i wrote this code
#views.py
#csrf_exempt
def ChapterApi(request, id=0):
if request.method=='GET':
chapters=UploadChapter.objects.all()
chaptersSerializer=UploadChapterSerializer(chapters, many=True)
return JsonResponse(chaptersSerializer.data, safe=False)
elif request.method=='POST':
chaptersData=JSONParser().parse(request)
chaptersSerializer=UploadChapterSerializer(data=chaptersData)
if chaptersSerializer.is_valid():
chaptersSerializer.save()
return JsonResponse('Added Successfully', safe=False)
return JsonResponse('Failed', safe=False)
so am getting errors from the JSONParser and I really dont know how to do this, I need help please
I found an answer for myself, i wrote a class-based view instead of the function based, here is the code for it
class ChapterView(APIView):
parser_classes = (MultiPartParser, FormParser)
def post(self, request, *args, **kwargs):
chapter_serializer = UploadChapterSerializer(data=request.data)
if chapter_serializer.is_valid():
chapter_serializer.save()
return JsonResponse('Chapter Sent Successfully', safe=False)
else:
return JsonResponse('upload fail', safe=False)
def get(self, request):
chapter = UploadChapter.objects.all()
chapterSerializer = UploadChapterSerializer(chapter, many=True)
return JsonResponse(chapterSerializer.data, safe=False)
Related
My problem in GIF
Instead of updating the user's rating DRF creating new.
Maybe i made a mistake in serializer?
I wrote documentation but i dont kwon where i wrong.
My code:
views.py:
class CreateReviewView(APIView):
def post(self, request):
review = CreateReviewSerializer(data= request.data)
if review.is_valid():
review.save()
return Response(status=201)
class CreateRatingView(APIView):
def get_user(self, request):
user= request.user
if user =="AnonymousUser":
return "noname in CreateRaringView"
return user
def post(self, request):
serializer = CreateRatingSerializer(data=request.data)
if serializer.is_valid(raise_exception=True):
serializer.save(user=self.get_user(request))
return Response(status=201)
else:
return Response(status=400)
serializers.py:
class Meta:
model = Rating
fields = ('star','movie')
def new(self,validated_data):
rating = Rating.objects.update_or_create(
user= validated_data.get('user',None),
movie= validated_data.get('movie',None),
defaults={'start': validated_data.get("star")}
)
return rating
models.py:
class Rating(models.Model):
"""Рейтинг"""
user = models.ForeignKey(User,on_delete=models.CASCADE,verbose_name="Пользователь",related_name='user')
star = models.ForeignKey(RatingStar, on_delete=models.CASCADE, verbose_name="Звезда",related_name="star")
movie = models.ForeignKey(Movie, on_delete=models.CASCADE, verbose_name="Фильм",related_name="movie")
def __str__(self):
return f"{self.star} - {self.movie}"
class Meta:
#unique_together = ['user','movie','star']
verbose_name = "Рейтинг"
verbose_name_plural = "Рейтинги"
According to documentation, Calling .save() will either create a new instance, or update an existing instance, depending on if an existing instance was passed when instantiating the serializer class:
# .save() will create a new instance.
serializer = CommentSerializer(data=data)
# .save() will update the existing `comment` instance.
serializer = CommentSerializer(comment, data=data)
In your case you are only passing new data and missing existing instance.
def post(self, request):
serializer = CreateRatingSerializer(data=request.data)
I renamed def new(self,validated_data): to def create(self,validated_data): in serializers.py and all started working. >.<
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)
I am trying to update my data in 'VoterList' model by using PUT api, but i don't know which function should i use in my 'views.py' file to handle the coming PUT request because in PUT api, we use parameters from URL to pick the relevent entry from model for updation and then update it by using data received from PUT api.
model.py
class VoterList(models.Model):
# id = models.IntegerField(auto_created= True, primary_key=True)
name = models.CharField( max_length=20)
email = models.EmailField()
mobile = models.IntegerField()
city = models.CharField( max_length=20)
type = models.CharField(max_length=20)
def __str__(self):
return self.name
serializers.py
class FillVoterListSerializers(serializers.HyperlinkedModelSerializer):
class Meta:
model = VoterList
fields = ('id','name', 'email', 'mobile', 'city', 'type')
def update(self, instance, validated_data):
instance.name = validated_data.pop("name", instance.name)
instance.email = validated_data.pop("email", instance.email)
instance.save()
return instance
I will manage the code for PUT in serializers by myself.
views.py
class UpdateVoter(APIView):
serializer_class = FillVoterListSerializers
permission_classes = (AllowAny,)
def post(self, request,*args,**kwargs):
isDataExist = VoterList.objects.get(id=request.data.get('id'))
if not isDataExist:
return Response({"message":"No Voter exist with this id."})
else:
isDataUpdated = self.serializer_class(isDataExist, request.data, partial=True)
if isDataUpdated.is_valid():
isDataUpdated.save()
return Response({"message": "Voter updated."})
else:
return Response({"message": "All fields are Mandatory."})
urls.py
urlpatterns = [
url('api/updateVoter/(?P<id>[0-9]+)/$', UpdateVoter.as_view(), name= "updateVoter")]
So what code should i write in my view.py to handle the PUT request.
Note: I want to tell you that i am preparing api for mobile applications, so please respond accordingly.
Any help is appreciated.
You can use the put() function in your view similar to the post() which you've used
def put(self, request, pk, format=None):
# Your code here
Refer the DRF docs : https://www.django-rest-framework.org/tutorial/3-class-based-views/
This is how I create my article
`class CreateArticleView(ListCreateAPIView):
"""
Class handles creating of articles
"""
permission_classes = (IsAuthenticatedOrReadOnly,)
serializer_class = ArticleSerializer
renderer_classes = (ArticleJSONRenderer,)
queryset = Article.objects.all()
def list(self, request, *args, **kwargs):
queryset = Article.objects.all()
serializer = self.serializer_class(queryset, many=True)
return Response(serializer.data)
def post(self, request, *args, **kwargs):
article = request.data.get('article', {})
if self.request.user.is_verified is False:
message = error_messages['email_verification']
return Response(message, status=status.HTTP_401_UNAUTHORIZED)
context = {"request": request}
serializer = self.serializer_class(data=article, context=context)
serializer.is_valid(raise_exception=True)
serializer.save(author=request.user)
return Response(serializer.data, status=status.HTTP_201_CREATED)`
`
This is how I get to view a single article, therefore I would like to fetch a single article and be able to highlight several parts of the article and manage to comment on them
class GetUpdateDeleteArticle(RetrieveUpdateDestroyAPIView):
permission_classes = (IsAuthenticated,)
renderer_classes = (ArticleJSONRenderer,)
queryset = Article.objects.all()
serializer_class = ArticleSerializer
lookup_field = 'slug'
#staticmethod
def validate_author(request, article):
if request.user.pk != article.author_id:
message = error_messages['unauthorised']
return Response(message, status.HTTP_403_FORBIDDEN)
def get(self, request, *args, **kwargs):
"""
:param request: user requests to get an article
:param kwargs: slug field is passed in the url
:return: data and response if article exists
"""
try:
article = Article.objects.get(slug=kwargs['slug'])
except Article.DoesNotExist:
message = error_messages['article_404']
return Response(message, status=status.HTTP_404_NOT_FOUND)
serializer = ArticleSerializer(
instance=article, context={'request': request})
return Response(serializer.data, status=status.HTTP_200_OK)
This is more of a design decision in the model level and less of an API issue. I would go with the following DB design:
A model Highlight that stores a reference to the article, the begining index of the highlighted part of the text and the ending index. So, something roughly like this:
class Highlight(models.Model):
article = models.ForeignKey(Article, related_name='highlights')
start = models.PositiveIntegerField()
end = models.PositiveIntegerField()
Then a Comment model. A common design is to use generic relations so that comments can be used with any model in your application. Something like this should suffice:
class Comment(TimeStampedModel):
text = models.TextField(blank=False)
author = models.ForeignKey(User, related_name='comments')
content_type = models.ForeignKey(ContentType)
object_id = models.PositiveIntegerField()
content_object = GenericForeignKey('content_type', 'object_id')
You can now build an API around this design where clients create highlights by sending the article id, start and end indices of the highlighted text. Comments can also be created using the highlight's id. Retrieving the highlights for an article should also be fairly easy to implement.
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')