Flask SQLAlchemy customer orm? [duplicate] - flask

This question already has an answer here:
SQLAlchemy: Convert column value back and forth between internal and database format
(1 answer)
Closed 4 years ago.
My model is like this:
class A(db.Model):
__tablename__ = 'tablename'
id = Column(Integer, primary_key=True)
users = Column(String(128))
But most of time, I use the users field as list.
In java ORM I can declared this field as list just by tell the framework how to map string to list and list to string.
So I wonder there is any way to do this in Flask.

You can create custom type with TypeDecorator
import sqlalchemy.types as types
class MyList(types.TypeDecorator):
impl = types.String
def process_bind_param(self, value, dialect):
return ','.join(value)
def process_result_value(self, value, dialect):
return value.split(',')
class A(db.Model):
__tablename__ = 'tablename'
id = Column(Integer, primary_key=True)
users = Column(MyList)
a = A(users=['user1', 'user2'])
db.session.add(a)
db.session.commit()
A.query.first().users
>> [u'user1', u'user2']

Related

How to Filter foreign key related models using datetime range

I'm trying to create a reservation system and I want to query all available tables. So, what I did is as follows,
...
date_time = request.data.get('date_time')
date_time = datetime.strptime(date_time, '%b %d %Y %I:%M%p')
num_of_attendees = request.data.get('num_of_attendees')
tables = Table.objects.filter(~Q(
tablereservation__date_time__range=[date_time, date_time + timedelta(hours=2)]),
num_of_chairs__gte=num_of_attendees
)
...
But it returns all the table objects.
My models,
class Table(models.Model):
""" Holds table details """
num_of_chairs = models.PositiveSmallIntegerField(default=1)
def __str__(self):
return str(self.id)
class TableReservation(models.Model):
""" Holds table reservation details """
date_time = models.DateTimeField()
table = models.ForeignKey(Table, on_delete=models.CASCADE)
user = models.ForeignKey(User, on_delete=models.CASCADE)
def __str__(self):
return '{}-{}'.format(self.table, self.user)
But I want is to get only the table objects that aren't reserved in the given date-time range. Any help is greatly appreciated.
~Q is negation of Q expression.
I.E. ~Q is NOT Q
Are you sure you want ~Q?
Also, the issue is likely due to how __range interacts with DateTimeField.
See the documentation here:
Range (I just ran into this issue yesterday, the issue will cause your query to always be empty on the final day of the range which your query is always for the final day of the range!)
You could try:
start_time = date_time
end_time = date_time + timedelta(hours=2)
tables = Table.objects.filter(
tablereservation__date_time__gte=start_time, tablereservation__date_time__lte=end_time).filter(num_of_chairs__gte=num_of_attendees)

How can I covert sqlachemy query into list object? [duplicate]

This question already has answers here:
How to serialize SqlAlchemy result to JSON?
(37 answers)
Closed 1 year ago.
hi guys I am trying to convert my query into object but I am getting this error " 'User' object is not iterable"
Below are my codes.
#app.route('/users')
def users():
rows = db.session.query(User).first();
for row in rows:
data.append(list(row))# data.append([x for x in row])
return jsonify(data)
The code you have for querying
rows = db.session.query(User).first();
selects the first object found and returns it, else returns None as per docs
if there are multiple rows you are trying to query, use the .all() function as per docs
data = []
rows = db.session.query(User).all();
for row in rows:
data.append(row)
return jsonify(data)
this will fetch all the users and add it to the list
I was able to do this buy using flask mashmallow
ma = Marshmallow(app)
enter code here
class User(db.Model):
id = db.Column(db.Integer,primary_key=True)
name = db.Column(db.String(200),nullable=False)
email = db.Column(db.String(200),nullable=False)
password = db.Column(db.String(200),nullable=False)
class UserSchema(ma.Schema):
class Meta:
# Fields to expose
fields = ("email", "password","name")
# Smart hyperlinking
user_schema = UserSchema()
users_schema = UserSchema(many=True)
#app.route("/users/")
def users():
#row= db.session.query(User)
all_users = User.query.all()
results = users_schema.dump(all_users)
return jsonify(results)
#app.route("/users/<id>")
def user_detail(id):
user = User.query.get(id)
results = user_schema.dump(user)
return jsonify(results)

