Home > Blockchain >  (django) 'utf-8' codec can't decode byte 0x89 in position 0: invalid start byte
(django) 'utf-8' codec can't decode byte 0x89 in position 0: invalid start byte

Time:05-28

I am now trying to assign two foreignkey onto the same custom user model, the username & profile image field. Custom User model:

class Account(AbstractBaseUser, PermissionsMixin):
    
    class Meta:
        verbose_name_plural = "Account List"

    email = models.EmailField(max_length=255, unique=True)
    username = models.CharField(max_length=255, unique=True)
    name = models.CharField(max_length=255, default="")
    profile_image = models.ImageField(max_length=255, upload_to=profile_image_path, blank=True, unique=True)
    about = models.TextField(max_length=255, default='Write something about yourself...', blank=True)
    start_date = models.DateTimeField(default=timezone.now)
    is_staff = models.BooleanField(default=False)
    is_superuser = models.BooleanField(default=False)
    is_active = models.BooleanField(default=True)
    last_login = models.DateTimeField(auto_now=True)

    objects = AccountManager()

    USERNAME_FIELD = "email"
    REQUIRED_FIELDS = ["username", "name"]

    def __str__(self):
        return self.username

Thread model:

class Thread(models.Model):

    options = (('active', 'Active'), ('deactivated', 'Deactivated'))

    username = models.ForeignKey(Account, on_delete=models.CASCADE, to_field='username', related_name='user')
    profile_image = models.ForeignKey(Account, on_delete=models.CASCADE, to_field='profile_image', related_name='profile')
    alt = models.TextField(max_length=255, blank=True)
    image = models.ImageField(max_length=255, upload_to=thread_image_path, default='images/family.png')
    content = models.TextField(blank=True)
    created = models.DateTimeField(default=timezone.now)
    status = models.CharField(max_length=11, choices=options, default='active')

However, whenever I try to create a Thread, I always encounter the error:

UnicodeDecodeError at /api/public/thread/
'utf-8' codec can't decode byte 0x89 in position 0: invalid start byte
Request Method: GET
Request URL:    http://127.0.0.1:8000/api/public/thread/
Django Version: 4.0.4
Exception Type: UnicodeDecodeError
Exception Value:    
'utf-8' codec can't decode byte 0x89 in position 0: invalid start byte
Exception Location: c:\Users\85291\Desktop\vscode\my-app\web\env\lib\site-packages\rest_framework\utils\encoders.py, line 50, in default

This error occurred right after I assign the foreignkey to the profile image, the serializer is unable to serialize the image to the API endpoint. I have tried going to encoders.py and change the encoder to utf16, but the problem remained.

Anyone has an idea what's wrong with my code? Much appreicated.

Update:

Custom User serializer.py

class UserSerializer(serializers.ModelSerializer):
    
    class Meta:
        model = Account
        fields = (
            'id',
            'email',
            'username',
            'name',
            'profile_image',
            'about',
            'start_date',
            'is_active',
            'last_login'
        )
        read_only_field = ('start_date',)

class RegisterSerializer(UserSerializer):
    
    password = serializers.CharField(max_length=128, min_length=8, required=True, write_only=True)
    email = serializers.EmailField(max_length=128, required=True, write_only=True)
    username = serializers.CharField(max_length=128, required=True)
    name = serializers.CharField(max_length=128, required=True)

    class Meta:
        model = Account
        fields = [
            'email',
            'username',
            'password',
            'name',
        ]
        extra_kwargs = {'password': {'wirte_only': True}}
        
    def create(self, validated_data):
        password = validated_data.pop('password', None)
        instance = self.Meta.model(**validated_data)
        
        if password is not None:
            instance.set_password(password)
            
        instance.save()
        
        return instance

