sqlalchemy primary key without auto-increment - python

I'm trying to establish a table with a layout approximately like the following:
class Widget(db.Model):
__tablename__ = 'widgets'
ext_id = db.Column(db.Integer, primary_key=True)
w_code = db.Column(db.String(34), unique=True)
# other traits follow...
All field values are provided through an external system, and new Widgets are discovered and some of the omitted trait values may change over time (very gradually) but the ext_id and w_code are guaranteed to be unique. Given the nature of the values for ext_id it behaves ideally as a primary key.
However when I create a new record, specifying the ext_id value, the value is not used in storage. Instead the values in ext_id follow an auto-increment behavior.
>>> # from a clean database
>>> skill = Widget(ext_id=7723, w_code=u'IGF35ac9')
>>> session.add(skill)
>>> session.commit()
>>> Skill.query.first().ext_id
1
>>>
How can I specify to SQLAlchemy that the ext_id field should be used as the primary key field without auto-increment?
Note:
I could add an extra synthetic id column as the primary key and make ext_id be a unique column instead but this both complicates my code and adds a (minimal) extra bloat to the database and all I/O to it. I'm hoping to avoid that.
Issue originated from a larger project but I was able to create a smaller repro.
Testing with sqlite

Set autoincrement=False to disable creating a sequence or serial for the primary key.
ext_id = db.Column(db.Integer, primary_key=True, autoincrement=False)

Related

How to construct table in postgreSQL

__tablename__ = "user_ingredients"
ingred_id = db.Column(db.Integer, db.ForeignKey('ingredients.ingred_id'), nullable=False)
user_id = db.Column(db.Integer, db.ForeignKey('users.user_id'), nullable=False)
ingred_id and user_id are variables in the class UserIngredient. How do i create the table user_ingredients in postgreSQL as im not sure how to do it when its like ingredients.ingred_id. On searching internet something about foreign keys was mentioned but this is first time im using postgreSQL so i dont know how to use that
What you are describing is a basic M:M relationship between tables USERS and INGREDIENTS. The table USER_INGREDIENTS the is the resolution between them. Any additional attributes then describe the particular attributes for a specific combination of user and ingredient.
create table users( user_id integer generated always as identity
, name text
--other columns
, constraint users_pk primary key (user_id)
);
create table ingredients( ingredient_id integer generated always as identity
, name text
--other columns
, constraint ingredients_pk primary key (ingredient_id)
);
create table user_ingredients( user_id integer
, ingredient_id integer
, quantity number -- for example
, measurement_type text -- for example
, quantity_description text -- for example
, constraint user_ingredients_pk
primary key (user_id, ingredient_id)
, constraint user_ingredients_2_user_fk
foreign key (user_id)
references users(user_id)
, constraint user_ingredients_2_ingredients_fk
foreign key (ingredients_id)
references ingredients(ingredients_id)
);
);
As indicated the above is pretty basic to any relational database. I suggest you invest some time ( references and tutorials) understanding them, even if you will only work with teem through an obfuscation (ORM) layer.

How to fix 'Invalid input syntax for integer' issue while using sqlalchemy Declarative API

I'm actually building a little utils which aims to take flat csv/excel file and populate a target database on MS Access - as I'm working on a Mac, i'm developping it using Postgres...
So I developped a part which deals with messy input (csv/excel) forms (several heading, etc) but that's not my issue at the moment.
On the other hand, I made my Database model using SQLAlchemy Declarative Base API.
I'm facing issue when importing data in some tables:
- Split flat record to several objects
- Check (SELECT) if the record doesn't exists yet based on uniqueness contraints
- If it doesn't exists I create object else I use the existing one
- Propagate keys information to related object
For some tables I'm using the auto_increment arguments but sometimes the record has its own ID (in input file) so I should it for insert/select in my tables and sometimes no ID so I have to create a new technical Id for my table.
Example: I have a record with for primary key -obsr25644- and sometimes nothing so I use a default value created with uuid.
So below the stacktrace when doing selectoperation on a my table. The same error occurs when working on existing data - obsr25644 - and generated uuid - 'a8098c1a-f86e-11da-bd1a-00112444be1e'
sqlalchemy.exc.DataError: (psycopg2.errors.InvalidTextRepresentation) **invalid input syntax for integer**: "obsr25644"
LINE 3: WHERE "Location"."Id_observer" = 'obsr25644'
As you can see below, "Location"."Id_observer" is declared as String(255). I don't understand why the error is related to 'integer'.
[SQL: SELECT "Location"."Id_location" AS "Location_Id_location", [...], "Location"."Id_observer" AS "Location_Id_observer",
FROM "Location"
WHERE "Location"."Id_observer" = %(Id_observer_1)s
LIMIT %(param_1)s]
[parameters: {'Id_observer_1': 'obsr25644', 'param_1': 1}]
class LocationModel(UniqueMixin, Base):
__tablename__ = 'Location'
# Primary key
Id_location = Column(Integer, primary_key=True, autoincrement=True)
[...]
Id_observer = Column(String(255), ForeignKey('Observer.Id_observer'))
observer = relationship("ObserverModel", load_on_pending=True, back_populates="location")
class ObserverModel(UniqueMixin, Base):
__tablename__ = 'Observer'
# Primary key
Id_observer = Column(String(255), primary_key=True, default=UniqueMixin.unique_hash())
[...]
# Relationship
location = relationship("LocationModel", load_on_pending=True, back_populates="observer")
Note :UniqueMixin.unique_hash() returns uuid.uuid4().hex

Database Design for Arbitrary User Submitted Database "Objects"

