Aún no tienes acceso a esta clase

Crea una cuenta y continúa viendo este curso

Creando la lógica del registro de usuarios

21/25
Recursos

Aportes 14

Preguntas 8

Ordenar por:

¿Quieres ver más aportes, preguntas y respuestas de la comunidad? Crea una cuenta o inicia sesión.

Pydantic permite la multiplicidad de herencia para los modelos, así los cambios realizados en un padre se reflejan en los hijos. En el caso de la clase UserRegister no era necesario agregar manualmente el password, simplemente se define la clase así:

class UserRegister(User, UserLogin):
	pass

Hola, en el minuto 3:18 el profesor obtiene el contenido de un archivo a modo de string con f.read() y eso se lo pasa como parametro a la funcion json.loads(), esta no es la manera mas optima de hacer este proceso, el propio Python trae una funcion la cual recibe como parametro un objeto de tipo file y se encarga de hacer el proceso, esta funcion es json.load() sin la s (la s quiere decir string). Tambien hay un metodo json.dump que recibe igualmente como parametro un objeto json y un objeto file y ahorra todo el proceso de convertir a string, hacer el f.write, etc.

with open('filepath', 'r+') as f:
	results = json.load(f)
	# Modificas el archivo
	json.dump(results, f)

Pequeña validación para comprobar si el email ya existe.

if any(users['email'] == user.email for users in results):
            raise HTTPException(
            status_code=status.HTTP_409_CONFLICT,
            detail="Email already exist!"
        )

Para evitar colocar de manera manual el casting de los tipos de datos que no str, pueden colocar la siguiente función general debajo de los modelos

## Function to apply a lambda function to a dictionary
def function_to_dict(f: Generic[T], dict: Dict) -> None:
    """
    Function in a dictionary.

    This function iterates to a dictionary and applies the function of the parameter.

    Parameters:
    - **f: Generic[T]**: The function to apply. For example a lamba function.
    - **dict: Dict**: The dictionary in which to apply the function.

    Returns
    - **None**
    """
    for key, val in dict.items():
        dict[key] = f(val)

Para invocarla en la path operation de signup queda de la siguiente manera:

### Register a user
@app.post(
    path = '/signup',
    response_model =  User,
    status_code = status.HTTP_201_CREATED,
    summary = 'Register a User.',
    tags = ['Users']
)
def signup(user: UserRegister = Body(...)) -> Dict[str, str]:
    """
    Register a new user.

    This path operation register a new user in the app.

    Parameters:
    - Request body parameter:
        - **user: UserRegister**: With all data required to create a new user.
    
    Returns:
    - A **JSON** with the basic tweet information, user_id, email, first_name, last_name and birth_date.
    """
    with open('users.json', 'r+', encoding = 'utf-8') as f:
        results: List[str, Dict[str, str]] = json.loads(f.read())
        user_dict: Dict[str, Generic[T]] = user.dict()
        # Cast the non str data types to string to have the correct json format
        function_to_dict(lambda x: x if type(x) == str else str(x), user_dict)
        results.append(user_dict)
        f.seek(0)
        f.write(json.dumps(results))
        return user

Para quien le sirva dejo mis apuntes con los pasos

@app.post(path="/signup",
          response_model=User,
          status_code = status.HTTP_201_CREATED,
          summary="Register a User",
          tags=["Users"])
def signup(user: UserRegister = Body(...)):
    """
    Signup
    
    This path operation register a user in the app
    
    Parameters:
        -Request body barameter
            -user: UserRegister

    Returns:
        -user_id: UUID
        -email: Emailstr
        -first_name: str
        -last_name: str
        -birth_date: datetime
    """
    # el "r+" quiere decir que lee y escribe
    with open("users.json", "r+", encoding="utf-8") as f:
        #Con json.loads nos permite crear un simil json, en este caso una lista de dicts
        #Los pasos son los siguentes:
        
        # 1- Leemos el json con .read() y lo transformamos en un tipo de dato que podemos trabajar con json.loads
        # 2- Crea un diccionario a partir del request Body (user)
        # 3- Casting de variables que no se pueden manejar a str
        # 4- Y se hace un append del dict
        # 5- Hay que moverse al principio del archivo porque ya se estuvo trabajando abierto, esto para evitar bugs, se realiza con ".seek(0)", nos lleva al primer byte
        # 6- Hay que hacer el write pero en json, se realiza con "json.dumps()"
        # 7- Se hace un return de user, el que viene como parámetro, para decirle al user del API que se escribio correctamente
        
        results = json.loads(f.read())
        user_dict = user.dict()
        user_dict["user_id"] = str(user_dict["user_id"])
        user_dict["birth_date"] = str(user_dict["birth_date"])
        results.append(user_dict)
        f.seek(0)
        f.write(json.dumps(results))
        return user

