fastapi + sqlalchemy + pydantic → how to process relations - sqlalchemy

Using FastAPI I can't fetch all the data. For example I have this output :
Response body Download (but the items list is always empty):
[
{
"email": "mmm#gmail.com",
"id": 1,
"is_active": true,
"items": []
},
{
"email": "ee#gmail.com",
"id": 2,
"is_active": true,
"items": []
},
]
Endpoint are for example:
#app.get("/users/", response_model=list[schemas.User])
async def read_users(skip: int = 0, limit: int = 100, db: Session = Depends(get_db)):
users = crud.get_users(db, skip=skip, limit=limit)
return users
#app.get("/users/{user_id}", response_model=schemas.User)
async def read_user(user_id: int, db: Session = Depends(get_db)):
db_user = crud.get_user(db, user_id=user_id)
if db_user is None:
raise HTTPException(status_code=404, detail="User not found")
return db_user
I have the following schemas (database is PostgreSQL):
from pydantic import BaseModel
class ItemBase(BaseModel):
title: str
description: str | None = None
class ItemCreate(ItemBase):
pass
class Item(ItemBase):
id: int
owner: int
class Config:
orm_mode = True
class UserBase(BaseModel):
email: str
class UserCreate(UserBase):
password: str
class User(UserBase):
id: int
is_active: bool
items: list[Item] = []
class Config:
orm_mode = True
Database is postgresql
Models are (table users and table items):
from sqlalchemy import Boolean, Column, ForeignKey, Integer, String
from sqlalchemy.orm import relationship
from .database import Base
class User(Base):
__tablename__ = "users"
__table_args__ = {'schema': 'socialcampaigns'}
id = Column(Integer, primary_key=True, index=True)
email = Column(String, unique=True, index=True)
hashed_password = Column(String)
is_active = Column(Boolean, default=True)
items_rel = relationship("Item", back_populates="owner_id_rel")
class Item(Base):
__tablename__ = "items"
__table_args__ = {'schema': 'socialcampaigns'}
id = Column(Integer, primary_key=True, index=True)
title = Column(String, index=True)
description = Column(String, index=True)
owner = Column(Integer, ForeignKey("socialcampaigns.users.id"))
owner_id_rel = relationship("User", back_populates="items_rel")
Crud code is:
from sqlalchemy.orm import Session
from . import models, schemas
def get_user(db: Session, user_id: int):
return db.query(models.User).filter(models.User.id == user_id).first()
def get_users (db: Session, skip: int = 0, limit: int = 100):
return db.query(models.User).offset(skip).limit(limit).all()
How to solve it? How do I view the list of Items when viewing users?

Related

AttributeError: 'BaseModel' object has no attribute '_sa_instance_state'

I have the following code in my app:
models.py
class MainTable(Base):
__tablename__ = "main_table"
id = Column(Integer, primary_key=True, index=True)
name = Column(String, unique=True, index=True, nullable=False)
owner = Column(String, index=True)
metas = relationship("ChildTable", back_populates="item")
class ChildTable(Base):
__tablename__ = "child"
id = Column(Integer, primary_key=True, index=True)
segment = Column(Integer)
name = Column(String)
main_name = Column(String, ForeignKey('main_table.name'), nullable=False)
item = relationship("MainTable", back_populates="metas")
__table_args__ = (UniqueConstraint('segment', 'main_name', name='_meta_for_main'),
)
And when I run my app, and create new obj in db:
{
"name": "string",
"owner": "string",
"metas": [
{
"segment": 0,
"name": "string",
"main_name": "string",
}
]
}
I get the following error:
AttributeError: 'MainMetaCreate' object has no attribute '_sa_instance_state'
schemas.py
class EnvironmentMetaBase(BaseModel):
segment: int
name: str
main_name: str
Haw you met the following problem?

Django,how to filter multiple JSONField data?

