Pydantic, sqlalchemy, fastapi, 'pydantic.error_wrappers.ValidationError: 1 validation error for' [duplicate] - python-3.x

I'm making a crud in fastapiI have a user model and I created another one called showuser to only show some specific fields in the query, but when I execute the request I get an error.
I just want my request to show the fields I have in showuser.
my schemas
from pydantic import BaseModel
from typing import Optional
from datetime import datetime
# Create a User model
# Create a class for the user
class User(BaseModel):
username: str
password: str
name: str
lastname: str
address: Optional[str] = None
telephone: Optional[int] = None
email: str
creation_user: datetime = datetime.now()
# Create UserId model
# Create a class for the UserId
class UserId(BaseModel):
id: int
# Create a ShowUser model
# Create a class for the ShowUser
class ShowUser(BaseModel):
username: str
name: str
lastname: str
email: str
class Config():
orm_mode = True
and this is the code from user where I implement the api
#router.get('/{user_id}', response_model=ShowUser)
def get_user(user_id: int, db: Session = Depends(get_db)):
user = db.query(models.User).filter(models.User.id == user_id).first()
if not user:
return {"Error": "User not found"}
return {"User": user}
Terminal Message
pydantic.error_wrappers.ValidationError: 4 validation errors for ShowUser
response -> username
field required (type-value_error.missing)
response -> name
field required (type=value_error.missing)
response -> lastname
field required (type=value_error.missing)
response -> email
field required (type=value_error.missing)

I think the return value of your get_user function is the issue. Rather than returning {"User": user}, try returning just the user object as shown below:
#router.get('/{user_id}', response_model=ShowUser)
def get_user(user_id: int, db: Session = Depends(get_db)):
user = db.query(models.User).filter(models.User.id == user_id).first()
if not user:
return {"Error": "User not found"}
return user
EDIT: The same error will occur if the database does not contain a User object matching the value of user_id. Rather than returning {"Error": "User not found"}, the best way to handle this very common scenario is to raise an HTTPException with a 404 status code and error message:
#router.get('/{user_id}', response_model=ShowUser)
def get_user(user_id: int, db: Session = Depends(get_db)):
user = db.query(models.User).filter(models.User.id == user_id).first()
if not user:
raise HTTPException(
status_code=int(HTTPStatus.NOT_FOUND),
detail=f"No user exists with user.id = {user_id}"
)
return user

Related

FastAPI + MongoDB Error: 'id': str(user['_id']), TypeError: string indices must be integers

I am creating a basic login form using oauth2.0 in FastAPI and MongoDB. I am trying to get the email and password from the database but it keeps showing the same error "'id': str(user['_id']), TypeError: string indices must be integers". I am not exactly sure what I am doing wrong.
#authentication.post('/login')
async def login(form_email: OAuth2PasswordRequestForm = Depends(),
form_password: OAuth2PasswordRequestForm = Depends()):
email = users_serializer(user_list.find_one({"email": form_email.username}))
password = users_serializer(user_list.find_one({"password": form_password.password}))
print(email)
print(password)
if form_email.username == email:
if form_password.password == password:
return {"status": "ok", "details": f"Welcome! {form_email.username} "}
raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail='Incorrect email or password')
This is the users_serializer schema:
def user_serializer(user) -> dict:
return {
'id': str(user['_id']),
'name': str(user['name']),
'email': str(user['email']),
'password': str(user['password']),
}
Can anyone help me understand what I am doing wrong? Thanks in advance!
PS: I don't have much experience with FastAPI and MongoDB.

Graphene mutation with multi InputObjectType

