django migrate primary OneToOneFiled ForeignKey + into composite foreign key - mysql

I've a model which is just a relation between two entities like this:
class SomeModel(models.Model):
a = OneToOneField(User,primary_key=True,...)
b = ForeignKey(Car,...)
As per design, it was correct, as I didn't want an User to have multiple Car. But in my new design, I want to accept multiple Car to an User. So I was trying something like this:
class SomeModel(models.Model):
class Meta:
unique_together = (("a", "b"),)
a = ForeignKey(User,...)
b = ForeignKey(Car,...)
But during migration, it asks me:
You are trying to add a non-nullable field 'id' to somenmodel without a default; we can't do that (the database needs something to populate existing rows).
Please select a fix:
1) Provide a one-off default now (will be set on all existing rows with a null value for this column)
2) Quit, and let me add a default in models.py
Select an option:
I just wanted to remove that foreign key from OneToOneRelation and add a new id combining both. - How to resolve this?

Delete the model and table from the database and create a new model from starting or add null=True to the given field. you must be having some data (rows) in your table and now you are creating a new column, so previous rows need something to be there in the newly created column, writing null = True will do that.

Related

SqlAlchemy db.metadata.create_all - does not create table when __bind_key__ has been specified?

When I create a class (Table), and I specify the bind_key = "bindingname" the table is not created using this method:
db.metadata.create_all(db.engines["bindingname"])
however, when I remove the bind_key property from the table class, the table is indeed created, however it will get created in all my bindings ...
how can i specify bind_key in a class table definition and then ensure that the table is created only in the specified database?
Aha, managed to get it working like this.
Example of class
from models.Models import db
class V3_Output_Binned(db.Model):
__bind_key__ = "output_v3"
__tablename__ = "V3_Output_Bin"
Example of how and where to create the missing tables, I need to do this since there is one database (binding) that I do not want to have table schemas auto created.
db.init_app(app)
#app.before_first_request
def create_table():
#db.create_all()
with app.app_context():
db.create_all(bind_key="default")
db.create_all(bind_key="output")
db.create_all(bind_key="output_v3")
If you need more information - having the same issue, let me know and I will give advice.

SQLAlchemy many-to-many relationship deletion operation on one side

I have a many-to-many relationship linked by an association table, like this:
left_right_association_table = Table("left_right_association_table", Base.metadata,
Column('leftside_id', Integer, ForeignKey('leftside_table.id')),
Column('rightside_id', Integer, ForeignKey('rightside_table.id'))
)
class LeftSide(Base):
...
rightside_members = relationship("RightSide", secondary=left_right_association_table, backref="leftside", lazy="joined")
...
class RightSide(Base):
...
Now I have a LeftSide instance, with a list of RightSide instances as its rightside_members attribute:
ls = LeftSide(**kw)
rs1 = RightSide(**kw)
rs2 = RightSide(**kw)
ls.rightside_members.append(rs1)
ls.rightside_members.append(rs2)
Then, I want to drop one of the list member: rs2.
Step 1: I reproduce the rightside_members list:
updated_rightside_members = [RightSide(**rs_attrs) for rs_attrs in ls.rightside_members] # each `rs` object already has primary key
updated_rightside_members.pop() # remove the second item from the list
Step 2: I retrieve the ls from the database:
old_ls = db_session.query(LeftSide).filter(LeftSide_id == ls.id).one()
Step 3: I tack the updated_rightside_members onto the old_ls:
old_ls.rightside_members = updated_rightside_members
Step 4: commit to database.
db_session.commit()
Then I get this Error:
sqlite3.IntegrityError: UNIQUE constraint failed: rightside_table.id
It seems to me that SQLAlchemy is thinking that I'm trying to put a duplicate rs1 back into the database, instead of deleting its brother rs2 from the database.
How should I do this deletion operation?
I've solved this problem. First I really want to point out that reading carefully the documentation helps. Using mapped class to initialize an instance doesn't mean the session knows about this object, at least not until you use Session.add() method.
So, the proper steps should be like this:
decide whether the incoming args contain a id which represent the instance primary key. If it does, then instead of initialize it, the right way to do is to query it from the database. This way the Session will ensure that the queried object has a unique object id in its identity map.
if it doesn't contain an id attribute, then initialize it, and add it to the member list.

Alembic default value to be used in add_column

How do I get alembic to use a specified default value for a new column, without making it the server_default?
Only the existing rows should receive this default value. New rows inserted after should still get server_default.
You have to use server_default, but you need to pass the value as string in the same format your database deals with it.
https://docs.sqlalchemy.org/en/13/core/metadata.html#:~:text=server_default%20%E2%80%93,server%20side%20defaults
For example:
op.add_column('users', sa.Column('created_at', sa.DateTime(), nullable=False, server_default=str(datetime.now())))
Check what miguelgrinberg said here:
https://github.com/miguelgrinberg/Flask-Migrate/issues/265#:~:text=The%20server_default%20should%20be%20given%20as%20text%20in%20the%20native%20format%20of%20the%20database%2C%20not%20as%20a%20Python%20type.%20See%20https%3A//docs.sqlalchemy.org/en/13/core/metadata.html%23sqlalchemy.schema.Column.params.server_default.
I had a similar problem, I wanted a new column to be not nullable, which does not work for existing rows, of course. So I created the row without not null constraint first, filled the column with some custom python code and than altered the column (in the same migration) to have the constraint.
So you'd iterate over the existing objects, set the values according to the transient default.

How to increment primary key without using Auto Increment in MySql

I am having a table called Tl which consists of fields ID,Name and Course.
In my view when i click ADD DETAILS button i should be able to fill name and course and save it DB.
Here my ID is primary key.But i am not using AutoIncrement for this field.Without using increment option i should be able to save the newly added values.
Can any one suggest me how to implement this using linq query.
Thanks!
I'll suppose that you're using EntityFramework
var dbMaxId = context.TIs..Max(m => (int?) m.ID);
model.ID = dbMaxId + 1;

auto generate in LINQ to SQL

I have a table whit 2 columns , ID and name .I set 'YES' Identity for ID column .
I want to insert data to table whit LINQ .I want to get only name column from user in my application , and then ID column fill automatic to database and I can't give data that column and fill whitout I give it .
What should I do ?
I write in c# and work whit LINQ .
So your database field already is a INT IDENTITY - right?
Next, in your LINQ to SQL designer, you need to make sure your column is set to:
Auto Generated Value = TRUE
Auto-Sync = ON INSERT
Now if you add an entry to your database, the ID will be automatically updated from the value assigned to it by the database:
YourClass instance = new YourClass();
instance.Name = "some name";
YourDataContext.InsertOnSubmit(instance);
YourDataContext.SubmitChanges();
After the SubmitChanges call, your instance.ID should now contain the ID from the database.
If you used the DBML designer, that should be setup correctly.
The 'id' will be populated after you call SubmitChanges.
Make sure your database table is setup correctly and that your ID is set as the primary key field and to auto increment. Regenerate your DBML if you need to by deleting the object and re-adding it. It should know that the ID is not needed and the auto fill it once the insert has succeeded.