具有客户用户模型的DRF多用户

2024-06-01 08:35:17 发布

您现在位置:Python中文网/ 问答频道 /正文

我正在实现一个自定义用户模型,该模型具有用户和托儿所帐户。注册正在进行,但登录没有按照我预期的方式进行。此外,令牌身份验证也不起作用 我想我的观点有点不对劲,但我没办法弄明白。我在登录时遇到此错误:

AttributeError at /api/auth/login/user

Got AttributeError when attempting to get a value for field `account` on serializer `UserSerializer`.
The serializer field might be named incorrectly and not match any attribute or key on the `Account` instance.
Original exception text was: 'Account' object has no attribute 'account'.

这是我的模特

class AccountManager(BaseUserManager):

    def create_user(self, username, email, contact, password=None):
        """Create and return a `User` with an email, username and password."""
        if username is None:
            raise TypeError('Users must have a username.')

        if email is None:
            raise TypeError('Users must have an email address.')

        user = self.model(username=username,
                          email=self.normalize_email(email), contact=contact)
        user.set_password(password)
        user.save()

        return user

    def create_superuser(self, username, email, contact, password):
        """
        Create and return a `User` with superuser (admin) permissions.
        """
        if password is None:
            raise TypeError('Superusers must have a password.')

        user = self.create_user(username, email, contact, password)
        user.is_superuser = True
        user.is_staff = True
        user.save()

        return user

    def get_by_natural_key(self, email):
        return self.get(email=email)


class Account(AbstractBaseUser, PermissionsMixin):
    email = models.EmailField(verbose_name="email", max_length=60, unique=True)
    username = models.CharField(max_length=30, unique=True)
    contact = models.CharField(max_length=10, unique=True, default=False)
    is_active = models.BooleanField(default=True)
    is_staff = models.BooleanField(default=False)
    is_superuser = models.BooleanField(default=False)
    is_nursery = models.BooleanField(default=False)
    is_user = models.BooleanField(default=False)

    created_at = models.DateTimeField(auto_now_add=True)
    updated_at = models.DateTimeField(auto_now=True)

    USERNAME_FIELD = 'email'
    REQUIRED_FIELDS = ['username', 'contact']

    objects = AccountManager()

    def get_username(self):
        return (self.username)

    def __str__(self):
        return self.email


class User(Account, models.Model):
    account = models.OneToOneField(
        Account, on_delete=models.CASCADE, primary_key=True)
    full_name = models.CharField(max_length=30)
    address = models.CharField(max_length=256)


class Nursery(Account, models.Model):
    account = models.OneToOneField(
        Account, on_delete=models.CASCADE, primary_key=True)
    nursery_name = models.CharField(max_length=30)


序列化程序.py

class AccountSerializer(serializers.ModelSerializer):
    class Meta:
        model = Account
        fields = ['email', 'username', 'contact', 'password']
        extra_kwargs = {'password': {'write_only': True}}


class UserSerializer(serializers.ModelSerializer):
    account = AccountSerializer(many=False)

    class Meta:
        model = User
        fields = ['account', 'full_name', 'address']

    def create(self, validated_data):
        account_data = validated_data.pop('account')
        user = User.objects.create(**validated_data)
        Account.objects.create(user=user, **account_data)
        return user


class NurserySerializer(serializers.ModelSerializer):
    account = AccountSerializer(many=False)

    class Meta:
        model = Nursery
        fields = ['account', 'nursery_name']

    def create(self, validated_data):
        account_data = validated_data.pop('account')
        nursery = Nursery.objects.create(**validated_data)
        Account.objects.create(nursery=nursery, **account_data)
        return nursery


class UserLoginSerializer(serializers.Serializer):
    email = serializers.CharField()
    password = serializers.CharField()

    def validate(self, data):
        account = authenticate(**data)
        if account and account.is_active:
            return account
        raise serializers.ValidationError("Incorrect Credentials")


class NurseryLoginSerializer(serializers.Serializer):
    email = serializers.CharField()
    password = serializers.CharField()

    def validate(self, data):
        account = authenticate(**data)
        if account and account.is_active:
            return account
        raise serializers.ValidationError("Incorrect Credentials")

views.py

from rest_framework import generics, permissions
from rest_framework.response import Response
from .serliaziers import UserSerializer, NurserySerializer, UserLoginSerializer, NurseryLoginSerializer, AccountSerializer


class RegisterUserAPI(generics.GenericAPIView):
    serializer_class = UserSerializer

    def post(self, request, *args, **kwargs):
        serializer = self.get_serializer(data=request.data)
        serializer.is_valid(raise_exception=True)
        user = serializer.save()
        return Response({
            "user": UserSerializer(user, context=self.get_serializer_context()).data,

        })


class RegisterNurseryAPI(generics.GenericAPIView):
    serializer_class = NurserySerializer

    def post(self, request, *args, **kwargs):
        serializer = self.get_serializer(data=request.data)
        serializer.is_valid(raise_exception=True)

        nursery = serializer.save()
        return Response({
            "nursery": NurserySerializer(nursery, context=self.get_serializer_context()).data,
        })


class LoginUserAPI(generics.GenericAPIView):
    serializer_class = UserLoginSerializer

    def post(self, request, *args, **kwargs):
        serializer = self.get_serializer(data=request.data)
        serializer.is_valid(raise_exception=True)
        account = serializer.validated_data
        return Response({
            "user": UserSerializer(account, context=self.get_serializer_context()).data,

        })


class LoginNurseryAPI(generics.GenericAPIView):
    serializer_class = NurseryLoginSerializer

    def post(self, request, *args, **kwargs):
        serializer = self.get_serializer(data=request.data)
        serializer.is_valid(raise_exception=True)
        nursery = serializer.validated_data
        return Response({
            "user": NurserySerializer(nursery, context=self.get_serializer_context()).data,

        })

url.py

from django.urls import path, include

from .api import RegisterUserAPI, RegisterNurseryAPI, LoginNurseryAPI, LoginUserAPI

urlpatterns = [
    path('api/auth/register/user', RegisterUserAPI.as_view()),
    path('api/auth/register/nursery', RegisterNurseryAPI.as_view()),
    path('api/auth/login/nursery', LoginNurseryAPI.as_view()),
    path('api/auth/login/user', LoginUserAPI.as_view())
]


Tags: selftruedatagetreturnismodelsemail
1条回答
网友
1楼 · 发布于 2024-06-01 08:35:17

试试这样的

class UserLoginView(ObtainAuthToken):
    def post(self, request, **kwargs):
        serializer = self.serializer_class(data=request.data,
        context={
            'request':request
        })
        serializer.is_valid(raise_exception=True)
        user = serializer.validated_data['user']
        token, created = Token.objects.get_or_create(user=user)
        return Response(
            {
                'token':token.key,
                'username':user.username,
            }
        )

UserLoginView继承自GetainAuthToken,它在项目中查找AUTH_USER_模型,并根据您在其中指定的用户模型请求所需参数以登录该用户

我希望这有帮助

编辑

要在注册用户时获取令牌,可以执行以下操作:

@api_view(['POST'])
@permission_classes((AllowAny,))
def api_user_registration_view(request):
    if request.method == 'POST':
        serializer = UserRegistrationSerializer(data=request.data)
        data = {

        }
        if serializer.is_valid():
            user = serializer.save()
            data['response'] = 'New user registration succesful.'
            data['email'] = user.email
            data['username'] = user.username
            token = Token.objects.get(user=user).key
            data['token'] = token
        else:
            data = serializer.errors
        return Response(data)

在您向api发出请求并成功响应之后,您向登录端点发出另一个请求

相关问题 更多 >