How to create integer of a certain length with Sqlalchemy? - python

I've tried two approaches and both are not working, I searched on Google and didn't find any proper solutions. My code looks like:
intField = Column(SmallInt(), length=5)
And the error says:
Unknown arguments passed to Column: ['length']
I also tried, knowing it shouldn't work, this solution:
intField = Column(SmallInt(5))
And it does not work because this SqlAlchemy datatype doesn't accept arguments.
Any ideas?
[Update]
I'm using MySQL as database engine, so the solution here is to import mysql's own Integer type, and then specify the length I want it to be.
In the above example, I would only need to do:
from sqlalchemy.dialects import mysql
Integer = mysql.INTEGER
class ...
...
intField = Column(Integer(5))
But I still wonder if there is a more generic approach?

MySQL has the DECIMAL/NUMERIC type.
Use Decimal(5, 0) to a field with 5 digits.
Use this only if you really need a number. If won't do math with this field, prefer a String(5) and validate the digits (isdigit() is your friend).
In SQLAlchemy, handle it as a Numeric field.

Related

Python Formatting SQL WHERE clause

I'm having this function that communicates via pymysql to an SQL database stored to my localhost. I know there are similar posts about formatting an SQL section especially this one but could anyone suggest a solution?
Always getting TypeError: can't concat tuple to bytes. I suppose it's sth with the WHERE clause.
def likeMovement(pID):
print("Give a rating for the movement with #id:%s" %pID)
rate=input("Give from 0-5: ")
userID=str(1)
print(rate,type(rate))
print(pID,type(pID))
print(userID,type(userID))
cursor=con.cursor()
sqlquery='''UDPATE likesartmovement SET likesartmovement.rating=%s WHERE
likesartmovement.artisticID=? AND likesartmovement.userID=?''' % (rate,),
(pID,userID)
cursor.execute(sqlquery)
TypeError: not all arguments converted during string formatting
Thanks in advance!
The problem is that you're storing (pID,userID) as part of a tuple stored in sqlquery, instead of passing them as the arguments to execute:
sqlquery='''UDPATE likesartmovement SET likesartmovement.rating=%s WHERE
likesartmovement.artisticID=? AND likesartmovement.userID=?''' % (rate,)
cursor.execute(sqlquery, (pID,userID))
It may be clearer to see why these are different if you take a simpler example:
s = 'abc'
spam(s, 2)
s = 'abc', 2
spam(s)
Obviously those two don't do the same thing.
While we're at it:
You have to spell UPDATE right.
You usually want to use query parameters for SET clauses for exactly the same reasons you want to for WHERE clauses.
You don't need to include the table name in single-table operations, and you're not allowed to include the table name in SET clauses in single-table updates.
So:
sqlquery='''UDPATE likesartmovement SET rating=? WHERE
artisticID=? AND userID=?'''
cursor.execute(sqlquery, (rating, pID, userID))

PostgreSQL UUID date type

