0

描述

我正在尝试为具有不同类型用户(司机、客户、系统管理员和授权人)的交通系统构建一个 API。为此,我AbstractUser为上述所有不同的用户创建了一个并使用继承关系。为了将 JWT 添加到模型中,我已经阅读了官方教程,但是每当我想创建一个像下面这样的新用户时,我都会遇到错误:

mutation {
  register(
    email: "new_user@email.com",
    username: "new_user",
    password1: "supersecretpassword",
    password2: "supersecretpassword",
  ) {
    success,
    errors,
    token,
    refreshToken
  }
}

重现步骤

  1. 这是我的模型:
from django.db import models
from django.contrib.auth.models import AbstractUser


# Create your models here.
class Usermodel(AbstractUser, models.Model):
    phone_no = models.CharField(
        max_length=11,
        blank=True,
        verbose_name="Phone Number"
    )

    USERNAME_FIELD = "username"   # e.g: "username", "email"
    EMAIL_FIELD = "email"         # e.g: "email", "primary_email"
    
    def __str__(self):
        return self.username

    
class Driver(Usermodel, models.Model):
    national_id = models.CharField(
        max_length=10, 
        blank=True, 
        verbose_name="National ID"
    )

    profile_picture = models.ImageField(
        blank=True,
        null=True
    )

    STATUS_CHOICES = [
        ('1', 'Free'),
        ('2', 'Busy')
    ]

    driver_status = models.CharField(
        max_length=1,
        choices=STATUS_CHOICES
    )

    rating = models.FloatField(
        default=-1
    )

    ranking = models.IntegerField(
        default=-1
    )

    class Meta:
        verbose_name = 'Driver'
        verbose_name_plural = 'Drivers'

class Authorizer(Usermodel, models.Model):
    class Meta:
        verbose_name = 'Authorizer'
        verbose_name_plural = 'Authorizers'

class Customer(Usermodel, models.Model):
    class Meta:
        verbose_name = 'Customer'
        verbose_name_plural = 'Customers'

class Administrator(Usermodel, models.Model):
    class Meta:
        verbose_name='Adminsitrator'
        verbose_name_plural='Administrators'
  1. 用户架构
import graphene
from graphene import Mutation, ObjectType, InputObjectType
from .models import Driver, Authorizer, Customer, Administrator
from graphene_django.types import DjangoObjectType


class DriverType(DjangoObjectType):
    class Meta:
        model = Driver

class AuthorizerType(DjangoObjectType):
    class Meta:
        model = Authorizer

class Query(ObjectType):
    driver = graphene.Field(
        DriverType,
        id = graphene.ID()
    )

    authorizer = graphene.Field(
        AuthorizerType,
        id = graphene.ID()
    )

    all_drivers = graphene.List(DriverType)
    all_authorizers = graphene.List(AuthorizerType)

    def resolve_all_drivers(self, info, **kwargs):
        return Driver.objects.all()

    def resolve_driver(self, info, **kwargs):
        id = kwargs.get('id')
        if id is not None:
            return Driver.objects.get(pk=id)

    def resolve_authorizer(self, info, **kwargs):
        id = kwargs.get('id')
        if id is not None:
            return Driver.objects.get(pk=id)

    def resolve_all_authorizers(self, info, **kwargs):
        return Authorizer.objects.all()


class DriverInput(InputObjectType):
    first_name = graphene.String()
    last_name = graphene.String()
    email = graphene.String()
    username = graphene.String()
    phone_no = graphene.String()
    national_id = graphene.String()
    password = graphene.String()


class AuthorizerInput(InputObjectType):
    first_name = graphene.String()
    last_name = graphene.String()
    email = graphene.String()
    username = graphene.String()
    phone_no = graphene.String()
    password = graphene.String()
class CreateDriver(Mutation):
    class Arguments:
        driver_data = DriverInput()
        
    driver = graphene.Field(DriverType)

    def mutate(self, info, driver_data=None):
        driver = Driver(
            first_name=driver_data.first_name,
            last_name=driver_data.last_name,
            email=driver_data.email,
            username=driver_data.username,
            phone_no=driver_data.phone_no,
            national_id=driver_data.national_id,
            password=driver_data.password
        )

        driver.save()

        return CreateDriver(
            driver=driver
        )