class LoginSerialier(TokenObtainPairSerializer):
    
    def validate(self, attrs):
        
        data = super().validate(attrs)
        refresh = self.get_token(self.user)
        data['user'] = UserSerializer(self.user).data
        data['refresh'] = str(refresh)
        data['access'] = str(refresh.access_token)

        if api_settings.UPDATE_LAST_LOGIN:
            update_last_login(None, self.user)

        return data

Custom User serializer.py

class RegisterViewSet(viewsets.ModelViewSet):
    permission_classes = (AllowAny,)
    
    def create(self, request, format='json'):
        serializer = RegisterSerializer(data=request.data)
        
        if serializer.is_valid():
            user = serializer.save()
            
            if user:
                json = serializer.data
                
                return Response(json, status=status.HTTP_201_CREATED)
        
        return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
        
class LoginViewSet(viewsets.ModelViewSet, TokenObtainPairView):
    serializer_class = LoginSerialier
    permission_classes = (AllowAny,)
    
    def create(self, request, *args, **kwargs):
        serializer = self.get_serializer(data=request.data)
        
        try:
            serializer.is_valid(raise_exception=True)
            
        except TokenError as e:
            raise InvalidToken(e.args[0])
        
        return Response(serializer.validated_data, status=status.HTTP_200_OK)
    
class RefreshViewSet(viewsets.ViewSet, TokenRefreshView):
    permission_classes = (AllowAny,)

    def create(self, request, *args, **kwargs):
        serializer = self.get_serializer(data=request.data)

        try:
            serializer.is_valid(raise_exception=True)
            
        except TokenError as e:
            raise InvalidToken(e.args[0])

        return Response(serializer.validated_data, status=status.HTTP_200_OK)        

class UserViewSet(viewsets.ModelViewSet):
    queryset = Account.objects.none()
    serializer_class = UserSerializer 
    permission_classes = (IsAuthenticated,)
    
    def get_queryset(self): 
        return Account.objects.filter(id=self.request.user.id)
    
class BlacklistTokenView(viewsets.ModelViewSet):
    permission_classes = (AllowAny,)

    def post(self, request):
        try:
            refresh_token = request.data["refresh_token"]
            token = RefreshToken(refresh_token)
            token.blacklist()
            
            return Response(status=status.HTTP_205_RESET_CONTENT)
        
        except Exception as e:
            
            return Response(status=status.HTTP_400_BAD_REQUEST)

Thread serializer.py

class ThreadSerializer(serializers.ModelSerializer):

    created = serializers.DateTimeField(format="%d %B, %Y %H:%M:%S")

    class Meta:
        model = Thread
        fields = (
                  'id',
                  'username', 
                  'profile_image',
                  'alt', 
                  'image', 
                  'content', 
                  'created', 
                  'status')

Thread view.py

class ThreadView(generics.ListAPIView):
    permission_classes = (IsAuthenticated,)
    serializer_class = ThreadSerializer
    
    def get_queryset(self):
        username = self.request.user.username
        return Thread.objects.filter(username=username)
    
class ThreadViewSets(viewsets.ModelViewSet):
    permission_classes = (AllowAny,)
    serializer_class = ThreadSerializer
    queryset = Thread.objects.all()

CodePudding user response:

I think you can deal with the uploaded image.

class ThreadSerializer(serializers.ModelSerializer):
    created = serializers.DateTimeField(format="%d %B, %Y %H:%M:%S")
    uploaded_image = serializers.FileField(
        max_length = 1000000,
        allow_empty_file = False,
        write_only = True
    )
    profile_image = UserSerializer(read_only = True)

    class Meta:
        model = Thread
        fields = (
            ...,
            'uploaded_image',
        )
        extra_kwargs = {
            'image': { 'read_only': True }
        }

    
    def create(self, validated_data):
        image_data = validated_data.pop('uploaded_image')
        thread_obj = Thread(**validated_data)
        thread_obj.image = image_data
        thread_obj.save()
        return thread_obj

In frontend, you need to upload the image with the key uploaded_image.

  • Related