Im using django with postgres i was able to add multiple filters in my views but mu question here is is there any possibility that i can filter multiple same jsonfield with different values:
ex i can filter localhost:127.0.0.1:products?areaOfUse=residential
so is there any possibilty that i can get the result of /products?areaOfUse=residential&areaOfUse=test
So from here i need to query two different json objects.
-Here are my views
class SubcategoriesProductsAPI(APIView):
# #cache_control(must_revalidate=True, max_age=3600)
def get (self, request, subCategoryId = None, pk = None):
try:
filters = {}
design = self.request.query_params.get('design', None)
dimension = self.request.query_params.get('dimension', None)
collectionName = self.request.query_params.get('collectionName', None)
material = self.request.query_params.get('material',None)
min_price = self.request.query_params.get('min_price',None)
max_price = self.request.query_params.get('max_price',None)
page = self.request.query_params.get('page', None)
wearLayer = self.request.query_params.get('wearLayer',None)
areaOfUse = self.request.query_params.getlist('areaOfUse',None)
productType = self.request.query_params.get('type', None)
installationMethod = self.request.query_params.get('installationMethod',None)
format_type = self.request.query_params.get('format_type',None)
wearLayer = self.request.query_params.get('wearLayer',None)
levelOfUse = self.request.query_params.get('levelOfUse',None)
if design is not None:
filters['product_options__options__data__design'] = design
if productType is not None:
filters['product_options__options__data__type'] = productType
if dimension is not None:
filters['product_options__options__data__dimensions__contains'] = [{'dimension': dimension}]
if collectionName is not None:
filters['product_options__options__data__collectionName'] = collectionName
if material is not None:
filters['product_options__options__data__material'] = material
if wearLayer is not None:
filters['product_options__options__data__wearLayer'] = wearLayer
if installationMethod is not None:
filters['product_options__options__data__installationMethod'] =installationMethod
if format_type is not None:
filters['product_options__options__data__format'] = format_type
if areaOfUse is not None:
filters['product_options__options__data__areaOfUse__contains'] = areaOfUse
if levelOfUse is not None:
filters['product_options__options__data__levelOfUse'] = levelOfUse
if min_price and max_price:
filters['product_options__options__data__dimensions__range__price'] = float(min_price)
filters['product_options__options__data__dimensions__0__price__lte'] = float(max_price)
queryset = Products.objects.filter(sub_categories_id = subCategoryId, is_active = True).select_related().filter(**filters)
if not queryset:
return JsonResponse({ 'status': False, 'msg': 'No products found', 'data': {} }, status=400)
if page is not None:
paginator = PageNumberPagination()
page = paginator.paginate_queryset(queryset, request)
if page is not None:
serializer = ProductSerializer(page, many=True)
return JsonResponse({ 'status': True, 'msg': 'Succesfully retrived products ', 'data': serializer.data, 'count': paginator.page.paginator.count, 'previous':paginator.get_previous_link(), 'next':paginator.get_next_link() }, status=200)
serializer = ProductSerializer(queryset, many=True)
return JsonResponse({ 'status': True, 'msg': 'Succesfully retrived products ', 'data': serializer.data }, status=200)
except Products.DoesNotExist:
return JsonResponse({ 'status': False, 'msg': 'Internal system error', 'data': {}}, status=500)
areaOfUse = self.request.query_params.getlist('areaOfUse[]',None)
/products?areaOfUse%5B%5D=residential&areaOfUse%5B%5D=test
import operator
from django.db.models import Q
from functools import reduce
queryset = Products.objects.filter(sub_categories_id = subCategoryId, is_active = True).select_related().filter(**filters)
if areaOfUse:
queryset.filter(
reduce(
operator.and_,
(Q(product_options__options__data__areaOfUse__contains=x) for x in areaOfUse)
)
)

How to serialize nested objects with related models?

i am really new to DRM and i have to following problem
I have three related models. Now i want to for each sensor values to the related patient. My models look like:
class Sensor(models.Model):
sensor_name = models.CharField(max_length=200, primary_key=True)
sensor_refreshRate = models.FloatField()
sensor_prio = models.IntegerField(choices=[
(1, 1), (2, 2), (3, 3), (4, 4), ], default='1')
sensor_typ = models.CharField(
max_length=200,
choices=[
('bar', 'bar'), ('pie', 'pie'),
('line', 'line'), ('text', 'text'),
],
default='bar'
)
class Patient(models.Model):
firstName = models.CharField(max_length=200)
lastName = models.CharField(max_length=200)
age = models.IntegerField()
doctor = models.ForeignKey(
settings.AUTH_USER_MODEL, on_delete=models.CASCADE)
sensor = models.ManyToManyField(Sensor)
class Value(models.Model):
value_date = models.DateTimeField(auto_now_add=True)
value = models.FloatField()
sensor = models.ForeignKey(Sensor, on_delete=models.CASCADE)
Now i would like to send a JSON file which looks like:
[
{
"value": 445.0,
"sensor": "Pressure",
"patient": 3
},
{
"value": 478.0,
"sensor": "Temperature",
"patient": 3
}
]
Now i am not sure how to serialize my JSON.
Thanks in advance
your data models seems incomplete.
There's no link between the Value model and the Patient one.
So first I'd suggest to modify the Value model
class Value(models.Model):
value_date = models.DateTimeField(auto_now_add=True)
value = models.FloatField()
sensor = models.ForeignKey(Sensor, on_delete=models.CASCADE)
patient = models.ForeignKey(Patient, on_delete=models.CASCADE)
then you could create a queryset
qs = Value.objects.filter(.....).values(
'patient_id', 'sensor__sensor_name', 'value'
)
and the write your serializer