class UpdateDriver(Mutation):
    class Arguments:
        id = graphene.ID()
        driver_data = DriverInput()
    
    driver = graphene.Field(DriverType)

    def mutate(self, info, id, driver_data=None):
        #TODO: Error handling if the id not exists
        driver = Driver.objects.get(pk=id)

        driver.first_name = driver_data.first_name
        driver.last_name = driver_data.last_name
        driver.email = driver_data.email
        driver.username = driver_data.username
        driver.phone_no = driver_data.phone_no
        driver.national_id = driver_data.national_id
        driver.password = driver_data.password
        driver.save()

        return UpdateDriver(driver=driver)


class AuthorizerInput(InputObjectType):
    first_name = graphene.String()
    last_name = graphene.String()
    email = graphene.String()
    username = graphene.String()
    phone_no = graphene.String()
    password = graphene.String()

class CreateAuthorizer(Mutation):
    class Arguments:
        authorizer_data = AuthorizerInput()

    authorizer = graphene.Field(AuthorizerInput)

    def mutate(self, info, authorizer_data=None):
        authorizer = Authorizer(
            firstname=authorizer_data.first_name,
            last_name=authorizer_data.last_name,
            email=authorizer_data.email,
            username=authorizer_data.username,
            phone_no=authorizer_data.phone_no,
            password=authorizer_data.password
        )
        authorizer.save()
        return CreateAuthorizer(authorizer=authorizer)

class UpdateAuthorizer(Mutation):
    class Arguments:
        id = graphene.ID()
        authorizer_data = AuthorizerInput()
    
    authorizer = graphene.Field(AuthorizerType)
    
    def mutate(self, info, id, authorizer_data=None):
        authorizer = Authorizer.objects.get(pk=id)
        authorizer.first_name = authorizer_data.first_name
        authorizer.last_name = authorizer_data.last_name
        authorizer.email = authorizer_data.email
        authorizer.username = authorizer_data.username
        authorizer.password = authorizer_data.password
        authorizer.save()

        return UpdateDriver(authorizer=authorizer)

class Mutations(ObjectType):
    create_driver = CreateDriver.Field()
    update_driver = UpdateDriver.Field()

  1. 项目架构
import graphene

from apps.users.schema import Query as user_query
from apps.users.schema import Mutations as user_mutation
from graphql_auth.schema import UserQuery, MeQuery
from graphql_auth import mutations

class AuthMutation(graphene.ObjectType):
   register = mutations.Register.Field()


class Query(user_query, UserQuery, MeQuery):
    pass

class Mutations(user_mutation, AuthMutation):
    pass    

schema = graphene.Schema(
    query=Query,
    mutation=Mutations
)

预期行为

我希望代码可以毫无问题地运行,但会遇到以下错误actual behavior

我还有另一个问题。正如我已经解释了各种用户和他们的注册,我需要不同的论点。但是在我们刚刚添加的模式中register = mutations.Register.Field(),我怎样才能达到这个目的?

实际行为

错误描述

要求

aniso8601==7.0.0
asgiref==3.2.10
Django==3.0.8
django-filter==2.3.0
django-graphql-auth==0.3.11
django-graphql-jwt==0.3.0
graphene==2.1.8
graphene-django==2.12.1
graphql-core==2.3.2
graphql-relay==2.0.1
Pillow==7.2.0
pkg-resources==0.0.0
promise==2.3
PyJWT==1.7.1
pytz==2020.1
Rx==1.6.1
singledispatch==3.4.0.3
six==1.15.0
sqlparse==0.3.1
Unidecode==1.1.1
4

1 回答 1

1

问题1:我希望代码运行没有任何问题,但在实际行为中会遇到以下错误

注意如果不查看您的配置方式,回答这个问题会有点困难settings.py,但请仔细检查您是否完成了每一步。我也完成了快速入门,但仍然错过了一些地方。

答:确保您已settings.py正确配置

我遇到了类似的“连接被拒绝”错误,但问题是我的设置没有正确配置。