flask sqlalchemy one-to-many filter, count & grouping

I am currently trying to build a query which
give me for a one-to-many sqlalchemy query in flask both my result filters grouped and then says how many individual entries there are for it
Following is my database model to illustrate the question:
class cellphone(db.Model):
__tablename__ = 'cellphone'
id = db.Column(db.Integer, primary_key = True)
number = db.Column(db.String(30), unique=True)
sms = db.relationship('sms_accounting', backref="cellphone", lazy='dynamic')
class sms_accounting(db.Model):
__tablename__ = 'sms_accounting'
id = db.Column(db.Integer, primary_key = True)
timestamp = db.Column(db.DateTime, index=True, default=datetime.utcnow)
cellphone_id = db.Column(db.Integer, db.ForeignKey('cellphone.id'))
What I want to do now is find out how many SMS were sent within X days per number.
Filtering and grouping I managed to do, but to calculate the sum per device correctly is not possible.
def sms_count():
search_peroid='90' #time to fetch events in days
period_start = datetime.utcnow() - timedelta(hours=int(search_peroid))
phone_count = sms_accounting.query.filter(sms_accounting.timestamp.between(period_start, \
datetime.utcnow() )).group_by(sms_accounting.cellphone_id).all()
I found some examples for func.count, but unfortunately none of them works. This already starts with the usage,
AttributeError: BaseQuery object has no attribute 'func'
even though it was imported especially.
from sqlalchemy.sql.functions import func
Forgive me if I am wrong.
As an option, you could try executing an SQL Query through Flask.
db.session.execute('select number, count(sms_accounting.id) from cellphone join sms_accounting on sms_accounting.cellphone_id = cellphone.id');
You can easily add the time based filter using where.
Regarding the AttributeError, are you sure you are using the 'func' method properly? The correct usage can be found on this unrelated answer at https://stackoverflow.com/a/4086229/4854064. It might be that you accidentally called func as a method of the query object.

How to implement "contain any" in flask/sqlalchemy?

The contains operation in SQLAlchemy only accepts one Model object instead of a list of objects. If I want to create a filter that accepts containing any of a group of objects, is there a more SQL-style way than creating multiple filters using contains and combining them with union?
For example, see the following code:
from flask import Flask
from flask.ext.sqlalchemy import SQLAlchemy
app = Flask(__name__)
db = SQLAlchemy(app)
class User(db.Model):
id = db.Column(db.Integer, primary_key = True)
name = db.Column(db.String(100))
son = db.relationship('Son', backref = 'parent', lazy = 'dynamic')
def __repr__(self):
return '<"%s">' % self.name
class Son(db.Model):
id = db.Column(db.Integer, primary_key = True)
name = db.Column(db.String(1000))
user_id = db.Column(db.Integer, db.ForeignKey('user.id'))
def __repr__(self):
return '<"%s">' % self.name
db.create_all()
son1 = Son(name = '1 a 1')
son2 = Son(name = '1 b 1')
son3 = Son(name = '1 c 1')
son4 = Son(name = '2 a 2')
son5 = Son(name = '2 b 2')
user0 = User(name = 'w1')
user1 = User(name = 'w2')
user2 = User(name = 'w3')
user0.son.append(son1)
user0.son.append(son2)
user1.son.append(son3)
user1.son.append(son4)
user2.son.append(son5)
db.session.add(son1)
db.session.add(son2)
db.session.add(son3)
db.session.add(son4)
db.session.add(son5)
db.session.add(user0)
db.session.add(user1)
db.session.add(user2)
db.session.commit()
son_query = Son.query.filter(Son.name.ilike('%a%'))
son_query_all = son_query.all()
print son_query.all()
user_query = User.query.filter(User.son.contains(son_query_all[0])).union(*[User.query.filter(User.son.contains(query)) for query in son_query_all[1:]])
print user_query.all()
The example firstly creates two models: User and Son, and then creates 3 User instances and 5 Son instances. user0 contains son1 and son2, user1 contains son3 and son4, and user2 contains son5. Note that the name of son1 and son4 are both like %a%. Now I want to select all User instances containing Son instances whose name likes %a%.
The current method is to select all Son instances in son_query_all, and then selects User instances containing individual desired Son instances, and then combines the selecting result using union. Is there a more SQL-style way for SQLAlchemy to select the same? For example, is there anything like contains_any so that the last query can be changed into something like
user_query = User.query.filter(User.son.contains_any(son_query_all))
Note that of course I can define a custom contains_any function for the same purpose using the union and contains operation. My question is whether there is a more efficient way than simply union all contains-ed?
The correct way to solve this kind of filtering is to use JOIN. Basically you join Son table with User table and filter by joined entity's field.
In SQLAlchemy you can express it like this:
User.query.join(Son).filter(Son.name.ilike('%a%'))
And it will produce following SQL:
SELECT * FROM user
JOIN son ON user.id = son.user_id
WHERE lower(son.name) LIKE lower('%a%')

