I am trying to create objects with a primary integer key, but when using fastAPI, I cannot get the keys to autogenerate. The validator says an ID needs to be passed in to pass validation, which makes sense, but I want to instead have an autokey each time a new object is created. How does one do this?
class PinSchema(BaseModel): id: Optional[int] = Field(primary_key=True)
class PinSchema(BaseModel):
id: Optional[int] = Field(primary_key=True)
//some other fields here
class Config:
allow_population_by_field_name = True
arbitrary_types_allowed = True
This is my current model for the object. I set the int to optional, but now it just has the default as null, not the autogen int.
I tried to set the field as optional, but it just defaults to null even after I set the default to a primary key field. I also tried just leaving it as int = Field(primary_key=True), but no luck, it fails the validation. Is there a way to exclude the id field from the validation process with fastAPI?
Related
I am learning fastapi and I've created a model in models.py as follows:
class Post(Base):
__tablename__ = "posts"
id = Column(Integer, primary_key=True, nullable=False)
title = Column(String, nullable=False)
content = Column(String, nullable=False)
published = Column(Boolean, server_default='TRUE')
created_at = Column(TIMESTAMP(timezone=True), nullable=False, server_default=text('now()'))
I have mentioned id as int but it is auto incrementing like serial and also serial is automatically set to default. Even if I am passing id from postman it is still getting auto incremented and discarding my sent value.
You have to explicitly disable the autoincrement functionality - an integer primary key without a default value will usually have autoincrement functionality added automagically:
The default value is the string "auto", which indicates that a single-column (i.e. non-composite) primary key that is of an INTEGER type with no other client-side or server-side default constructs indicated should receive auto increment semantics automatically.
Instead, set the autoincrement argument explicitly to False:
False (this column should never have auto-increment semantics)
I'm trying to use jOOQ's metadata API, and most columns behave the way I'd expect, but enum columns seem to be missing type and nullability information somehow.
For example, if I have a schema defined as:
CREATE TYPE public.my_enum AS ENUM (
'foo',
'bar',
'baz'
);
CREATE TABLE public.my_table (
id bigint NOT NULL,
created_at timestamp with time zone DEFAULT now() NOT NULL,
name text,
my_enum_column public.my_enum NOT NULL,
);
The following test passes:
// this is Kotlin, but hopefully pretty easy to decipher
test("something fishy going on here") {
val jooq = DSL.using(myDataSource, SQLDialect.POSTGRES)
val myTable = jooq.meta().tables.find { it.name == "my_table" }!!
// This looks right...
val createdAt = myTable.field("created_at")!!
createdAt.dataType.nullability() shouldBe Nullability.NOT_NULL
createdAt.dataType.typeName shouldBe "timestamp with time zone"
// ...but none of this seems right
val myEnumField = myTable.field("my_enum_column")!!
myEnumField.dataType.typeName shouldBe "other"
myEnumField.dataType.nullability() shouldBe Nullability.DEFAULT
myEnumField.dataType.castTypeName shouldBe "other"
myEnumField.type shouldBe Any::class.java
}
It's telling me that enum columns have Nullability.DEFAULT regardless of whether they are null or not null. For other types, Field.dataType.nullability will vary depending on whether the column is null or not null, as expected.
For any enum column, the type is Object (Any in Kotlin), and the dataType.typeName is "other". For non-enum columns, dataType.typeName gives me the correct SQL for the type.
I'm also using the jOOQ code generator, and it generates the correct types for enum columns. That is, it creates an enum class and uses that as the type for the corresponding fields, which are marked as not-nullable. The generated code for this field looks something like (reformatted to avoid long lines):
public final TableField<MyTableRecord, MyEnum> MY_ENUM_COLUMN =
createField(
DSL.name("my_enum_column"),
SQLDataType.VARCHAR
.nullable(false)
.asEnumDataType(com.example.schema.enums.MyEnum.class),
this,
""
)
So it appears that jOOQ's code generator has the type information, but how can I access the type information via the metadata API?
I'm using postgres:11-alpine and org.jooq:jooq:3.14.11.
Update 1
I tried testing this with org.jooq:jooq:3.16.10 and org.jooq:jooq:3.17.4. They seem to fix the nullability issue, but the datatype is still "other", and the type is still Object. So it appears the nullability issue was a bug in jOOQ. I'll file an issue about the type+datatype.
Update 2
This is looking like it may be a bug, so I've filed an issue.
I am using flask-mongoalchemy to do a demo, and here is a question confused me for a while.
At first I create a class User
class Student(db.Document):
'''student info'''
name = db.StringField()
grade = db.IntField(required=False, default=None)
Then, I use this DB and create some example, such as student1, student2...and so on。
Now, I change the default value of grade from None to 0
grade = db.IntField(required=False, default=0)
When I run query again, it raise error:
mongoalchemy.exceptions.BadValueException: Bad value for field of type "grade". Reason: "Value is not an instance of <class 'int'>
SO, how to auto-update this field change? What I did now is to modify the value of age in database manualy.
First, to get the queries working as before set allow_none option on the field to True.
grade = db.IntField(required=False, default=0, allow_none=True)
That should allow documents having no value for grades to not trigger errors when unwrapped as python objects.
Next, make a migration that sets the default value for documents where grade is None to 0.
from mongoalchemy.session import Session
with Session.connect('mongoalchemy') as s:
update = s.query(Student).filter(Student.grade == None).set(User.grade, 0)
update.execute()
Lastly, switch the field declaration back to disallow None values for the grade.
I have the following class that represents a record in postgresql:
case class Action(id: Option[Int], EmailAct: String, carriedAt: Timestamp)
id is an auto-increment field and carriedAt defaults to CURRENT_TIMESTAMP. How do I tell Slick I only want to provide value for EmailAct and the rest should be defaults?
This does not quite work: Dbs.actionsLog += Action(null, "test", null) - id gets auto-incremented but carriedAt becomes empty, not default.
insert into a query that selects what you want to update:
Dbs.actionsLog.map(_.EmailAct) += "test"
I have a model:
case class MyModel(
id: Pk[Long] = NotAssigned,
startsAt: Option[DateTime] = None,
addedAt: Option[DateTime] = None
)
object MyModel {
// .....................
SQL("""
INSERT INTO my_table(starts_at)
VALUES ({startsAt})
"""
).on('startsAt -> newItem.startsAt).executeInsert()
}
Both startst_at and added_at have a default value of now() in Postgresql and don't allow null values in them. It doesn't cause any error for addedAt (because I never pass it to the server from the client) but it does cause the error for startsAt if it's not specified at newItem.startsAt and, thus, is equal to None and, thus, it's being passed as null.
org.postgresql.util.PSQLException: ERROR: null value in column "starts_at" violates not-null constraint
What I want is be able to specify startsAt whenever I want it and pass it to the server, meaning if I specify it then that value should be passed to the server, if not - nothing should be passed and the server should use its default value now(). I don't want to specify the default value at the client because it's already set at the server at the db level.
How about this SQL fix:
insert into my_table(starts_at)
values (COALESCE({startsAt}, now())
Updated: requirement is to use the default value of the column
The only way that I know of to get the server to use the default value of a column in an insert, is not to mention that column in the columns list. For example (not tested):
startsAt.map { date =>
SQL("""insert into my_table(starts_at) values({startsAt})""")
.on('startsAt -> date)
.execute()
}.orElse {
SQL("""insert into my_table() values()""")
.execute()
}