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
.