How to Left Join Model (or) Table in DRF

I have two models Employee and AccessDr.
Employee Model=>
class Employee(models.Model):
empid = models.CharField(max_length=20, unique=True)
empname = models.CharField(max_length=50)
phone = models.CharField(max_length=20, blank=True)
token = models.ForeignKey(
Company, to_field='token', on_delete=models.CASCADE)
def __str__(self):
return "%s" % (self.empid)
class Meta:
managed = True
db_table = 'employee'
AccessDr Model=>
class AccessDr(models.Model):
empid = models.ForeignKey(
Employee, to_field='empid', on_delete=models.CASCADE)
_date = models.DateField()
_time = models.IntegerField()
device = models.CharField(max_length=5)
takey = models.CharField(max_length=3, default='00')
token = models.ForeignKey(
Company, to_field='token', on_delete=models.CASCADE)
def __str__(self):
return "%s %s" % (self.empid, self._date)
class Meta:
ordering = ['_date']
managed = True
db_table = 'tstrdoor'
I would like to return object when the request to AccessDr like SQL left join, Example json=>
{
empid:'',
empname:'', <=this one from employee model
phone:'', <=this one from employee model
_date:'',
_time:'',
.
.
}
How can I achieve that one?
have a look at this LEFT JOIN Django ORM
read this as well https://docs.djangoproject.com/en/2.2/topics/db/queries/#spanning-multi-valued-relationships
you can print query to look at how it translates to SQL by
Employes=AccessDr.objects.values('employee__empname','employee__phone')
print(Employes.query)
Are you using serializers in the views? in this case, you could create a serializer field
which will put agreement data as an array like this
class CustomerSerializer(serializers.ModelSerializer):
agreements = AgreementSerializer(many=True, read_only=True)
class Meta:
model = Customer
fields = [
'id',
'username',
'mail',
'fName',
'lName',
'fNameEng',
'lNameEng',
'personalId',
'phone',
'crmId', # "ID": "20995",
'agreements',
]
depth = 1
Are you using serializers in the views? in this case, you could create serializer field
which will put agreement data as an array like this
{
"id": 985,
"username": null,
"mail": "undefined",
"fName": "Merab",
"lName": "Dasv",
"fNameEng": "Merab",
"lNameEng": "Dasv",
"personalId": "01022342346003629",
"phone": "5912324234282331",
"crmId": 1439,
"agreements": [
{
"id": 884,
"signDate": "2015-04-16",
"accountDate": "2015-05-01",
"amount": 0,
"comBalance": -1445.0,
"status": 1,
"details": [
{
"square": 32.38,
"amount": 35.0,
"object": {
"id": 578,
"object": 2,
"block": 1,
"floor": 19,
"flat": "7",
"cadastre": "05.24.04.055.01.563",
"square": 32.38,
"pCounter": 25915123146,
"wCounter": 104412312435,
"accountDate": "2015-04-01T00:00:00",
"comBalance": -1445.0,
"comDeptAmount": 1895.0,
"rentDate": null,
"active": 1,
"finaAmount": 0,
"crmId": 0
}
},
]
},
]
}

sqlalchemy ---》type object 'role_user' has no attribute 'foreign_keys'

