OneToOne Relationship with a foreign key on both sides - sqlalchemy

How can I define a OneToOne-relationship between two tables and have a foreign key on both sides? I know that it is redundant.
class A(Base):
__tablename__ = 'A'
id = Column(Integer, primary_key=True)
b_id = Column(Integer, ForeignKey('b.id'), unique=True, nullable=False)
b = relationship("B", uselist=False, back_populates="a")
class B(Base):
__tablename__ = 'B'
id = Column(Integer, primary_key=True)
a_id = Column(Integer, ForeignKey('a.id'), unique=True)
a = relationship("A", uselist=False, back_populates="b")
This results into an error:
sqlalchemy.exc.AmbiguousForeignKeysError: Could not determine join condition between parent/child tables on relationship ...
I found this duplicate to my question: SQLAlchemy one-to-one, store foreign key in each table? but the accepted answer is not an answer to the question. I only tells that normaly only one key is needed.

Related

Sqlalchemy union foreign key

I want to make table field (foreign key) that can reference to one of 2 tables: Dog or Cat.
I know it may be most likely implemented in PostgreSQL (via check) keyword (not a part of SQL standard), not a foreign key).
So I suppose it may be possible at other databases also via their private syntax.
Theoretically it may be done by Sqlalchemy even if some particular database not supporting a such functionality.
in Python code it looks like this:
# # # SCHEMAS.PY # # #
from dataclasses import dataclass
#dataclass
class Cat: ...
#dataclass
class Dog: ...
#dataclass
class review:
stars_value: int
entity: Cat | Dog
comment: str
# # # MODELS.PY # # #
from sqlalchemy import Column, Table, ForeignKey, Integer, String
from sqlalchemy.ext.declarative import declarative_base
Base = declarative_base()
cats = Table(
"cats",
Base.metadata,
Column("id", Integer, primary_key=True),
Column("name", String)
)
dogs = Table(
"dogs",
Base.metadata,
Column("id", Integer, primary_key=True),
Column("name", String),
)
review = Table(
"review",
Base.metadata,
Column("id", Integer, primary_key=True),
Column("comment", String),
Column("entity", Integer, ForeignKey("cats.id" | "dogs.id") # Invalid syntax here!
)
If no - I will do it via some intermediate table as:
review_categories = Table(
"review_categories",
Base.metadata,
Column("id", Integer, primary_key=True),
Column("cat", Integer),
Column("dog Integer),
)
You could create a common table for cats and dogs such that the id for any cat and dog is unique, and keep an additional parameter as type (dog or cat).
id (pk)
name
type
1
A
Dog
2
B
Cat
3
B
Dog
For a general solution where you may want a union of columns as a foreign key.
One interesting way to approach this might be to create a new table containing two columns. The first column will be unique names and the other column will be the frequency of these names (ie, how many times this keyword appears in cats and dogs combined).
Unique_id (pk)
Count
A
1
B
2
Such that
Unique_id = Dogs.id ∪ Cats.id
Logic to update the table
Insert in Cats - Insert or Increment Count of Unique_id
Deletion in Cats - Decrement Count of Unique_id or Delete If reaches 0
Then you can use the unique_id column for your foreign key

Django migration is creating extra table

I am beginner for Django and i am working on my final year project but i am stuck at one thing.
here is my model.py
class MatchList(models.Model):
user = models.OneToOneField(settings.AUTH_USER_MODEL, on_delete=models.CASCADE, related_name="user")
matches = models.ManyToManyField(settings.AUTH_USER_MODEL, blank=True, related_name="matches")
class Meta:
app_label = "matchsystem"
Also my here is my migration file as well.
class Migration(migrations.Migration):
initial = True
dependencies = [
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
]
operations = [
migrations.CreateModel(
name='MatchRequest',
fields=[
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('is_active', models.BooleanField(default=True)),
('times_tamp', models.DateTimeField(auto_now_add=True)),
('receiver', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='receiver', to=settings.AUTH_USER_MODEL)),
('sender', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='sender', to=settings.AUTH_USER_MODEL)),
],
),
migrations.CreateModel(
name='MatchList',
fields=[
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('matches', models.ManyToManyField(blank=True, related_name='matches', to=settings.AUTH_USER_MODEL)),
('user', models.OneToOneField(on_delete=django.db.models.deletion.CASCADE, related_name='user', to=settings.AUTH_USER_MODEL)),
],
),
]
but when i migrate the data it create an extra table with added name.
Any response is much appricated.
Nothing is wrong. In database terms a ManyToManyField is just an extra intermediate table which has foreign keys to the two related tables. This is because you really cannot have multiple values in the same column pointing to multiple entries.
Your first table matchsystem_matchlist you show in the image has the fields id and user_id which is correct, id is the primary key and user_id is the foreign key (in your model user). This is the table for your model MatchList.
Next your second table matchsystem_matchlist_matches has the fields id which is the primary key, matchlist_id which is the foreign key to MatchList and users_id which is the foreign key to the user model. This second table is the intermediate table made for the ManyToManyField named matches in your model MatchList.