Turbogears2 AdminController throwing an error with a many-to-many relationship

I'm having an issue with turbogears admin controller throwing an error when I try to edit the User, ShoppingItem or ShoppingList items (code below). The error coming up is AttributeError: 'function' object has no attribute 'primary_key'. The Local Variables in frame always come back as the same:
mapper
<Mapper at 0x3719810; ShoppingList>
fields
['id']
self
<sprox.sa.provider.SAORMProvider instance at 0x03E537B0>
value
<bound method OrderedProperties.items of <sqlalchemy.util._collections.OrderedProperties object at 0x037199F0>>
entity
<class 'insertmealhere.model.shoppinglist.ShoppingList'>
field_name
'items'
I'm having trouble figuring out what is different between this and the other many-to-many relationships that are configured elsewhere in the code and are not throwing this error. I'm running Turbogears 2.2 on Python 2.7.8 currently on a windows 8.1 system. Any help is greatly appreciated.
list_item_table = Table("list_item_table", metadata,
Column('item_id', Integer, ForeignKey('shopping_item.id', onupdate="CASCADE", ondelete="CASCADE"), primary_key=True),
Column('list_id', Integer, ForeignKey('shopping_list.id', onupdate="CASCADE", ondelete='CASCADE'), primary_key=True))
class ShoppingItem(DeclarativeBase):
__tablename__ = "shopping_item"
id = Column(Integer, primary_key=True)
name = Column(String(50))
quantity = Column(String(5))
measure = Column(String(10))
# less important optional parameters that will be useful for users
brand = Column(String(50))
list_id = Column(Integer, ForeignKey('shopping_list.id'))
shopping_list = relation("ShoppingList", secondary=list_item_table, backref="items")
def get_owner_id(self):
return self.list.user_id
#classmethod
def delete_list(cls, id, user_id):
item = DBSession.query(cls).filter_by(id=id).one() # get the item from the given ID
if item.get_owner_id() == user_id: # owned by current user
DBSession.delete(item) # delete from shopping list
return True
flash(_("You do not have authorization to perform that action."))
return False
class ShoppingList(DeclarativeBase):
__tablename__ = 'shopping_list'
id = Column(Integer, primary_key=True)
date = Column(Date, index=True, nullable=False)
static = Column(Boolean, nullable=False, default=False)
# static is true if the items from the meal plan have been imported into the shopping list. Once done you can edit
# the items in the shopping list, remove items, etc. Until the shopping list is made static it is impossible to edit
# the items that are imported from the schedule as they do not exist in the shopping list! (and we do not want to
# edit them in the recipe!
user_id = Column(Integer, ForeignKey('tg_user.user_id'))
user = relation("User", backref="shopping_lists")
date_user_list = Index('date_user_list', 'date', 'user_id')
Maybe it's the list_id = Column(Integer, ForeignKey('shopping_list.id')) in the ShoppingItem model class that's confusing SQLAlchemy?