Cannot update with FastAPI - python

When I run put from FastAPI docs with the following code, I get 500 Error: Internal Server Error`` and the terminal shows AttributeError: 'Test' object has no attribute ' items'```` and the terminal shows AttributeError: 'Test' object has no attribute 'items'.
I can create, get, delete, etc. normally, but for some reason I can't just put.
Also, if I try putting in a non-existent ID, I get a 404 error normally.
I would appreciate it if you could tell me more about it.
router
#router.put('/{id}', status_code=status.HTTP_202_ACCEPTED)
def update(id, request:schemas.Test ,db:Session = Depends(get_db)):
test= db.query(models.Test).filter(models.Test.id == id)
if not test.first():
raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail=f'Test with id {id} is not found')
test.update(request)
db.commit()
return 'updated'
models
from sqlalchemy import Column, Integer, String
from db import Base
class Test(Base):
__tablename__ = 'tests'
id = Column('id',Integer, primary_key=True,index=True)
title = Column('title',String(256))
schemas
from pydantic import BaseModel
class Test(BaseModel):
title:str

SQLAlchemy's update method on objects expects a dict. You're giving it a pydantic base model.
Pydantic's BaseModel supports a dict() method to return the object's properties as a dictionary. You can give this dictionary to your update method instead:
test.update(request.dict())
Also be aware that the request name is used for other things in FastAPI and might not be a good name for a route parameter. The id name is also a reference to a built-in Python function, so you'll usually want to name it test_id or something similar instead.

Related

Access to marshmallow field value