Is mysql table not matching sqlalchemy model can cause an error?

Mysql User table: user_id int (pk), name varchar, last_name varchar
SQLAlchemy model:
class User(db.Model):
__tablename__ = 'user'
user_id = Column('user_id',INTEGER, nullable=False, primary_key=True)
name = Column('name',String(256), nullable=False)
lastname = Column('last_name',String(256), nullable=False)
If I want to add columns in my User table like phone_number and address which are not going to be used by my application. Do I need to change necessary my model of sqlalchemy or is it not harmful?
You do not have add the columns into your User class. But if you add data into the database using sqlachemy, it will construct the rows using only the fields from the class User, so if you do not have the defaults set in the database table definition, it may cause an error.
EDIT: You should be safe if you only use the model to query the database.

Django / MYSQL foreign key best practice

I have three models:
class Agent(models.Model):
name = models.CharField(max_length=200)
class Phone(models.Model):
calls = models.CharField(max_length=200)
agent_phone_name = models.CharField(max_length=200)
agent = models.ForeignKey(Agent, on_delete=models.CASCADE)
class Chat(models.Model):
chats = models.CharField(max_length=200)
agent_chat_name = models.CharField(max_length=200)
agent = models.ForeignKey(Agent, on_delete=models.CASCADE)
Chat and Phone links to agent with foreign key.
I want to make a table like this:
agent1 | sum(calls) | sum(chats)
agent2 | sum(calls) | sum(chats)
agent3 | sum(calls) | sum(chats)
First question is:
I've read about SQL foreign key as a way to maintain data and referential integrity. However in my case, there are miss call and chat (agent didn't pick it up) that generate rows of data has empty value on agent_name. So when I'm inserting the phone/chat data and update the FK, I have leave the FK empty and kinda that conflicts with the idea of FK. What's the best way to handle this?
Second question is: is using Foreign key the only way to perform SQL join table query in Django ORM? Is there any other way around it?
Thank you !

Unique constraint for column in one-to-many relationship in SQLAlchemy & MySQL

I'm not sure I've titled this question correctly. I can add a unique constraint well enough to any of my tables, but in the case below I'm not sure how to do what I'm after:
class Branch(db.Model):
id = db.Column(db.Integer, primary_key = True)
name = db.Column(db.String(160))
#foreign key for 'branches' in Account class. access with Branch.account
account_id = db.Column(db.Integer, db.ForeignKey('account.id'))
class Account(db.Model):
id = db.Column(db.Integer, primary_key = True)
name = db.Column(db.String(160), unique=True)
branches = db.relationship('Branch', backref = 'account', lazy = 'dynamic')
So when I added a unique constraint to the Branch table's name column, I could not add same-name branches to different accounts. For example, Seattle, could be a branch for both AccountA and AccountB.
What I want to do is apply a constraint that checks for uniqueness only when account.id is the same. Is this possible?
Thanks to dirn, pointing out the duplicate, I've added:
__table_args__ = (db.UniqueConstraint('account_id', 'name', name='_account_branch_uc'),
)
to my Branch class, and then pushed it to the database with alembic via:
def upgrade():
op.create_unique_constraint('_account_branch_uc', 'branch', ['name','account_id'])
I will note, though, that since I added this constraint manually via alebmic, I'm not certain if I added it correctly to my model. I suppose I'll find out when I eventually wipe my DB and start a new one.
EDIT
I have rolled a new database and the __table_args__ from above works correctly!