DRF: передать пользователя как внешний ключ для профиля

#python #django-models #django-rest-framework

#python #django-модели #django-rest-framework

Вопрос:

Я новичок в Django. Я пытаюсь создать зарегистрированного пользователя с созданным профилем по умолчанию. Но я получаю имя пользователя, уже существующее исключение

 {
  "owner": {
    "username": [
      "A user with that username already exists."
    ]
  }
}
  

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

Вот как выглядят мои модели :

 from django.db import models
from django.contrib.auth.models import User

class Profile(models.Model):
    name = models.CharField(max_length=255, null=False)
    birth_date = models.DateTimeField(auto_now=False, blank=True)
    owner = models.ForeignKey(User, on_delete=models.CASCADE)

    def __str__(self):
        return "{} {}".format(self.name)
  

Сериализатор для создания пользователя и профиля, как показано ниже

 from django.contrib.auth import get_user_model
from rest_framework import serializers
from .models import Profile
from django.contrib.auth.models import User

User = get_user_model()

class UserCreateSerializer(serializers.ModelSerializer):
    password = serializers.CharField(write_only=True, required=True, style={
                                     "input_type":   "password"})
    password2 = serializers.CharField(
        style={"input_type": "password"}, write_only=True, label="Confirm password")

    class Meta:
        model = User
        fields = [
            "username",
            "email",
            "password",
            "password2",
        ]
        extra_kwargs = {"password": {"write_only": True}}

    def create(self, validated_data):
        username = validated_data["username"]
        email = validated_data["email"]
        password = validated_data["password"]
        password2 = validated_data["password2"]
        first_name = validated_data["first_name"]
        last_name = validated_data["last_name"]

        if email and User.objects.filter(email=email).exclude(username=username).exists():
            raise serializers.ValidationError(
                {"email": "Email addresses must be unique."})
        if password != password2:
            raise serializers.ValidationError(
                {"password": "The two passwords differ."})
        user = User(username=username, email=email, first_name=first_name, last_name=last_name)
        user.set_password(password)
        user.save()
        return user


class ProfileSerializer(serializers.ModelSerializer):
    owner = UserCreateSerializer()

    class Meta:
        model = Profile
        fields = '__all__'

    def create(self, validated_data):
        user_data = validated_data.pop('owner')
        user = User.objects.get(username=user_data.username)
        profile = Profile.objects.create(owner=user, **validated_data)

        return profile
  

Это мой взгляд на регистрацию

 @swagger_auto_schema(methods=[ 'post'], request_body=ProfileSerializer)
@decorators.api_view(["POST"])
@decorators.permission_classes([permissions.AllowAny])
def registration(request):
    user_data = request.data['owner']
    serializer = UserCreateSerializer(data=user_data)
    if not serializer.is_valid():
        return response.Response(serializer.errors, status.HTTP_400_BAD_REQUEST)
    user = serializer.save()
    profile_data = request.data
    profile_data.pop('owner')
    profile_data['owner'] = user_data
    profile_serializer = ProfileSerializer(data=profile_data, partial=True)
    if not profile_serializer.is_valid():
        return response.Response(profile_serializer.errors, status.HTTP_400_BAD_REQUEST)
    profile = profile_serializer.save()
    refresh = RefreshToken.for_user(profile.owner)
    res = {
        "refresh": str(refresh),
        "access": str(refresh.access_token),
    }
    return response.Response(res, status.HTTP_201_CREATED)
  

Это выдает мне ошибку при проверке profile_data.

Есть ли у кого-нибудь идеи, как я могу передать объект user в profile_serializer, чтобы я мог использовать тот же метод create в следующий раз, когда пользователь захочет создать новый профиль?

Ответ №1:

Измените что-то подобное в своем serializers.py файле.

 from rest_framework import serializers
from django.contrib.auth import get_user_model
from django.db.models import Q

User = get_user_model()

class UserCreateSerializer(serializers.ModelSerializer):
    email = serializers.EmailField(label='Email')
    username = serializers.CharField(label='Userame')
    password = serializers.CharField(write_only=True, required=True, style={
                                     "input_type": "password"})
    password2 = serializers.CharField(
        style={"input_type": "password"}, write_only=True, label="Confirm password")

    class Meta:
        model = User
        fields = [
            "username",
            "email",
            "password",
            "password2",
        ]
        extra_kwargs = {"password": {"write_only": True}}



    def create(self, data):
        username = data['username']
        email = data['email']
        password = data['password']
        password2 = data['password2']
        user_queryset = User.objects.filter(Q(email__iexact=email) | Q(username__iexact=username)).first()
        password = data.pop('password', None)
        instance = self.Meta.model(**data)

        if password != password2:
            raise serializers.ValidationError({"password": "The two passwords differ."})

        if user_queryset == None:
            if password is not None:
                instance.set_password(password)
            instance.save()

            return instance

        else:
            raise serializers.ValidationError("User Already Exists!")
  

Комментарии:

1. получение ошибки TypeError: User() получил неожиданный аргумент ключевого слова ‘password2’ ошибка

2. Все еще возникает та же проблема. Кстати, я могу это решить. Мне нужно удалить ‘UniqueValidator’ из поля имени пользователя.

3. похоже, у вашего User нет поля с именем password2