Para que la documentacion separe correctamente en lineas mis parametros y los datos a retornar, la estructua debe ser la siguiente:

'''
    Signup

    This path operation creates an user in the app

    Parameters:
    - Request body parameter
        - user: UserRegister

    Returns a json with the basic user information:
    - user_id: UUID
    - email: Emailstr
    - first_name: str
    - last_name: str
    - birth_date: date

''' 

Todo bien con el código pero al momento de darle a Try it out y execute, me marca un error 500 undocumented y no se crea el json del nuevo usuario en el documento users.json, pero abajo aparece un SC 201 y me arroja los valores predeterminados, y sinceramente no sé qué sea.

Quizás notaron que el UUID no cambia, es el mismo en cada registro, no se si lo aclare en un video más adelante pero les explico:

from uuid import UUID, uuid4 # importamos uuid4

class user(BaseModel):
user_id: UUID = Field(default_factory=uuid4) # añadimos default_factory

Al colocar default factory se crea una nueva automáticamente con cada registro.

Para que salga bien la indentación:

def signup(user: UserRegister = Body(...)):
    """
    Signup

    This path operations register a user in the app

    Parameters:
    - Request body parameter
        - user: UserRegister

    Return a json with the basic user information:
    - user_id: UUID
    - email: Emailstr
    - first_name: str
    - last_name: str
    - birth_date: datetime
    """
    with open("users.json", "r+", encoding="utf-8") as f:
        results = json.loads(f.read())
        user_dict = user.dict()
        user_dict["user_id"] = str(user_dict["user_id"])
        user_dict["birth_date"] = str(user_dict["birth_date"])
        results.append(user_dict)
        f.seek(0)
        f.write(json.dumps(results))
        return user

Hola, aquí dejo mis aportes sobre la clase:

  • Exportar un modelo pydantic a json se puede hacer más fácil de la siguiente manera:
    user.json()
    Sin la necesidad de sobreescribir atributos para convertirlos de forma manual (UUID y Date). Docs aquí

  • Lo segundo, el UUID debería ser generado por el servidor y no enviado por el usuario. Estos se pueden generar de forma simple con la misma librería de donde se exportó la clase UUID:
    uuid.uuid1()
    Para esto es necesario que el modelo de entrada no contenga el ID, el de salida sí.

Para evitar tener que hacer el format del json, usen esto en su código:

f.write(json.dumps(results, indent=2))

Yo utilizo la librería PysonDB para manejar la data de los archivos JSON

Es preciso señalar que no debemos guardar las contraseñas de nuestros usuarios de forma explicita en nuestras bases de datos porque podemos caer en fuertes problemas de seguridad y legales. La alternativa a ello son las tablas de Hash.

json.loads() parse a JSON string en un dict in Python. Cada request body tiene el método dict.

Los archivos de tipo UUID (Universal Unique Identifier) y date, no se pueden convertir a dict de forma directa, tenemos que realizarlo de forma manual mediante un un casting.

user_dict["user_id" ] = str(user_dict["user_id" ])

f.seek(0) movernos al byte del principio.
f.write(json.dumps(results)) casting results (dict) a json

@app.post(
    path="/signup",
    response_model=User,
    status_code=status.HTTP_201_CREATED,
    summary="Register a User",
    tags=["Users"]
)
def signup(user: UserRegisterForm = Body(...)):
    """
    Register a new User

    Parameters: 
        - Request Body Parameter
            - user: UserRegister

    Return a json with the basic user information:
        - user_id: UUID
        - email: EmailStr
        - first_name: str
        - last_name: str
        - birth_date: datetime

    """
    with open("users.json", "r+", encoding="utf-8") as f:
        results = json.loads(f.read())
        user_dict = user.dict()
        user_dict["user_id"] = str(user_dict["user_id"])
        user_dict["birth_date"] = str(user_dict["birth_date"])
        results.append(user_dict)
        f.seek(0)
        f.write(json.dumps(results))
        return user