class User(Base):
"""
users table
"""
__tablename__ = 'users'
__table_args__ = {
'mysql_engine': 'InnoDB',
'mysql_charset': 'utf8'
}
id = Column(INTEGER, primary_key=True)
email = Column(String(64), nullable=False, unique=True)
password = Column(String(64), nullable=False)
name = Column(String(32), nullable=False)
last_login_time = Column(DateTime, default='')
last_login_ip = Column(String(32), default='')
create_time = Column(DateTime, nullable=False)
status = Column(SMALLINT, default=0)
role = relationship("Role",
secondary="role_user",
backref=backref('user'))
def __init__(self, email, password, name, last_login_time=now,
last_login_ip='0', create_time=now, status=0):
self.email = email
self.password = md5(password)
self.name = name
self.last_login_time = last_login_time
self.last_login_ip = last_login_ip
self.create_time = create_time
self.status = status
def __repr__(self):
return "<User('%s', '%s')>" % (self.name, self.email)
class Role(Base):
"""
roles table
"""
__tablename__ = 'roles'
__table_args__ = {
'mysql_engine': 'InnoDB',
'mysql_charset': 'utf8'
}
id = Column(SMALLINT(5), primary_key=True)
name = Column(String(32), nullable=False, unique=True)
def __init__(self, name):
self.name = name
def __repr__(self):
return "<Role('%s', '%s')>" % (self.id, self.name)
class role_user(Base):
"""
role_user association table
"""
__tablename__ = 'role_user'
__table_args__ = {
'mysql_engine': 'InnoDB',
'mysql_charset': 'utf8'
}
user_id = Column(INTEGER, ForeignKey('users.id'), primary_key=True)
role_id = Column(SMALLINT(5), ForeignKey('roles.id'), primary_key=True)
def __init__(self, user_id, role_id):
self.user_id = user_id
self.role_id = role_id
when I create an user,I meet the error:
u1 = User(email='john#example.com', password='12345', name='john')
Traceback (most recent call last):
File "<console>", line 1, in <module>
File "<string>", line 2, in __init__
File "/usr/local/lib/python2.6/dist-packages/SQLAlchemy-0.8.1dev-py2.6-linux-i686.egg/sqlalchemy/orm/instrumentation.py", line 310, in _new_state_if_none
state = self._state_constructor(instance, self)
File "/usr/local/lib/python2.6/dist-packages/SQLAlchemy-0.8.1dev-py2.6-linux-i686.egg/sqlalchemy/util/langhelpers.py", line 582, in __get__
obj.__dict__[self.__name__] = result = self.fget(obj)
File "/usr/local/lib/python2.6/dist-packages/SQLAlchemy-0.8.1dev-py2.6-linux-i686.egg/sqlalchemy/orm/instrumentation.py", line 145, in _state_constructor
self.dispatch.first_init(self, self.class_)
File "/usr/local/lib/python2.6/dist-packages/SQLAlchemy-0.8.1dev-py2.6-linux-i686.egg/sqlalchemy/event.py", line 409, in __call__
fn(*args, **kw)
File "/usr/local/lib/python2.6/dist-packages/SQLAlchemy-0.8.1dev-py2.6-linux-i686.egg/sqlalchemy/orm/mapper.py", line 2209, in _event_on_first_init
configure_mappers()
File "/usr/local/lib/python2.6/dist-packages/SQLAlchemy-0.8.1dev-py2.6-linux-i686.egg/sqlalchemy/orm/mapper.py", line 2118, in configure_mappers
mapper._post_configure_properties()
File "/usr/local/lib/python2.6/dist-packages/SQLAlchemy-0.8.1dev-py2.6-linux-i686.egg/sqlalchemy/orm/mapper.py", line 1242, in _post_configure_properties
prop.init()
File "/usr/local/lib/python2.6/dist-packages/SQLAlchemy-0.8.1dev-py2.6-linux-i686.egg/sqlalchemy/orm/interfaces.py", line 231, in init
self.do_init()
File "/usr/local/lib/python2.6/dist-packages/SQLAlchemy-0.8.1dev-py2.6-linux-i686.egg/sqlalchemy/orm/properties.py", line 1028, in do_init
self._setup_join_conditions()
File "/usr/local/lib/python2.6/dist-packages/SQLAlchemy-0.8.1dev-py2.6-linux-i686.egg/sqlalchemy/orm/properties.py", line 1102, in _setup_join_conditions
can_be_synced_fn=self._columns_are_mapped
File "/usr/local/lib/python2.6/dist-packages/SQLAlchemy-0.8.1dev-py2.6-linux-i686.egg/sqlalchemy/orm/relationships.py", line 114, in __init__
self._determine_joins()
File "/usr/local/lib/python2.6/dist-packages/SQLAlchemy-0.8.1dev-py2.6-linux-i686.egg/sqlalchemy/orm/relationships.py", line 180, in _determine_joins
consider_as_foreign_keys=consider_as_foreign_keys
File "/usr/local/lib/python2.6/dist-packages/SQLAlchemy-0.8.1dev-py2.6-linux-i686.egg/sqlalchemy/sql/util.py", line 345, in join_condition
b.foreign_keys,
AttributeError: type object 'role_user' has no attribute 'foreign_keys'
>>>
jiankong#ubuntu:~/git/admin-server$ python manage.py shell
Python 2.6.5 (r265:79063, Oct 1 2012, 22:07:21)
[GCC 4.4.3] on linux2
Type "help", "copyright", "credits" or "license" for more information.
(InteractiveConsole)
>>> from apps.auth.models import User
>>> u1 = User(email='john#example.com', password='12345', name='john')
what can i do to solve the question? thank you !!
you've got conflicting names for role_user, in that there's a class called role_user and a table with the same name. So secondary="role_user" picks the class object first. Maybe state it like this:
relationship("Role", secondary="role_user.__table__")
EDIT: ideally you'd define "role_user" as a Table only, and define it before you do "secondary". Follow the example at http://docs.sqlalchemy.org/en/latest/orm/relationships.html#many-to-many.