When defining a model with an index_together Meta property, does the order of the columns matter?
In other words, is there a difference between
Class myModel(models.Model):
name = models.CharField(max_length=100)
address = models.CharField(max_length=100)
favorite_color = models.CharField(max_length=20)
class Meta:
index_together = ('name', 'address', 'favorite_color')
vs
Class myModel(models.Model):
name = models.CharField(max_length=100)
address = models.CharField(max_length=100)
favorite_color = models.CharField(max_length=20)
class Meta:
index_together = ('favorite_color', 'name', 'address')
I only ask because I've noticed when looking at the structure of a table, each column in the key has an "index in key" property. Does MySQL/PostgreSQL expect the columns to be queried in that order?
Just as an aside, is there a great deal of difference between indexing the columns together vs separately?
The order of index_together explains the "path" the index is created.
You can query from left to the right to profit from the index.
So with your first index_together:
index_together = ('name', 'address', 'favorite_color')
if your first filter is name the index is used. If the first is name and the second is address the index is used, too.
But if you filter by address and then name or address, favorite_color the index can't be used.
Related
I'm trying to model following situation:
I need to set prices for groups of countries. So I have three entities:
class Zone:
zone = Column(Integer, primary_key=True)
class Country:
country = Column(String(2), primary_key=True)
zone = Column(Integer, ForeignKey('Zone.zone')
class Rate:
zone = Column(Integer, ForeignKey('Zone.zone')
rate = Column(Float)
Now I want to be able to access rates for a chosen Country. So I change my Country entity this way:
class Country:
country = Column(String(2), primary_key=True)
zone = Column(Integer, ForeignKey('Zone.zone')
rates = relationship('Rate', foreign_keys=[zone])
And I'm getting an error:
sqlalchemy.exc.NoForeignKeysError: Could not determine join condition between parent/child tables on relationship Country.rates - there are no foreign keys linking these tables. Ensure that referencing columns are associated with a ForeignKey or ForeignKeyConstraint, or specify a 'primaryjoin' expression.
Ok, I changed the Country entity:
class Country:
country = Column(String(2), primary_key=True)
zone = Column(Integer, ForeignKey('Zone.zone')
rates = relationship('Rate', primaryjoin="Country.zone == Rate.zone")
The error is changed:
sqlalchemy.exc.ArgumentError: Could not locate any relevant foreign key columns for primary join condition 'countries.zone = rates.zone' on relationship Country.rates. Ensure that referencing columns are associated with a ForeignKey or ForeignKeyConstraint, or are annotated in the join condition with the foreign() annotation.
So the next version looks like that:
class Country:
country = Column(String(2), primary_key=True)
zone = Column(Integer, ForeignKey('Zone.zone')
rates = relationship('Rate', primaryjoin="foreign(Country.zone) == remote(Rate.zone)")
Surprisingly that partially worked. Partially because value of rates wasn't a list (by the way lazy='dynamic' caused an error as well) but a single (first) value. Somewhere I found a solution to that, which required change rather in Rate:
class Rate:
zone = Column(Integer, ForeignKey('Zone.zone')
rate = Column(Float)
__countries = relationship('Country',
primaryjoin="foreign(Rate.zone) == remote(Country.zone)",
backref='rates')
This finally worked. So here comes a question. The solution seems to be a bit cumbersome and doesn't rely on indexes, which might cause performance issues. Is there a better solution?
I have items of different type, say City, Country and Continent. And I have Labels. I want to be able to add multiple Labels to either City, Country and Continent objects. And each Label could have multiple items, too.
I cannot use table inheritance for defining City, Country and Continent here, since the models and their respective database tables are already existing and populated. Migrating the database to a different structure is impossible in my situation due to the size of the database. So I tried to make it with an Association Object, but I cannot figure out, how to create the relation from, say, Country to the Association in a way, that it only retrieves the lablables which have lablable_type = "country"
So, what I have looks like this:
Base = declarative_base()
class Lablable(Base):
__tablename__ = 'lablables'
label_id = db.Column(db.Integer, db.ForeignKey('labels.id'), primary_key=True)
lablable_id = db.Column(db.Integer)
lablable_type = db.Column(db.String(100))
labels = db.relationship("Label")
class Label(db.Model):
__tablename__ = "labels"
id = db.Column(db.Integer, primary_key=True, autoincrement=True, nullable=False)
caption = db.Column(db.String(200))
class Country(db.Model):
__tablename__ = "countries"
lablable_id = db.Column(db.Integer(), db.ForeignKey('lablables.id'))
lables = association_proxy('lablables', 'label',
creator=lambda x: Lablable(x=label))
How can I design my models to achieve what I want?
I have a quick function that I threw up together to remove duplicates on my table given a particular combination of fields:
for l in table.select():
if table.select().where((table.Field1==l.Field1) & (table.Field2==l.Field2) & ....).count()>1:
l.delete()
l.save()
But I imagine that there's a better way to do this
You could add a unique constraint on the columns you wish to be unique, then let the database enforce the rules for you. That'd be the best way.
For peewee, that looks like:
class MyModel(Model):
first_name = CharField()
last_name = CharField()
dob = DateField()
class Meta:
indexes = (
(('first_name', 'last_name', 'dob'), True),
)
Docs: http://docs.peewee-orm.com/en/latest/peewee/models.html#indexes-and-unique-constraints
Django Model
class logdetail(models.Model):
scantype = models.CharField(max_length=100)
scanrange = models.CharField(max_length=100)
scandate = models.DateTimeField(max_length=100)
status = models.CharField(max_length=100)
Views.py
logDBObj = logdetail.objects.all().filter(id=logdetail_id).order_by('-logdetail_id')
I have to collect all the records in logdetail table by descending order of autoincrement id.
I could not find where I am missing. Any help would be appreciated.
You haven't shown your model but by the looks of it you just need to remove the logdetail in your order_by:
logdetail.objects.all().order_by('-id')
Answer no longer needed as I changed focus in code. (see my comment in answer) Post answers for future reference...
How do I retrieve results from a one to many backref ordered by a field in the child? I need all somethings for the gid ordered by index. But at this time they are retrieved randomly even though they are ordered in the ms sql server.
I have in TurboGears 2 datamodels.py:
`class Parcel(DeclarativeBase):
__tablename__ = 'GENERAL'
__table_args__ = ({'autoload': True})
gid = Column(Integer, primary_key=True)`
somethings = relationship('Something', backref='Parcel')
'class Something(DeclarativeBase):
__tablename__ = 'SKETCH'
__table_args__ = ({'autoload': True})
gid = Column(Integer, ForeignKey('GENERAL.gid'), primary_key=True)
index = Column(Integer, primary_key=True)
In Turbogears root.py:
query = DBSession.query(Parcel)
query = query.options(joinedload('somethings')
query=session.filter(Parcel.gid==gid)
Returns all somethings for gid unordered.
DBSession.query(Something).filter_by(gid=gid).order_by(Something.index).all()
edit: relationship() accepts a keyword argument order_by to order instances when you use the relationship. If you want to specify the ordering for the reverse direction, you can use the backref() function instead of the backref keyword and use the same order_by keyword argument as with relationship().