I am trying the new cqlengine models as part of the datastax driver. , here I am not able get the table_name from the class
from cassandra.cqlengine.models import Model
class User(Model):
uid = columns.UUID(primary_key=True,default=uuid.uuid4)
fname = columns.Text(primary_key=True,required=True)
lname = columns.Text(primary_key=True,required=True)
user_id = columns.Text(primary_key=True,required=True)
email_id = columns.Text(primary_key=True,required=True)
password = columns.Text(primary_key=True,required=True)
salt = columns.Text(required=True)
User.table_name gives me None.
Do I need to set this ?
From the documentation
Model.table_name
Optional. Sets the name of the CQL table for this model. If left blank, the table name will be the name of the model, with it’s module name as it’s prefix. Manually defined table names are not inherited.
As answered on the mailing list, considering the __table_name__ can also be dynamically computed based on the name of the model, the way to get the table name is using User.column_family_name(include_keypspace=False).
Related
Given the following Models:
class LeftTable(Model):
left_table_col = TextField()
class Meta:
table_name = 'left_table'
class RightTable(Model):
right_table_col = TextField()
class Meta:
table_name = 'right_table'
class ConnectingTable(BaseModel):
con_table_column = TextField()
from_left = ForeignKeyField(User, backref='left_table')
to_right = ForeignKeyField(User, backref='related_to')
class Meta:
table_name = 'connecting_table'
indexes = (
# Specify a unique multi-column index on from/to-user.
(('from_left', 'to_right'), True),
)
Is there a way to create the left_table row, connecting_table row and right_table row all in one step in Peewee?
normally I'd just populate left_table, right_table and then adding a row in connecting_table using the respective ids (left_table_id, right_table_id) and additional values.
Programmer looking for a short-cut... go figure.
Unless I'm misunderstanding your question, relational databases don't have any concept of "insert into multiple tables in one operation". For this you have a different primitive: transactions.
So the proper way to do this is:
Begin a transaction
Insert into left table, right table, join table.
Commit
I'm using PostGres 10, Python 3.9, and Django 3.2. I have set up this model with the accompanying many-to-many relationship ...
class Account(models.Model):
id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False)
...
crypto_currencies = models.ManyToManyField(CryptoCurrency)
After generating and running Django migrations, the following table was created ...
\d cbapp_account_crypto_currencies;
Table "public.cbapp_account_crypto_currencies"
Column | Type | Modifiers
-------------------+---------+------------------------------------------------------------------------------
id | integer | not null default nextval('cbapp_account_crypto_currencies_id_seq'::regclass)
account_id | uuid | not null
cryptocurrency_id | uuid | not null
Indexes:
"cbapp_account_crypto_currencies_pkey" PRIMARY KEY, btree (id)
"cbapp_account_crypto_cur_account_id_cryptocurrenc_38c41c43_uniq" UNIQUE CONSTRAINT, btree (account_id, cryptocurrency_id)
"cbapp_account_crypto_currencies_account_id_611c9b45" btree (account_id)
"cbapp_account_crypto_currencies_cryptocurrency_id_685fb811" btree (cryptocurrency_id)
Foreign-key constraints:
"cbapp_account_crypto_account_id_611c9b45_fk_cbapp_acc" FOREIGN KEY (account_id) REFERENCES cbapp_account(id) DEFERRABLE INITIALLY DEFERRED
"cbapp_account_crypto_cryptocurrency_id_685fb811_fk_cbapp_cry" FOREIGN KEY (cryptocurrency_id) REFERENCES cbapp_cryptocurrency(id) DEFERRABLE INITIALLY DEFERRED
How do I alter my field relation, or generate a migration, such that the cascade relationship is ON-DELETE CASCADE? That is, When I delete an account, I would like accompanying records in this table to also be deleted.
Had a closer look on this. I tried to replicate your models and I also see that the intermediary table has no cascade. I have no answer on your main question on how to add the cascade, but it seems that django does the cascade behavior which already supports this:
When I delete an account, I would like accompanying records in this table to also be deleted.
To demonstrate:
a = Account.objects.create(name='test')
c1 = CryptoCurrency.objects.create(name='c1')
c2 = CryptoCurrency.objects.create(name='c2')
c3 = CryptoCurrency.objects.create(name='c3')
a.crypto_currencies.set([c1, c2, c3])
If you do:
a.delete()
Django runs the following SQL which simulates the cascade on the intermediary table:
[
{
'sql': 'DELETE FROM "myapp_account_crypto_currencies" WHERE "myapp_account_crypto_currencies"."account_id" IN (3)', 'time': '0.002'
},
{
'sql': 'DELETE FROM "myapp_account" WHERE "myapp_account"."id" IN (3)', 'time': '0.001'
}
]
I can't find in the documentation why it is done this way though. Even adding a custom intermediary like this results in the same behavior:
class Account(models.Model):
name = models.CharField(max_length=100)
crypto_currencies = models.ManyToManyField(CryptoCurrency, through='myapp.AccountCryptocurrencies')
class AccountCryptocurrencies(models.Model):
account = models.ForeignKey(Account, on_delete=models.CASCADE)
cryptocurrency = models.ForeignKey(CryptoCurrency, on_delete=models.CASCADE)
When you use a ManyToManyField, Django creates a intermediary table for you, in this case named cbapp_account_crypto_currencies. What you want to do in the future is to always explicitly create the intermediary model, AccountCryptoCurrencies, then set the through attribute of the ManyToManyField. This will allow you to add more fields in the future to the intermediary model. See more here: https://docs.djangoproject.com/en/3.2/ref/models/fields/#django.db.models.ManyToManyField.through.
What you will now need to do is so create this intermediary table:
class AccountCryptoCurrencies(models.Model):
account = models.ForeignKey(Account)
cryptocurrency = models.ForeignKey(CryptoCurrency)
class Meta:
db_table = 'cbapp_account_crypto_currencies'
class Account(models.Model):
id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False)
...
crypto_currencies = models.ManyToManyField(CryptoCurrency, through=AccountCryptoCurrencies)
You are now need to generate a migration, but do not apply it yet! Modify the migration by wrapping it in a SeparateDatabaseAndState. I havent created your migration file because I dont have the full model, but you can see here for how to do it: How to add through option to existing ManyToManyField with migrations and data in django
Now you can apply the migration and you should now have an explicit intermediary table without losing data. You can also now add additional fields to the intermediary table and change the existing fields. You can add the on_delete=models.CASCADE to the account field and migrate the change.
I am creating a rating system. Rating is a table which contains individual ratings as rows. Each rating has a "rater" and a "ratee". These two columns reference a different table, "User", by means of a foreign key. However, they both reference the same user.id column. Code:
class Rating(db.Model):
id = db.Column(db.Integer, primary_key=True)
rater_id = db.Column(db.Integer, db.ForeignKey('user.id'), nullable=False)
ratee_id = db.Column(db.Integer, db.ForeignKey('user.id'), nullable=False)
And here is how they are represented from within the User class (table):
class User(db.Model, UserMixin):
id = db.Column(db.Integer, primary_key=True)
username = db.Column(db.String(32), unique=True, nullable=False)
ratesOfOthers = db.relationship('Rating', backref='rater', lazy=True)
ratingsByOthers = db.relationship('Rating', backref='ratee', lazy=True)
Now, when I try to use this relationship, I am presented with the following error:
sqlalchemy.exc.AmbiguousForeignKeysError: Could not determine join condition between parent/child tables on relationship User.ratesOfOthers - there are multiple foreign key paths linking the tables. Specify the 'foreign_keys' argument, providing a list of those columns which should be counted as containing a foreign key reference to the parent table.
I have tried using the foreign_keys argument from inside the User class, but that did nothing. Any help would be appreciated.
The assumption is that in your scenario a user can rate other users, and they (themselves) can be rated. Basically, there is one table called User referencing other users within an application.
A relationship in which instances of a class are linked to other instances of the same class is called self-referential relationship, and that is exactly what you have here.
Here is a diagram that represents this self-referential many-to-many relationship that keeps track of ratings:
The Ratings table is the association table of the relationship. The foreign keys in this table are pointing at entries in the User table since it is linking users to users.
To add this table to your database, this is how you can go about it:
ratings = db.Table('ratings'
db.Column('my_ratings_id', db.Integer, db.ForeignKey('user.id'))
db.Column('other_people_rating_id', db.Integet, db.ForeignKey('user.id'))
)
This is an auxiliary table (directly-translated as seen above) that has no data other than foreign keys. It is, therefore, created without an associated model class.
To declare the many-to-many relationship in the User table, add this:
class User(UserMixin, db.Model):
id = db.Column(db.Integer, primary_key=True)
username = db.Column(db.String(32), unique=True, nullable=False)
def __repr__(self):
return f'{self.username}'
my_ratings = db.relationship(
'User',
secondary=ratings,
primaryjoin=(ratings.c.my_ratings_id == id),
secondaryjoin=(ratings.c.other_people_rating_id == id),
backref = db.backref('other_people_rating', lazy='dynamic'), lazy='dynamic'
)
I am defining the relationship as seen from the left side user with the name my_ratings because when you query this relationship from the left side, you will get a list of all those on the right side. Visually, this is what I mean:
Examining all the arguments of the db.relationship() call, you will see that:
User is the right side entity of the relationship.
secondary configures the ratings association table
primaryjoin indicates the condition that links the left side entity with the association table. The user id should match my_ratings_id
secondaryjoin indicates the condition that links the right side entity with the association table. Again, other_people_rating_id should match the user id
backref defines how this relationship will be accessed from the right side entity. From the left side, the relationship is named my_ratings, so from the right side, I decided to name it other_people_rating to represent all the left side users that are linked to the target user in the right side.
The dynamic mode is used to set up the query to not run until specifically requested.
The second lazy parameter applies to the left side query instead of the right side.
Suppose i have 2 tables , Table 1 consist of users info and Table 2 consist of Branch info.
table 1 and table 2 is related to each other by many to many relationship.
e.g 1 user can work in multiple branches and 1 branch can have multiple users.
so here there's no parent child concept. i was wondering if i have to create another table with schema and relate it to user and branch table using foreign key or shall i create an association table.
I have done this :
class UserBranchMap(db.Model):
id = db.Column(db.Integer, primary_key=True)
branch_id = db.Column(db.Integer,db.ForeignKey('branch.id'))
branch = db.relationship("Branch", backref=db.backref("UBMbranch", lazy="dynamic"))
user_id = db.Column(db.Integer,db.ForeignKey('user.id'))
user = db.relationship("User", backref=db.backref("UBMuser", lazy="dynamic"))
created_at = db.Column(db.VARCHAR(20), nullable = False)
created_by = db.Column(db.VARCHAR(20), nullable = False)
class UserBranchMapSchema(ma.Schema):
branch = fields.Nested(branch_schema)
user = fields.Nested(user_schema)
class Meta:
fields = ('branch_id','user_id','created_at','created_by')
userbranchmap_schema = UserBranchMapSchema()
userbranchmaps_schema = UserBranchMapSchema(many = True)
what's the difference between association table and this mapping table ?
If I understand you correctly, you're asking about the difference between an association table
UserBranches = db.Table(
'user_branches',
db.Column('user_id', db.Integer, db.ForeignKey('user.id'), primary_key=True),
db.Column('branch_id', db.Integer, db.ForeignKey('branch.id'), primary_key=True)
)
and a mapping table
class UserBranch(db.Model):
id = db.Column(db.Integer, primary_key=True)
user = db.relationship("User", backref=db.backref("UBMuser", lazy="dynamic"))
user_id = db.Column(db.Integer, db.ForeignKey('user.id'))
branch = db.relationship("Branch", backref=db.backref("UBMbranch", lazy="dynamic"))
branch_id = db.Column(db.Integer, db.ForeignKey('branch.id'))
On a database level, there is no real difference between them. If you only want to have a strict Many To Many relationship between two tables, just use an association table. Because of SQLAlchemy, you never have to do anything with it, because joining through this table happens automatically, as soon as you join Users to Branches or the reverse.
If, however, you want to do more, like have it actually denote a relationship, then the mapping table like you wrote it the way to go, because it behaves exactly like a normal table. This means you can use it like UserBranch.created_at or even query it directly if you want.
I am using SQLAlchemy to handle requests from an API endpoint; my database tables (I have hundreds) are differentiated via a unique string (e.g. test_table_123)...
In the code below, __tablename__ is static. If possible, I would like that to change based on the specific table I would like to retrieve, as it would be tedious to write several hundred unique classes.
from config import db, ma # SQLAlchemy is init'd and tied to Flask in this config module
class specific_table(db.Model):
__tablename__ = 'test_table_123'
var1 = db.Column(db.Integer, primary_key=True)
var2 = db.Column(db.String, index=True)
var3 = db.Column(db.String)
class whole_table_schema(ma.ModelSchema):
class Meta:
model = specific_table
sqla_session = db.session
def single_table(table_name):
# collect the data from the unique table
my_data = specific_table().query.order_by(specific_table.level_0).all()
Thank you very much for your time in advance.
You can use reflect feature of SQLAlchemy.
engine = db.engine
metadata = MetaData()
metadata.reflect(bind=engine)
and finally
db.session.query(metadata.tables[table_name])
If you want smoother experience with querying, as previous solution cannot offer one, you might declare and map your tables: tables = {table_name: create_table(table_name) for table_name in table_names}, where create_table constructs models with different __tablename__. Instead of creating all tables at once, you can create them on demand.