SQLAlchemy-migrate on a new Table with a relationship? - foreign-keys

Let's say I have created this new SQLAlchemy class:
class C(Base):
id = Column(Int, primary_key=True)
tags = relationship("B")
I want to create this table for SQLAlchemy-migrate.
However, I don't know how to convert 'relationship' from the declarative style, or what schema tags should have.
How do I write code for SQLAlchemy-migrate that will create or drop this Table?

Related

Flask Admin a custom inline model - update relation after saving

I have a catalog and the price is a one to many relationship, so that I can track the price of a catalog item over time. The model looks like:
class CatalogItem(db.Model)
id = db.Column(db.Integer(), primary_key=True)
name = db.Column(db.String(250))
price = db.relationship("Price", back_populates="catalogitem")
class Price(db.Model):
id = db.Column(db.Integer(), primary_key=True)
price = db.Column(db.Float())
timestamp = db.Column(db.DateTime(), server_default=func.now(), nullable=False)
catalogitem_id = db.Column(db.Integer(), db.ForeignKey("catalogitem.id"))
catalogitem = db.relationship("CatalogItem", back_populates="material_einheitspreis_verkauf")
And this is my View. At least I managed to only show the price.
class CatalogItemView(ModelView):
inline_models = [(Price, dict(form_columns=["id","price"]))]
There are two issues:
When I render a catalog item and set price as inline model, I can do that just fine, but the default behavior would allow me to add multiple prices. What I would actually like to do is to have just a price field. I'm looking for a way to limit the form to just one entity (and also leaving away the button "add price".
When editing a catalogitem, it shouldn't edit the price, but actually create a new relationship -> basically when I edit the price it will create a new Price entity.
For 1 I have not idea on how to achieve this. For 2 I guess I could maybe do this by adding some kind of additional form field outside of the model and then create the "magic" with some kind of listeners.
Any other ideas?

Working with multiple schemas on one server?

I have one MySQL server with multiple schemas and it looks something like this:
-app_metadata [database]
users [table]
app_data [table]
-site1 [database]
tableA [table]
tableB [table]
There is multiple sites (site1, site2.. site32) and there are new sites being added periodically but the structure of all sites are the same, they all have table A and table B that that can be represented by identical models in flask-SQLalchemy.
Retrieving information depending on what site the user is interested in is quite simple with a query (not actual code but the idea is there):
user_selection = site3
query = f'SELECT * FROM `{user_selection}`.tableA;'
I'm not that familiar with flask-sqlalchemy and I have a hard time figuring out how can I translate this so that the URI is dynamically switch (based on the site selection).
I can do bindings for the app_metadata database as follows (I assume, not really the issue):
class User(db.Model):
__bind_key__ = 'app_metadata'
id = db.Column(db.Integer, primary_key=True)
username = db.Column(db.String(80), unique=True)
The problem is how do I connect to the second database (pretty much on the go) based on the users choice and change the bind key inside the table classes.
class TableA(db.Model):
__bind_key__ = *users_choice*
id = db.Column(db.Integer, primary_key=True)
....
class TableB(db.Model):
__bind_key__ = *users_choice*
id = db.Column(db.Integer, primary_key=True)
....
I can't really change the structure of the database but obviously I can play with the code.

Select raw data from multi table