编辑:在进一步本地开发和切换个别设置后,我意识到我的“连接被拒绝错误与未EMAIL_BACKEND配置有关。它试图连接到任何未运行的 SMTP 服务器。确保您已EMAIL_BACKEND = "django.core.mail.backends.console.EmailBackend"设置记录此功能到您的控制台。

这是我正在使用的一个从头开始的项目的稍微缩写的副本settings.py,只是为了确保您已正确配置它:

来源:django-graphql-auth 快速入门

注意:它有点长,请确保一直滚动

# ...


# Application definition

INSTALLED_APPS = [
    "django.contrib.admin",
    "django.contrib.auth",
    "django.contrib.contenttypes",
    "django.contrib.sessions",
    "django.contrib.messages",
    "django.contrib.staticfiles",
    
    # Package apps
    "corsheaders",
    "graphene_django",
    "graphql_jwt.refresh_token.apps.RefreshTokenConfig",
    "graphql_auth",
    "django_filters",

    # Created apps
    "users", # or whatever the name of the app is with your custom users model
]

MIDDLEWARE = [
    "django.middleware.security.SecurityMiddleware",
    "django.contrib.sessions.middleware.SessionMiddleware",
    "corsheaders.middleware.CorsMiddleware",
    "django.middleware.common.CommonMiddleware",
    "django.middleware.csrf.CsrfViewMiddleware",
    "django.contrib.auth.middleware.AuthenticationMiddleware",
    "django.contrib.messages.middleware.MessageMiddleware",
    "django.middleware.clickjacking.XFrameOptionsMiddleware",
]

ROOT_URLCONF = "<project_name>.urls"

# TEMPLATES = ...
# WSGI_APPLICATION = ...
# DATABASES = ...

# Ensure that custom user is set
AUTH_USER_MODEL = "users.CustomUser"

# AUTH_PASSWORD_VALIDATORS = ...

# Internationalization
# https://docs.djangoproject.com/en/3.0/topics/i18n/

# ...

# Static files (CSS, JavaScript, Images)
# https://docs.djangoproject.com/en/3.0/howto/static-files/
# ...

GRAPHENE = {
    "SCHEMA": "backend.schema.schema",
    "MIDDLEWARE": ["graphql_jwt.middleware.JSONWebTokenMiddleware",],
}

AUTHENTICATION_BACKENDS = [
    "graphql_jwt.backends.JSONWebTokenBackend",
    "django.contrib.auth.backends.ModelBackend",
    "graphql_auth.backends.GraphQLAuthBackend",
]

GRAPHQL_JWT = {
    "JWT_VERIFY_EXPIRATION": True,
    "JWT_LONG_RUNNING_REFRESH_TOKEN": True,
}

EMAIL_BACKEND = "django.core.mail.backends.console.EmailBackend"

问题 2:正如我对各种用户及其注册的解释,我需要不同的论据。但是在模式中我们只添加了 register = mutation.Register.Field(),我怎样才能达到这个目的?

答:TLDR - 这在设置文档的动态字段部分中进行了说明。

答:演练

第 1 步:确保您的自定义用户模型具有字段集

在我们考虑更新我们的设置之前,请确认您需要设置的自定义字段存在于模型中。例如,如果我想要一个luck_number字段,我会添加:

class CustomUser(AbstractUser):
    ...

    luck_number = models.IntegerField()
    ...

然后,您需要确保运行迁移,以便它存在于您的数据库中。 python manage.py makemigrations python manage.py migrate

第 2 步:添加GRAPHQL_AUTHsettings.py

在您的设置中,确保设置:

# Rest of your settings ...

GRAPHQL_AUTH = {}

第 3 步:添加您的自定义字段并仔细检查您的架构

如果您想在注册时添加要收集的字段,您需要将 添加REGISTER_MUTATION_FIELDS到您的GRAPHQL_AUTH设置中。因此,在添加luck_number到我们的register突变的情况下:

GRAPHQL_AUTH = {
  REGISTER_MUTATION_FIELDS = {
    "email": "String",
    "username": "String",
    "luck_number": "Int",
  }
}
使用自定义字段注册突变

编辑1:添加图像

编辑 2:围绕我的注册突变错误添加说明

于 2020-08-04T19:33:24.547 回答