2

I'm struggling with recruitment task, i'm pretty new in Django and I haven't used rest framework before. I'm trying to built view where user can upload picture and set how long link should be valid(in range 3000-30000, validation works for that). This feature works thru postman instaed of received link to file I have following error:

    return renderer.render(serializer.data, None, {'style': style})
AttributeError: 'str' object has no attribute 'data'

When I try to upload file using website serializer is not passing validation.

I'm using render_form in html file and result in QueryDict is different than in postman so i guess thats the issue, however no idea how to solve it: using website:

'image_url': ['airplane.jpg'],

using postman:

 'image_url': [<InMemoryUploadedFile: airplane.jpg (image/jpeg)>]

models.py:

import datetime

from django.db import models
from django.contrib.auth.models import User
from images.validators import expiring_in_validator


def upload_to(instance, filename):
    unique_identify = str(int(datetime.datetime.now().timestamp()))
    return f"media/{filename}-{unique_identify}"

# Create your models here.
class Image(models.Model):
    uploaded_by = models.ForeignKey(User, on_delete=models.CASCADE)
    image_url = models.ImageField(upload_to=upload_to)
    expiring_within = models.IntegerField(validators=[expiring_in_validator])

serializers.py:

from rest_framework import serializers
from images.models import Image


class PostSerializer(serializers.ModelSerializer):
    class Meta:
        model = Image
        fields = ['image_url', 'expiring_within']

views.py:

from django.shortcuts import render
from django.views import View
from rest_framework import status
from rest_framework.parsers import FormParser, MultiPartParser
from rest_framework.permissions import IsAuthenticated
from rest_framework.response import Response
from rest_framework.views import APIView
from rest_framework.renderers import TemplateHTMLRenderer

from images.serializers import PostSerializer


# Create your views here.
class AddImage(APIView):
    renderer_classes = [TemplateHTMLRenderer]
    # permission_classes = [IsAuthenticated]
    template_name = "add_image.html"
    parser_classes = [MultiPartParser, FormParser]
    def get(self, request):
        serializer = PostSerializer()
        return Response({"serializer": serializer})

    def post(self, request):
        serializer = PostSerializer(data=request.data)
        if serializer.is_valid():
            serializer.save(uploaded_by=self.request.user)
            return Response(serializer.data, status=status.HTTP_200_OK)

html:

<form method="post">
{% csrf_token %}
        {% render_form serializer %}

    <input type="submit" value="Wyślij">
</form>

Forms works now but after uploading image instead of link I'm having following traceback:(

Traceback (most recent call last): File "/home/wojciech/PycharmProjects/thumbnail/virtual/lib/python3.10/site-packages/django/core/handlers/exception.py", line 56, in inner response = get_response(request) File "/home/wojciech/PycharmProjects/thumbnail/virtual/lib/python3.10/site-packages/django/core/handlers/base.py", line 220, in _get_response response = response.render() File "/home/wojciech/PycharmProjects/thumbnail/virtual/lib/python3.10/site-packages/django/template/response.py", line 114, in render self.content = self.rendered_content File "/home/wojciech/PycharmProjects/thumbnail/virtual/lib/python3.10/site-packages/rest_framework/response.py", line 70, in rendered_content ret = renderer.render(self.data, accepted_media_type, context) File "/home/wojciech/PycharmProjects/thumbnail/virtual/lib/python3.10/site-packages/rest_framework/renderers.py", line 166, in render return template.render(context, request=request) File "/home/wojciech/PycharmProjects/thumbnail/virtual/lib/python3.10/site-packages/django/template/backends/django.py", line 61, in render return self.template.render(context) File "/home/wojciech/PycharmProjects/thumbnail/virtual/lib/python3.10/site-packages/django/template/base.py", line 175, in render return self._render(context) File "/home/wojciech/PycharmProjects/thumbnail/virtual/lib/python3.10/site-packages/django/template/base.py", line 167, in _render return self.nodelist.render(context) File "/home/wojciech/PycharmProjects/thumbnail/virtual/lib/python3.10/site-packages/django/template/base.py", line 1005, in render return SafeString("".join([node.render_annotated(context) for node in self])) File "/home/wojciech/PycharmProjects/thumbnail/virtual/lib/python3.10/site-packages/django/template/base.py", line 1005, in return SafeString("".join([node.render_annotated(context) for node in self])) File "/home/wojciech/PycharmProjects/thumbnail/virtual/lib/python3.10/site-packages/django/template/base.py", line 966, in render_annotated return self.render(context) File "/home/wojciech/PycharmProjects/thumbnail/virtual/lib/python3.10/site-packages/django/template/library.py", line 237, in render output = self.func(*resolved_args, **resolved_kwargs) File "/home/wojciech/PycharmProjects/thumbnail/virtual/lib/python3.10/site-packages/rest_framework/templatetags/rest_framework.py", line 81, in render_form return renderer.render(serializer.data, None, {'style': style}) AttributeError: 'str' object has no attribute 'data' [08/Mar/2023 09:59:08] "POST /uploadimage/ HTTP/1.1" 500 115861

1 Answer 1

2

For the form, you need to add enctype information to bind the file to the form, like this:

<form method="post" enctype="multipart/form-data">
{% csrf_token %}
        {% render_form serializer %}

    <input type="submit" value="Wyślij">
</form>

For the actual problem regarding str object has no attribute data, DRF documentation mentions that:

Django rest framework looks for render_form template tag, to render Serializer.

The error is happening because in the html file it is looking for rendering the serializer using render_form tag. Since you are passing the serializer as serializer context variable, you need to send the serializer in post method like this:

   if serializer.is_valid():
        serializer.save(uploaded_by=self.request.user)
        return Response({"serializer":serializer})

If you do not want to render the form again, I suggest either redirect it to a different url where you get the same response in JSON format using JSONRenderer. If you intend to render in the response in HTML, then I would put another context variable, like this:

# view
if serializer.is_valid():
    serializer.save(uploaded_by=self.request.user)
    return Response({"serializer":serializer, "data": serializer.data})

# template
{% if data %}
    {{ data }}
{{ endif }}
<form method="post" enctype="multipart/form-data">
{% csrf_token %}
        {% render_form serializer %}

    <input type="submit" value="Wyślij">
</form>
Sign up to request clarification or add additional context in comments.

11 Comments

Thanks that works! Can you advise why Im getting ` return renderer.render(serializer.data, None, {'style': style}) AttributeError: 'str' object has no attribute 'data'` as return instead of link?
without the enctype, you would not get the file stream in the views, instead you will get a string, hence the error happened.
unfortunately enctype helped with uploading images from browser, but it returns error at the end. serializer.data = {'image_url': '/media/media/airplane.jpg-1678205283', 'expiring_within': 4444} but this line return Response(serializer.data, status=status.HTTP_200_OK) returns return renderer.render(serializer.data, None, {'style': style}) AttributeError: 'str' object has no attribute 'data'
@djangobeginner where do you use serializer.data = {'image_url': '/media/media/airplane.jpg-1678205283', 'expiring_within': 4444} ?
in ` def post(self, request): serializer = PostSerializer(data=request.data) if serializer.is_valid(): serializer.save(uploaded_by=self.request.user) return Response(serializer.data, status=status.HTTP_200_OK)`
|

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.