I would like to select raw data from multiple tables.
eg.
query = tempmodel.objects.raw('select empid as id,employee.empid,ccmaster.cscid from employee
left join ccmaster
on employee.cscid = ccmaster.cscid'
Am I need to create a new model for tempmodel that includes all required fields?
I already tried with cursor.execute but this only returns result value, not with the field.
How can I select raw for multi-table?
I already check that one=> raw sql with multiple table but honestly, I don't understand the answer.
raw() automatically maps fields in the query to fields on the model. (https://docs.djangoproject.com/en/2.2/topics/db/sql/#mapping-query-fields-to-model-fields)
I suggest you create a Model that includes all required fields and set the managed Meta option to False (https://docs.djangoproject.com/en/2.2/ref/models/options/#managed)
i.e.
class TempModel(models.Model):
field = models.ForeignKey(Question, on_delete=models.CASCADE)
# ...
class Meta:
managed = False
(Optional) In addition to that, maybe you could use a Custom Model Manager (https://docs.djangoproject.com/en/2.2/topics/db/managers/#adding-extra-manager-methods)

Django ManyToManyField not present in Sqlite3

I'm new to Django and I have some issues with a ManyToMany relationship.
I work on a blastn automatisation and here are my classes:
class Annotation(models.Model):
sequence = models.IntegerField()
annotation = models.TextField()
start = models.IntegerField()
end = models.IntegerField()
class Blast(models.Model):
sequence = models.ManyToManyField(Annotation, through="AnnotBlast")
expectValue = models.IntegerField()
class AnnotBlast(models.Model):
id_blast = models.ForeignKey(Blast, to_field="id")
id_annot = models.ForeignKey(Annotation, to_field="id")
class Hit(models.Model):
id_hit = models.ForeignKey(Blast, to_field="id")
length = models.IntegerField()
evalue = models.IntegerField()
start_seq = models.IntegerField()
end_seq = models.IntegerField()
In a view, I want to access to Annotation's data from the rest of the model via this many to many field and then apply filters based on a form. But when I do a syncdb , the "sequence" field of the Blast class disappear :
In Sqlite3 :
.schema myApp_blast
CREATE TABLE "myApp_blast" (
"id" integer not null primary key,
"expectValue" integer not null
);
So I can't load data in this table as I want. I don't understand why this field disappear during the syncdb. How can I do to link the first class to the others (and then be able to merge data in a template) ?
A ManyToManyField isn't itself a column in the database. It's represented only by an element in the joining table, which you have here defined explicitly as AnnotBlast (note that since you're not defining any extra fields on the relationship, you didn't actually need to define a through table - Django would have done it automatically if you hadn't).
So to add data to your models, you add data to the AnnotBlast table pointing at the relevant Blast and Annotation rows.
For a many-to-many relationship an intermediate join table is created, see documentation here: https://docs.djangoproject.com/en/1.2/ref/models/fields/#id1

How can i get a list of objects from a postgresql view table to display

this is a model of the view table.
class QryDescChar(models.Model):
iid_id = models.IntegerField()
cid_id = models.IntegerField()
cs = models.CharField(max_length=10)
cid = models.IntegerField()
charname = models.CharField(max_length=50)
class Meta:
db_table = u'qry_desc_char'
this is the SQL i use to create the table
CREATE VIEW qry_desc_char as
SELECT
tbl_desc.iid_id,
tbl_desc.cid_id,
tbl_desc.cs,
tbl_char.cid,
tbl_char.charname
FROM tbl_desC,tbl_char
WHERE tbl_desc.cid_id = tbl_char.cid;
i dont know if i need a function in models or views or both. i want to get a list of objects from that database to display it. This might be easy but im new at Django and python so i having some problems
Django 1.1 brought in a new feature that you might find useful. You should be able to do something like:
class QryDescChar(models.Model):
iid_id = models.IntegerField()
cid_id = models.IntegerField()
cs = models.CharField(max_length=10)
cid = models.IntegerField()
charname = models.CharField(max_length=50)
class Meta:
db_table = u'qry_desc_char'
managed = False
The documentation for the managed Meta class option is here. A relevant quote:
If False, no database table creation
or deletion operations will be
performed for this model. This is
useful if the model represents an
existing table or a database view that
has been created by some other means.
This is the only difference when
managed is False. All other aspects of
model handling are exactly the same as
normal.
Once that is done, you should be able to use your model normally. To get a list of objects you'd do something like:
qry_desc_char_list = QryDescChar.objects.all()
To actually get the list into your template you might want to look at generic views, specifically the object_list view.
If your RDBMS lets you create writable views and the view you create has the exact structure than the table Django would create I guess that should work directly.
(This is an old question, but is an area that still trips people up and is still highly relevant to anyone using Django with a pre-existing, normalized schema.)
In your SELECT statement you will need to add a numeric "id" because Django expects one, even on an unmanaged model. You can use the row_number() window function to accomplish this if there isn't a guaranteed unique integer value on the row somewhere (and with views this is often the case).
In this case I'm using an ORDER BY clause with the window function, but you can do anything that's valid, and while you're at it you may as well use a clause that's useful to you in some way. Just make sure you do not try to use Django ORM dot references to relations because they look for the "id" column by default, and yours are fake.
Additionally I would consider renaming my output columns to something more meaningful if you're going to use it within an object. With those changes in place the query would look more like (of course, substitute your own terms for the "AS" clauses):
CREATE VIEW qry_desc_char as
SELECT
row_number() OVER (ORDER BY tbl_char.cid) AS id,
tbl_desc.iid_id AS iid_id,
tbl_desc.cid_id AS cid_id,
tbl_desc.cs AS a_better_name,
tbl_char.cid AS something_descriptive,
tbl_char.charname AS name
FROM tbl_desc,tbl_char
WHERE tbl_desc.cid_id = tbl_char.cid;
Once that is done, in Django your model could look like this:
class QryDescChar(models.Model):
iid_id = models.ForeignKey('WhateverIidIs', related_name='+',
db_column='iid_id', on_delete=models.DO_NOTHING)
cid_id = models.ForeignKey('WhateverCidIs', related_name='+',
db_column='cid_id', on_delete=models.DO_NOTHING)
a_better_name = models.CharField(max_length=10)
something_descriptive = models.IntegerField()
name = models.CharField(max_length=50)
class Meta:
managed = False
db_table = 'qry_desc_char'
You don't need the "_id" part on the end of the id column names, because you can declare the column name on the Django model with something more descriptive using the "db_column" argument as I did above (but here I only it to prevent Django from adding another "_id" to the end of cid_id and iid_id -- which added zero semantic value to your code). Also, note the "on_delete" argument. Django does its own thing when it comes to cascading deletes, and on an interesting data model you don't want this -- and when it comes to views you'll just get an error and an aborted transaction. Prior to Django 1.5 you have to patch it to make DO_NOTHING actually mean "do nothing" -- otherwise it will still try to (needlessly) query and collect all related objects before going through its delete cycle, and the query will fail, halting the entire operation.
Incidentally, I wrote an in-depth explanation of how to do this just the other day.
You are trying to fetch records from a view. This is not correct as a view does not map to a model, a table maps to a model.
You should use Django ORM to fetch QryDescChar objects. Please note that Django ORM will fetch them directly from the table. You can consult Django docs for extra() and select_related() methods which will allow you to fetch related data (data you want to get from the other table) in different ways.