Как загрузить изображение в модель профиля пользователя, когда имеет отношение один к одному с моделью пользователя в django рамках остального? - PullRequest
0 голосов
/ 12 января 2020

У меня есть модель UserProfile, которая имеет отношение один к одному с моделью User.

Я столкнулся с проблемой при загрузке изображения с помощью конечной точки API остаточного каркаса во вложенную модель.

Проблема в следующем: Хотя я явно использую декоратор @action (), он также вызывает встроенный метод create () для сохранения изображения методом POST.

Затем я явно упомянул, какой метод вызывать в urls.py. Теперь он показывает ошибки.

Есть ошибки в реализации в serializer.py и views.py.

Поэтому, если возможно, пожалуйста, исправьте мои ошибки и направьте меня в правильное направление. Больше двух дней, но я все еще поражен.

В models.py :

def user_image_upload_file_path(instance, filename):
    """Generates file path for uploading user images"""
    extension = filename.split('.')[-1]
    file_name = f'{uuid.uuid4()}.{extension}'
    date = datetime.date.today()
    initial_path = f'pictures/uploads/user/{date.year}/{date.month}/{date.day}/'
    full_path = os.path.join(initial_path, file_name)

    return full_path

class UserManager(BaseUserManager):

    def create_user(self, email, password, username, **extra_kwargs):
        """Creates and saves a new user"""

        if not email:
            raise ValueError(_('Email cannot be empty'))

        user = self.model(email=self.normalize_email(email), **extra_kwargs)
        user.set_password(password)
        user.save(using=self._db)

        return user

    def create_superuser(self, email, password, username, **extra_kwargs):
        """Creates and saves a new user with superuser permission"""
        user = self.create_user(
            email, password, username, **extra_kwargs)
        user.is_staff = True
        user.is_superuser = True
        user.save(using=self._db)

        return user


class User(AbstractBaseUser, PermissionsMixin):
    """Creates user model that supports using email as username"""
    email = models.EmailField(_('Email'), max_length=255, unique=True)
    created_date = models.DateTimeField(
        _('Created Date'), default=timezone.now, editable=False)

    objects = UserManager()

    USERNAME_FIELD = 'email'

    def __str__(self):
        """String representation of user model"""
        return self.email


class UserProfile(models.Model, Languages):
    """Creates user profile model"""
    user = models.OneToOneField(
        'User',
        related_name='profile',
        on_delete=models.CASCADE
    )
    first_name = models.CharField(
        _('First Name'), max_length=255, blank=True)
    last_name = models.CharField(
        _('Last Name'), max_length=255, blank=True)
    image = models.ImageField(
        _('Image'),
        upload_to=user_image_upload_file_path,
        null=True,
        blank=True,
        max_length=1024
    )


@receiver(post_save, sender=User)
def user_is_created(sender, instance, created, **kwargs):
    if created:
        UserProfile.objects.create(user=instance)
    else:
        instance.profile.save()

В serializer.py :

class UserSerializer(serializers.ModelSerializer):
    """Minimal serializer for supporting user image upload field"""

    class Meta:
        model = get_user_model()
        fields = ('username', )


class UserImageUploadSerializer(serializers.ModelSerializer):
    """Serializer for user profile"""
    user = UserSerializer(read_only=True)

    class Meta:
        model = UserProfile
        fields = ('id', 'user', 'image', )
        read_only_fields = ('id', 'user', )

В views.py :

class UserImageUploadView(viewsets.ModelViewSet):
    serializer_class = serializer.UserImageUploadSerializer
    authentication_classes = [authentication.TokenAuthentication, ]
    permission_classes = [permissions.IsAuthenticated, ]
    queryset = get_user_model().objects.all()

    def get_queryset(self):
        """Return object for only authenticated user"""
        return self.queryset.filter(id=self.request.user)


    @action(detail=True, methods=['POST'], url_path='user-upload-image')
    def image_upload(self, pk=None):
        """Save the uploaded picture and profile data"""
        user = self.get_object()
        profile = user.profile
        data = {'user': user, 'id': profile.pk, 'data': request.data}
        serializer_ = serializer.UserImageUploadSerializer(data=data)

        if serializer_.is_valid():
            serializer_.save()
            return Response(serializer_.data, status=status.HTTP_200_OK)
        else:
            return Response(serializer_.errors, status=status.HTTP_400_BAD_REQUEST)

В urls.py :

urlpatterns = [
    path('<int:pk>/upload-image/', views.UserImageUploadView.as_view(
        {'get': 'list', 'post': 'image_upload', }), name='user-image-upload')
]

1 Ответ

0 голосов
/ 13 января 2020

Чтобы выполнить эту задачу, я вручную создал функцию сохранения изображения с помощью APIView.

Пожалуйста, обновите, если существует эффективный код

В моих URL. py file:

urlpatterns = [
    path('upload-image/', views.UserImageUploadView.as_view(), name='user-image-upload'),
]

In views.py :

from rest_framework.parsers import FormParser, MultiPartParser, JSONParser
from rest_framework.views import APIView

from . import serializer
from core import models

class UserImageUploadView(APIView):
    """View to upload or view image for user"""
    serializer_class = serializer.TempSerializer
    authentication_classes = [authentication.TokenAuthentication, ]
    permission_classes = [permissions.IsAuthenticated, ]
    parser_classes = [JSONParser, MultiPartParser]

    def get(self, request, format=None):
        """To get user profile picture"""
        user = get_user_model().objects.get(email=request.user)
        user_profile = models.UserProfile.objects.get(user=user)

        # Preparing the data manually as per our serializer
        data = {'user': {'username': user.username},
                'image': user_profile.image or None}

        # Serializing our prepared data
        ser = serializer.TempSerializer(
            user_profile, data=data, context={"request": request})

        # Returning appropriate response
        if ser.is_valid():
            return_ser_data = {'id': ser.data.get('id'),
                               'image': ser.data.get('image')}
            return Response(return_ser_data, status=status.HTTP_200_OK)
        else:
            return Response(ser.errors, status=status.HTTP_400_BAD_REQUEST)

    def post(self, request, format=None):
        """To save the profile picture"""
        user = get_user_model().objects.get(email=request.user)
        user_profile = models.UserProfile.objects.get(user=user)

        # Formatting the data to as per our defined serializer
        data = {'user': {'username': user.username},
                'image': request.data.get('image')}

        # Serializing our data
        ser = serializer.TempSerializer(
            user_profile, data=data, context={"request": request})

        if ser.is_valid():
            if ser.validated_data:
                # Deleting the old image before uploading new image
                if user_profile.image:
                    user_profile.image.delete()

                # Saving the model
                ser.save(user=user)
            return_ser_data = {'id': ser.data.get('id'),
                               'image': ser.data.get('image')}
            return Response(return_ser_data, status=status.HTTP_200_OK)
        else:
            return Response(ser.errors, status=status.HTTP_400_BAD_REQUEST)

In serializer.py :

class UserSerializer(serializers.ModelSerializer):
    """Minimal serializer for supporting user image upload field"""

    class Meta:
        model = get_user_model()
        fields = ('username', )

class TempSerializer(serializers.ModelSerializer):
    """Serializer for user image upload"""
    user = UserSerializer(read_only=True)
    image = serializers.ImageField(allow_null=True, use_url=True)

    class Meta:
        model = UserProfile
        fields = ('id', 'user', 'image')
        read_only_fields = ('id', 'user')
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...