I begin with marshamallow and I try to validate a field. My schema is very simple.
class MySchema(Schema):
pid = fields.String(required=true)
visibility = fields.String(validate=OneOf(['public','private'])
#validates('visibility')
def visibility_changes(self, data, **kwargs):
# Load data from DB (based on ID)
db_record = load_data_from_db(self.pid) # <-- problem is here
# Check visibility changed
if db_record.get('visibility') != data:
do_some_check_here()
But using self.pid doesn't work. It raises an error AttributeError: 'MySchema' object has no attribute 'pid'.
What's the correct way to access to my "pid" field value into my #validates function ?
I tried using self.fields, self.load_fields.get('pid').get_value(), ... no easy way to access it, but I suppose that Marshmallow has such magic method.
Thanks for your help.

flask-login using UserMixin - no 'id' attribute error despite being implemented

I have been trying to use flask-login for authentication in my flask app. While trying to implement the user_loader like this:
#login_manager.user_loader
def load_user(id):
return User.get_id(id)
i get the error
NotImplementedError: No id attribute - override get_id
My User class is defined like this:
class User(Base, UserMixin):
__tablename__ = 'users'
id = Column(Integer, primary_key=True)
email = Column(String(70), unique=True)
userName = Column(String(40), unique=True)
password = Column(String(150))
#def get_id(self):
# return (self.id)
i tried overriding the get_id method, as you can see in the User class. It just got me the error
AttributeError: 'str' object has no attribute 'id'
What am i missing? Why is the id attribute not found?
You are correctly implementing a getter for the id variable in your override, but I think that you are misinterpreting how to use the function in the code to load a user by id. In your overridden function, get_id takes in no parameters besides self, because the function simply returns the id of a user. However you are trying to use this as a function to load a user from their id. The reason we are getting this specific error is because by calling User.get_id(id), you are calling get_id with self=id and since id is a str, we get the AttributeError from trying to get the id property of id, which doesn't exist.
Try using get instead of get_id (as shown in this tutorial).
This way the returned value is an instance of User with the desired id
#login_manager.user_loader
def load_user(id):
return User.query.get(int(id))

issue creating an user with calculated field fastAPI

I have a simple API to insert data inside an object type dictionary, my issue is when I try to save a calculated field. Example code:
from fastapi import FastAPI
from pydantic import BaseModel
app = FastAPI()
users = {}
class User(BaseModel):
name: str
email: str
calculated: float
#app.post('/user-create/{id_user}')
def creating_an_user(id_user:int,user:User):
calculated = 1+2+3*2
if id_user in users:
return {"Error":"User ID already exists."}
users[id_user] = {
"name":user.name,
"email":user.email,
"calculated":user.calculated #should I need to put just like that ?
}
return users[id_user]
Obviously I receive an error, I think because my method is waiting a manually insert "calculated" field but is not:
TypeError: Failed to execute 'fetch' on 'Window': Request with GET/HEAD method cannot have body.
I am lost in this concern, can anybody help me on this?

Cornice schema validation with colanderalchemy

Cornice's documentation mentions how to validate your schema using a colander's MappingSchema subclass. How should we use a colanderalchemy schema for the same purpose? Because if we create a schema using colanderalchemy as stated in the documentation, the schema object has already instantiated the colander's class, and I think that this results in an error.
To be more precise, here is my sample code:
from sqlalchemy.ext.declarative import declarative_base
from cornice.resource import resource, view
from colanderalchemy import SQLAlchemySchemaNode
from sqlalchemy import (
Column,
Integer,
Unicode,
)
Base = declarative_base()
'''
SQLAlchemy part
'''
class DBTable(Base):
__tablename__ = 'mytable'
id = Column(Integer, primary_key=True,
info={'colanderalchemy': {'exclude': True}})
name = Column(Unicode(70), nullable=False)
description = Column(Unicode(256))
'''
ColanderAlchemy part
'''
ClndrTable = SQLAlchemySchemaNode(DBTable)
'''
Cornice part
'''
PRF='api'
#resource(collection_path='%s/' % PRF, path='%s/{fid}' % PRF)
class TableApi(object):
def __init__(self, request):
self.request = request
#view(schema=ClndrTable, renderer='json')
def put(self):
# do my stuff here
pass
Where ClndrTable is my auto-generated schema. Now, when trying to deploy this code, I get the following error:
NotImplementedError: Schema node construction without a typ argument or a schema_type() callable present on the node class
As I've mentioned earlier, I am suspecting that the problem is that ClndrTable (given as an argument to the view decorator) is an instantiation of the automatically generated schema by colanderalchemy.
Anyone knowing how to resolve this?
Thanks all in advance!
This appears to be due to the issue of colander having both a typ property and a schema_type property. They're both supposed to tell you the schema's type, but they can actually be different values. I filed an issue with colander, but if there's a fix it'll likely not make it to pypi any time soon.
So what's happing is: ColanderAlchemy ignores schema_type and uses typ while Cornice ignores typ and uses schema_type.
You can hack a fix with the following: ClndrTable.schema_type = lambda: ClndrTable.typ
However, that just leads you to the next exception:
cornice.schemas.SchemaError: schema is not a MappingSchema: <class 'colanderalchemy.schema.SQLAlchemySchemaNode'>
This is due to Cornice not duck typing but expecting all Schema to be a subclass of MappingSchema. However, MappingSchema is just a Schema with typ/schema_type being Mapping (which is what ColanderAlchemy returns).
I'll see if I can enact some changes to fix this.
Update
Despite the names, 'typ' and 'schema_type' have two different purposes. 'typ' always tells you the type of a schema instance. 'schema_type' is a method that's called to give a SchemaNode a default type when it's instantiated (so it's called in the __init__ if you don't pass a typ in, but other than that it's not supposed to be used).
Cornice has been patched to properly use typ now (though, as of this message, it's not part of the latest release).

PYMongo : Parsing|Serializing query output of a collection

By default collection.find or collection.findone() functions results in a dictionary types and if you pass paramater as_class=SomeUserClass than it will try to parse the result into this class format.
but it seems this class should also be derived class of dictionary (as it required __setitem__ function to be defined and i can add keys in the class ).
Here i want to set the properties of the class. how can i do achieve this?
Also, my collection class contains some child classes as properties .So how can i set the properties of child classes also.
It sounds like you want something like an object-relational mapper. I am the primary author of one Ming , but there exist several others for Python as well. In Ming, you might do the following to set up your mapping:
from ming import schema, Field
from ming.orm import (mapper, Mapper, RelationProperty,
ForeignIdProperty)
WikiDoc = collection(‘wiki_page', session,
Field('_id', schema.ObjectId()),
Field('title', str, index=True),
Field('text', str))
CommentDoc = collection(‘comment', session,
Field('_id', schema.ObjectId()),
Field('page_id', schema.ObjectId(), index=True),
Field('text', str))
class WikiPage(object): pass
class Comment(object): pass
ormsession.mapper(WikiPage, WikiDoc, properties=dict(
comments=RelationProperty('WikiComment')))
ormsession.mapper(Comment, CommentDoc, properties=dict(
page_id=ForeignIdProperty('WikiPage'),
page=RelationProperty('WikiPage')))
Mapper.compile_all()
Then you can query for some particular page via:
pg = WikiPage.query.get(title='MyPage')
pg.comments # loads comments via a second query from MongoDB
The various ODMs I know of for MongoDB in Python are listed below.
Ming
MongoKit
MongoEngine
I have solved this by adding __setitem__ in class.
than i do
result = as_class()
for key,value in dict_expr.items():
result.__setitem__(key,value)
and in my class __setitem__ is like
def __setitem__(self,key,value):
try:
attr = getattr(class_obj,key)
if(attr!=None):
if(isinstance(value,dict)):
for child_key,child_value in value.items():
attr.__setitem__(child_key,child_value)
setattr(class_obj,key,attr)
else:
setattr(class_obj,key,value)
except AttributeError:
pass

Categories