I'm building a platform with a PostgreSQL database (first time) but I've experience with Oracle and MySQL databases for a few years now.
My question is about the UUID data type in Postgres.
I am using an UUIDv4 uuid to indentify a record in multiple tables, so the request to /users/2df2ab0c-bf4c-4eb5-9119-c37aa6c6b172 will respond with the user that has that UUID. I also have an auto increment ID field for indexing.
My query is just a select with a where clause on UUID. But when the user enters an invalid UUID like this 2df2ab0c-bf4c-4eb5-9119-c37aa6c6b17 (without the last 2) then the database responds with this error: Invalid input syntax for UUID.
I was wondering why it returned this because when you select on a integer-type with a string-type it does work.
Now I need to set a middleware/check on each route that has an UUID-type parameter in it because otherwise the server would crash.
Btw I'm using Flask 0.12 (Python) and PostgreSQL 9.6
UUID as defined by RFC 4122, ISO/IEC 9834-8:2005... is a 128-bit quantity ... written as a sequence of lower-case hexadecimal digits... for a total of 32 digits representing the 128 bits. (Postgresql Docs)
There is no conversion from a 31 hex digits text to a 128-bit UUID (sorry). You have some options:
Convert to ::text on your query (not really recommended, because you'd be converting every row, every time).
SELECT * FROM my_table WHERE my_uuid::TEXT = 'invalid uid';
Don't store it as a UUID type. If you don't want / need UUID semantics, store it as a varchar.
Check your customer input. (My recommendation). Conceptually, this is no different from asking for someone's age and getting 'ABC' as the response.
Postgres allows upper/lower case, and is flexible about use of hyphens, so a pre-check is simply strip the hyphens, lowercase, count [0-9[a-f] & if == 32, you have a workable UUID. Otherwise, rather than telling your user "not found", you can tell them, "not a UUID", which is probably more user-friendly.
The database is throwing an error because you're trying to match in a UUID-type column with a query that doesn't contain a valid UUID. This doesn't happen with integer or string queries because leaving off the last character of those does result in a valid integer or string, just not the one you probably intended.
You can either prevent passing invalid UUIDs to the database by validating your input (which you should be doing anyway for other reasons) or somehow trap on this error. Either way, you'll need to present a human-readable error message back to the user.
Also consider whether users should be typing in URLs with UUIDs in the first place, which isn't very user-friendly; if they're just clicking links rather than typing them, as usually happens, then how did that error even happen? There's a good chance that it's an attack of some sort, and you should respond accordingly.

Peewee execute_sql with escaped characters

I have wrote a query which has some string replacements. I am trying to update a url in a table but the url has % signs in which causes a tuple index out of range exception.
If I print the query and run in manually it works fine but through peewee causes an issue. How can I get round this? I'm guessing this is because the percentage signs?
query = """
update table
set url = '%s'
where id = 1
""" % 'www.example.com?colour=Black%26white'
db.execute_sql(query)
The code you are currently sharing is incredibly unsafe, probably for the same reason as is causing your bug. Please do not use it in production, or you will be hacked.
Generally: you practically never want to use normal string operations like %, +, or .format() to construct a SQL query. Rather, you should to use your SQL API/ORM's specific built-in methods for providing dynamic values for a query. In your case of SQLite in peewee, that looks like this:
query = """
update table
set url = ?
where id = 1
"""
values = ('www.example.com?colour=Black%26white',)
db.execute_sql(query, values)
The database engine will automatically take care of any special characters in your data, so you don't need to worry about them. If you ever find yourself encountering issues with special characters in your data, it is a very strong warning sign that some kind of security issue exists.
This is mentioned in the Security and SQL Injection section of peewee's docs.
Wtf are you doing? Peewee supports updates.
Table.update(url=new_url).where(Table.id == some_id).execute()

Can't find django auth user with PostgreSQL

from django.contrib.auth.models import User as DjangoUser
class Ward(models.Model):
user = models.ForeignKey(DjangoUser, related_name='wards')
group = models.ForeignKey(Group, related_name='wards')
This is my django model and I use this filter.
Group.objects.filter(wards__user=_user).all()
I used this code in sqlite3, it works well.
But, it doesn't work in PostgreSQL.
operator does not exist: character varying = integer
LINE 1: ...rchive_ward"."group_id" ) WHERE "archive_ward"."user_id" = 1
I think it is caused by user_id field in archive_ward tables.
I found this field's data type is character.varying(20).
What can I do for this code?
Try removing the user table in the database and adding it again.
create a new one from scratch. Syncing database again will work..
or else You can do like this Way raw_query
You cannot compare an integer with a varchar. PostgreSQL is strict and does not do any magic typecasting for you. I'm guessing SQLServer does typecasting automagically (which is a bad thing).
If you want to compare these two different beasts, you will have to cast one to the other using the casting syntax ::
The Postgres error means you're comparing an integer to a string:
operator does not exist: character varying = integer
You could change the database model so user_id is of an integer type. Or you could cast the integer to string in Python:
Group.objects.filter(wards__user=str(_user)).all()

How to get peewee result length

I use peewee orm in python.
I have a query that :
userOrganizations = (UserOrganization
.select(UserOrganization,Organization)
.join(Organization)
.where(UserOrganization.user==user.user_id)
.aggregate_rows()
)
I want to get length of userOrganizations variable. Is there any method like userOrganizations.length() ?
According to the peewee documentation you can use the count() function, i.e.:
userOrganizations.count()
If you're worried about maybe running extra DB queries, you can convert your result to a list and get the length, like:
len(list(userOrganizations))
Source for second technique: this question.

Categories

Resources