GraphQL: [Errno 111] В соединении отказано - PullRequest
0 голосов
/ 01 августа 2020

Описание

Я пытаюсь создать 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'
схема пользователей
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()

схема проекта
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

1 Ответ

1 голос
/ 04 августа 2020

Вопрос 1: Я ожидаю, что код будет работать без каких-либо проблем, но сталкиваюсь со следующей ошибкой в ​​реальном поведении

NB. Будет немного сложно ответить на этот вопрос, не видя, как ваш settings.py настроен, но дважды проверьте, что вы прошли каждый шаг. Я тоже прошел через быстрый старт, но все же пропустил несколько мест.

A: Убедитесь, что ваш settings.py правильно настроен

Я столкнулся с аналогичной ошибкой «Соединение отказано» , но проблема заключалась в том, что мои настройки не были настроены должным образом.

Изменить: после дальнейшей локальной разработки и переключения с индивидуальными настройками я понял, что моя ошибка «Отказ в соединении» связана с отсутствием EMAIL_BACKEND настроен. Он пытался подключиться к любому SMTP-серверу, который не работал. Убедитесь, что у вас установлен EMAIL_BACKEND = "django.core.mail.backends.console.EmailBackend" для регистрации этой функции на вашей консоли.

Вот немного сокращенная копия моего settings.py из проекта с нуля, который я использовал, просто чтобы убедиться, что он у вас настроен правильно:

Источник: django -graphql-auth quickstart .

NB: это немного длинновато, обязательно прокрутите до конца

# ...


# 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 = mutations.Register.Field (), как я могу достичь этой цели?

A: TLDR - это объясняется в Dynami c полях раздел настроек документации.

A: Пошаговое руководство

Шаг 1. Убедитесь, что в вашей пользовательской модели задано поле

Прежде чем мы подумаем об обновлении наших настроек, подтвердите что настраиваемое поле, которое необходимо установить, существует в модели. Например, если бы я хотел иметь поле luck_number, я бы добавил:

class CustomUser(AbstractUser):
    ...

    luck_number = models.IntegerField()
    ...

Затем вам нужно убедиться, что вы выполняете миграции, чтобы оно существовало в вашей базе данных. python manage.py makemigrations python manage.py migrate

Шаг 2: Добавьте GRAPHQL_AUTH к settings.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: добавить пояснения к моей ошибке при мутации регистра

...