I am working on a database software for a user with a need to store generic "objects" and associated information. (With a web interface, to abstract the SQL)
First, what I mean by "object", in this situation, is an "thing" that can be defined by an arbitrary amount of input fields, for example:
A "Customer" object might be defined by
Name
Phone Number
Email
Company
etc...
These objects are to be designed by the User. Therefore, I need a way to define an arbitrary object in SQL.
The solution I have come up with so far is something along the lines of this:
CREATE TABLE object_name
(
p_key SERIAL PRIMARY KEY,
name varchar UNIQUE NOT NULL
);
CREATE TABLE field_type
(
p_key SERIAL PRIMARY KEY,
type varchar UNIQUE NOT NULL
);
CREATE TABLE field_name
(
p_key SERIAL PRIMARY KEY,
name varchar UNIQUE NOT NULL
);
CREATE TABLE object
(
object_name_id integer REFERENCES object_name (p_key),
field_type_id integer REFERENCES field_type (p_key),
field_name_id integer REFERENCES field_name (p_key),
PRIMARY KEY (object_name_id, field_type_id, field_name_id)
);
The basic idea is to use a junction table to define the amount/type of fields being used to define the object. (This is just an extremely basic example)
I have a few problems that I am running into with this solution.
The user wants the field of an object to reference another object. For example, in the "Customer" example I showed earlier, the "Company" field would likely be a selection from a list of "Company" objects. This causes an issue, because a situation can be imagined where "Company" would also have a field referencing "Customer". Meaning, there would be circular referencing... which object would be created first?
Is using SQL for defining the objects even a reasonable approach? Or would defining an object be better suited to XML files?
Assuming the objects can be arbitrarily defined, what would be the best way of storing instances of the arbitrary objects?
Any breadcrumbs would be helpful. Sidenote: I was thinking about using Django and postgresql as the framework.
Thank you.

How to achieve that every record in two tables have different id?

I have two tables inherited from base table ( SQLALCHEMY models)
class Base(object):
def __tablename__(self):
return self.__name__.lower()
id = Column(Integer, primary_key=True, nullable=False)
utc_time = Column(Integer, default=utc_time(), onupdate=utc_time())
datetime = Column(TIMESTAMP, server_default=func.now(), onupdate=func.current_timestamp())
and inherited tables Person and Data
How to achieve that every Person and Data have different id, every id to be unique for two tables ? ( Person when generate of id to be aware of Data ids and vice versa)
if you're using Postgresql, Firebird, or Oracle, use a sequence that's independent of both tables to generate primary key values. Otherwise, you need to roll some manual process like an "id" table or something like that - this can be tricky to do atomically.
Basically if I were given this problem, I'd ask why exactly would two tables need unique primary key values like that - if the primary key is an autoincrementing integer, that indicates it's meaningless. It's only purpose is to provide a unique key into a single table.

SQLAlchemy one-to-many without the child table having a primary key

Is it possible to create a table without a primary key in SQLAlchemy? The relationship I want to define is as follows:
class TPost(Base):
__tablename__ = "forum_post"
id = Column(Integer, primary_key = True)
topic_id = Column(Integer, ForeignKey("forum_topic.id"))
index = Column(Integer)
page = Column(Integer)
user_id = Column(Integer, ForeignKey("forum_user.id"))
posted_at = Column(DateTime)
post_text = Column(String)
has_quotes = Column(Boolean)
quotes = relationship("TQuote")
class TQuote(Base):
__tablename__ = "forum_quotes"
id = Column(Integer, ForeignKey("forum_post.id"))
is_direct = Column(Boolean)
quoted_text = Column(String)
quoted_id = Column(Integer)
As you can see I don't really need a primary key, and I don't intend to extend the Quote relationship in the future.
My problem specifically is represented by this error message :
sqlalchemy.exc.ArgumentError: Mapper Mapper|TQuote|forum_quotes
could not assemble any primary key columns for mapped table 'forum_quotes'
edit :
The (id,quoted_id) pair is unique, and it present for the majority of the data, however when the quote is not direct(and doesn't have a quoted_id in that case), I inline the quoted text directly into the quote relationship. I could use a dual table approach (where the indrect quotes have a table with a primary key), but I'd really rather implement this as a single one-to-many relationship. I don't want to have to do more than a single join.
edit 2:
I'll number the quotes and use the foreign-key + app generated number as a pkey, still annoying tho. Now to figure out the syntax.
edit 3:
Solved the problem as outlined in edit 2. Quite annoyed with sql alchemy since it has all the information it needs to implement the relatioship even when modelling the data at a high level. I understand the reasons why Sql Alchemy wants to have a primary key (makes the orm easier to implement).
I am beginning to question why I am using Sql Alchemy, without it I could implement one way UPSERT or CREATE_IF_NOT_EXIST asynchronous operations using psycopg2. ORM's really need to catch up.
I am assuming #TokenMacGuy is right, and you really are confusing the notions of PrimaryKey, and a surrogate key. In which case the answer to your question is:
NO, SA does not support tables (and therefore relations to tables) without a primary key
and NO, you do not need to create a surrogate key for each table for the purpose of serving as a primary key. You can define a PK using any combination of columns with are unique.
See the code below for an example:
class TPost(Base):
__tablename__ = 'forum_post'
id = Column(Integer, primary_key = True)
post_text = Column(String)
quotes = relationship("TQuote", backref="post")
class TQuote(Base):
__tablename__ = "forum_quotes"
id = Column(Integer, ForeignKey("forum_post.id"))
is_direct = Column(Boolean)
quoted_text = Column(String)
quoted_id = Column(Integer)
__table_args__ = (PrimaryKeyConstraint(id, quoted_id),)
Add an additional column to give the quotes a index, and then add make a composite key of this new column + the foreign key.

Categories

Resources