I am trying to convert graphql server from #nestjs/graphql to python graphene. Is it possible to create mutation class in graphene that generates the same schema as the one made in #nestjs/graphql like this?
type Mutation {
register(input: RegisterInput!): AuthResponse!
login(input: LoginInput!): AuthResponse!
socialLogin(input: SocialLoginInput!): AuthResponse!
otpLogin(input: OtpLoginInput!): AuthResponse!
...
Where the AuthResponse class mutation can be used in many requests (register, login etc). What I can make so far is as follow:
class RegisterInput(graphene.InputObjectType):
email = graphene.String()
password = graphene.String()
class LoginInput(graphene.InputObjectType):
email = graphene.String()
password = graphene.String()
class AuthResponse(graphene.Mutation):
response = graphene.String()
def mutate(root, info, **args):
response = 'this is response'
return AuthResponse(
response=response,
)
class RegisterObject(AuthResponse):
class Arguments:
input = RegisterInput(required=True)
class LoginObject(AuthResponse):
class Arguments:
input = LoginInput(required=True)
class Mutation(graphene.ObjectType):
register = RegisterObject.Field(
required=True
)
login = LoginObject.Field(
required=True
)
But above generate the following schema which differs from the one above:
type Mutation {
register(input: RegisterInput!): RegisterObject!
login(input: LoginInput!): LoginObject!
...
Finally I can answer my own question. In order to make multi mutation requests with one answer, we can do the following:
user.py
import graphene
from ..common import (
core,
attachment,
pagination
)
from ..addresses import address
from ..wallets import wallet
from ..shops import shop
from ..refunds import refund
from ..orders import order
from . import profile
class User(core.CoreEntity):
name = graphene.String(required=True)
email = graphene.String(required=True)
password = graphene.String()
shop_id = graphene.Int(name='shop_id')
profile = graphene.Field(lambda:profile.Profile)
shops = graphene.List(graphene.NonNull(lambda:shop.Shop))
refunds = graphene.List(lambda:refund.Refund)
managed_shop = graphene.Field(lambda:shop.Shop,name='managed_shop')
is_active = graphene.Boolean(name='is_active')
address = graphene.List(graphene.NonNull(lambda:address.Address))
orders = graphene.List(lambda:order.Order)
wallet = graphene.Field(lambda:wallet.Wallet)
class SuccessResponse(graphene.ObjectType):
message = graphene.String(required=True)
success = graphene.Boolean(required=True)
class OtpResponse(graphene.ObjectType):
id = graphene.String(required=True)
message = graphene.String(required=True)
success = graphene.Boolean(required=True)
phone_number = graphene.String(required=True)
provider = graphene.String(required=True)
is_contact_exist = graphene.Boolean(required=True)
class PasswordChangeResponse(graphene.ObjectType):
success = graphene.Boolean(required=True)
message = graphene.String(required=True)
class AuthResponse(graphene.ObjectType):
token = graphene.String()
permissions = graphene.List(graphene.String)
class RegisterInput(graphene.InputObjectType):
name = graphene.String(required=True)
email = graphene.String(required=True)
password = graphene.String()
permissions = graphene.Field(lambda:Permission)
class Permission(graphene.Enum):
SUPER_ADMIN = 'Super admin'
STORE_OWNER = 'Store owner'
STAFF = 'Staff'
CUSTOMER = 'Customer'
class LoginInput(graphene.InputObjectType):
email = graphene.String()
password = graphene.String()
mutation.py
import graphene
from .models.users import user, profile
from .models.products import product
from .models.orders import order
class Mutation(graphene.ObjectType):
register = graphene.Field(
lambda:user.AuthResponse,
input=graphene.Argument(user.RegisterInput, required=True),
required=True,
)
login = graphene.Field(
lambda:user.AuthResponse,
input=graphene.Argument(user.LoginInput, required=True),
required=True,
)
#staticmethod
def resolve_register(root, info, input):
# return AuthResponse(email=input['email'], password=input['password'])
# Here we can insert data into database (eg. Django or Odoo) and get fresh token for the registered user
token = 'thisistoken'
permissions = ['super_admin', 'customer']
return user.AuthResponse(token=token, permissions=permissions)
#staticmethod
def resolve_login(root, info, input):
# Here we can compare credential with database (eg. Django or Odoo) and get token
token = 'thisistoken'
permissions = ['super_admin', 'customer']
return user.AuthResponse(token=token, permissions=permissions)
and here is the schema generated inside our graphql playground app:
type Mutation {
register(input: RegisterInput!): AuthResponse!
login(input: LoginInput!): AuthResponse!
# below is other mutation request similar
socialLogin(input: SocialLoginInput!): AuthResponse!
otpLogin(input: OtpLoginInput!): AuthResponse!
verifyOtpCode(input: VerifyOtpInput!): SuccessResponse!
sendOtpCode(input: OtpInput!): OtpResponse!
logout: Boolean!
changePassword(input: ChangePasswordInput!): PasswordChangeResponse!
forgetPassword(input: ForgetPasswordInput!): PasswordChangeResponse!
verifyForgetPasswordToken(
input: VerifyForgetPasswordTokenInput!
): PasswordChangeResponse!
resetPassword(input: ResetPasswordInput!): PasswordChangeResponse!
updateUser(input: UpdateUserInput!): User!
activeUser(id: ID!): User!
banUser(id: ID!): User!
removeUser(id: ID!): User!
createProfile(input: ProfileInput!): Profile!
updateProfile(id: ID!, input: ProfileInput!): Profile!
deleteProfile(id: ID!): Profile!
So the two mutation requests: register and login are answered by one object mutation object called AuthResponse.
Hope this help others.

using custom model fo django djoser

i am creating api endpoints for user management using Djoser and i want to use a custom model to create user and login i only want to use email.
the user entity given to me does not have a username field
below i will share the various settings i have set up for my apps
#accounts/model.py
from django.db import models
from django.contrib.auth.models import AbstractUser
# Create your models here.
class CustomUser(AbstractUser):
username = None
email = models.EmailField(unique=True)
REQUIRED_FIELDS = ['first_name', 'last_name']
USERNAME_FIELD = 'email'
def __str__(self):
return self.email
My serializer file
#accounts/serializers.py
from djoser.serializers import UserCreateSerializer, UserSerializer
from rest_framework import serializers
from rest_framework.fields import CurrentUserDefault
from .models import CustomUser
class UserCreateSerializer(UserCreateSerializer):
class Meta:
model = CustomUser
fields = ['id', 'email', 'first_name', 'last_name']
#settings.py
REST_FRAMEWORK = {
'DEFAULT_AUTHENTICATION_CLASSES': (
# 'rest_framework_simplejwt.authentication.JWTAuthentication',
'rest_framework.authentication.TokenAuthentication',
),
'DEFAULT_PERMISSIONS_CLASSES': (
'rest_framework.permissions.IsAuthenticated'
)
}
AUTH_USER_MODEL = 'accounts.CustomUser'
DJOSER = {
'LOGIN_FIELD': 'email',
'USER_CREATE_PASSWORD_RETYPE': True,
'SERIALIZERS': {
'user_create': 'accounts.serializers.UserCreateSerializer',
'user': 'accounts.serializers.UserCreateSerializer',
# 'current_user': 'accounts.serializers.CurrentUserSerializer'
}
when i try to register user i get
TypeError at /auth/users/
create_user() missing 1 required positional argument: 'username'
Request Method: POST
Request URL: http://127.0.0.1:8000/auth/users/
Django Version: 3.1
Exception Type: TypeError
Exception Value:
create_user() missing 1 required positional argument: 'username'
Exception Location: /home/femiir/.virtualenvs/codegarage/lib/python3.8/site-packages/djoser/serializers.py, line 73, in perform_create
Python Executable: /home/femiir/.virtualenvs/codegarage/bin/python
Python Version: 3.8.5
please what i my doing wrong ?
You need to have a custom user manager, probably something like this:
from django.contrib.auth.base_user import BaseUserManager
class MyUserManager(BaseUserManager):
def create_user(self, email, password=None, **extra_fields):
"""
Creates and saves a User with the given email, first name,
last name and password.
"""
if not email:
raise ValueError("Users must have an email address")
user = self.model(
email=self.normalize_email(email),
**extra_fields,
)
user.set_password(password)
user.save(using=self._db)
return user
def create_superuser(self, email, password=None, **extra_fields):
"""
Creates and saves a superuser with the given email, first name,
last name and password.
"""
user = self.create_user(
email,
password=password,
**extra_fields,
)
user.is_admin = True
user.save(using=self._db)
return user
And in your custom user model:
class CustomUser(AbstractBaseUser):
# [...]
objects = MyUserManager()
# [...]
I've taken the code from the django documentation about customizing the User model. They provide an example using the email as the username field (which is what you want).
You may keep the inheritance from AbstractUser but if you do not need most of the things that are in that model, you can also inherit your model from AbstractBaseUser, as in the example.

user.check_password assertion failing

I have some tests trying to validate my user creation process in an API application.
The issue I am having is that when I try to validate a users password was created as a hashed object the test is failing.
Test:
CREATE_USER_URL = reverse('user:create')
def create_user(**params):
return get_user_model().objects.create_user(**params)
...
def test_create_valid_user_success(self):
"""Test creating user with valid user is successful"""
payload = {
'email': 'test#email.com',
'password': 'testpass',
'name': 'Test Name'
}
res = self.client.post(CREATE_USER_URL, payload)
self.assertEqual(res.status_code, status.HTTP_201_CREATED)
user = get_user_model().objects.get(**res.data)
self.assertTrue(user.check_password(payload['password']))
self.assertNotIn('password', res.data)
Serializer:
from django.contrib.auth import get_user_model
from rest_framework import serializers
class UserSerializer(serializers.ModelSerializer):
"""Serializer for users object"""
class Meta:
model = get_user_model()
fields = ('email', 'password', 'name')
extra_kwargs = {
'password': {
'write_only': True,
'min_length': 8
}
}
def create(self, validated_data):
"""Create a new user with encrypted password and return it"""
return get_user_model().objects.create_user(**validated_data)
Failed Test:
FAIL: test_create_valid_user_success (user.tests.test_user_api.PublicUserApiTests)
Test creating user with valid user is successful
----------------------------------------------------------------------
Traceback (most recent call last):
File "/app/user/tests/test_user_api.py", line 33, in test_create_valid_user_success
self.assertTrue(user.check_password(payload['password']))
AssertionError: False is not true
From what I can tell from documentation etc, I have the correct syntax.
Wjhat is missing/incorrect that I need in order to fix this error?
Turns out the issue was indentation in my UserSerializer class.
See this issue:
Django users being created with cleartext passwords

Error cannot unpack non-iterable NoneType object

not sure why the code is breaking down but am assigning 3 variables to a function call that are all used in the call and i keep getting an Nonetype error with the class function call.
i am trying to create a user and passing a success, user and message.
If success is true then it will then proceed to create and send the user an activation email
user is the user created.
message is if there is an error(there user has been created before and exists)
if email_address and first_name and last_name:
#register user and check other params
success, user, message = User.create(email_address=email_address, first_name=first_name, last_name=last_name)
if success:
# send activation email
success, message = User.send_activation_email(email_address=email_address)
if success:
return make_response(jsonify({"Message" : "Registration Successful"}))
#Todo include the correct url
#return render_template_with_translations("public/auth/register_success.html", **params)
else:
return abort(403, description=message)
else:
params["register_error_message"] = message
return make_response(jsonify({"Message" : params}))
#return render_template_with_translations("public/auth/register_error.html", **params)
The class being called in the users.model
#classmethod
def create(cls, email_address, password=None, admin=False, first_name=None, last_name=None):
try:
# check if there's any user with the same email address already
user = db.query("Select * FROM User WHERE email_address = {}".formart(email_address))
if not user: # if user does not yet exist, create one
hashed = None
if password:
# use bcrypt to hash the password
hashed = bcrypt.hashpw(password=str.encode(password), salt=bcrypt.gensalt(12))
# create the user object and store it into Datastore
user = cls(email_address=email_address, password_hash=hashed, admin=admin, first_name=first_name,
last_name=last_name)
user.put()
return True, user, "Success" # succes, user, message
else:
return False, user, "User with this email address is already registered. Please go to the " \
"Login page and try to log in."
except:
print ("Error with application")

Resources