How to access a field in a related django model other than the primary key - class

This seems a silly, simple question. I'm going round in circles trying to get this work, but I can't see the wood for the trees.
Given a simple model such as (I've skipped the imports):
class Location(models.Model):
description = model.CharField(max_length=40)
address1 = model.CharField(max_length=40)
# ..... (and so on)
tel = model.CharField(max_length=12)
and another with a relationship to it:
class InformationRequest(models.Model):
source = models.ForeignKey(Location)
request_date = Models.DateField(default=datetime.now())
# ..... (and so on)
How do I add a field that references the 'tel' field from the Location model in such a way that it can be populated automatically or from a select list in Django admin.

OK, if I get this right than you are, nomen est omen, thoroughly confusing the way that relational databases work :] One of key principles is to eliminate redundancy. There shouldn't be the very same piece of data stored in two tables that are related to one another.
I think that your current models are correct. Given these instances (I'm ignoring the fact that you have other, non-nullable fields)...
>>> loc = Location()
>>> loc.tel = "123"
>>> loc.save()
>>> info = InformationRequest()
>>> info.source = loc
>>> info.save()
...you can access tel from InformationRequest instance just like this:
>>> info.source.tel
'123'
You can also create a method...
class InformationRequest(models.Model):
source = models.ForeignKey(Location, related_name="information_requests")
request_date = Models.DateField(default=datetime.now())
# ..... (and so on)
def contact_tel(self):
return self.source.tel
... and get it like this:
>>> info.contact_tel()
'123'
You can even trick it into being an attribute...
class InformationRequest(models.Model):
source = models.ForeignKey(Location, related_name="information_requests")
request_date = Models.DateField(default=datetime.now())
# ..... (and so on)
#property
def contact_tel(self):
return self.source.tel
... and get it without parentheses:
>>> info.contact_tel
'123'
Anyway, you should work your way around it programatically. Hope that helps.

Related

Accessing values from one-to-many relationship in PonyORM

For a database of games, where one game is called different names by different users, I have two tables, set up as one-to-many:
class Game(db.Entity):
name = Set('Name')
...
class Name(db.Entity):
game = Required(Game)
name = Required(str)
...
How can I access the names for a specific game? They come back as "Multiset", which (I think) is a special Counter object, when I do this:
games = Game.select()
for g in games:
names = g.name.name
print(names)
>>> Multiset({'Sticks And Stones': 1, 'May Break Your Bones': 1 })
This also seems pretty ugly to me, I suppose there must be a better way?
It turns out the to_dict() method, well documented in PonyORM's API Reference, helps greatly with to-many relationships.
for g in games:
this_game = g.to_dict(
with_collections=True,
related_objects=True,
exclude=['game_meta', 'statistics']
)
And then access the dict() entries like this: this_game['name']

Using multiple POSTGRES databases and schemas with the same Flask-SQLAlchemy model

I'm going to be very specific here, because similar questions have been asked, but none of the solutions work for this problem.
I'm working on a project that has four postgres databases, but let's say for the sake of simplicity there are 2. Namely, A & B
A,B represent two geographical locations, but the tables and schemas in the database are identical.
Sample model:
from flask_sqlalchemy import SQLAlchemy
from sqlalchemy import *
from sqlalchemy.ext.declarative import declarative_base
db = SQLAlchemy()
Base = declarative_base()
class FRARecord(Base):
__tablename__ = 'tb_fra_credentials'
recnr = Column(db.Integer, primary_key = True)
fra_code = Column(db.Integer)
fra_first_name = Column(db.String)
This model is replicated in both databases, but with different schemas, so to make it work in A, I need to do:
__table_args__ = {'schema' : 'A_schema'}
I'd like to use a single content provider that is given the database to access, but has identical methods:
class ContentProvider():
def __init__(self, database):
self.database = database
def get_fra_list():
logging.debug("Fetching fra list")
fra_list = db.session.query(FRARecord.fra_code)
Two problems are, how do I decide what db to point to and how do I not replicate the model code for different schemas (this is a postgres specific problem)
Here's what I've tried so far:
1) I've made separate files for each of the models and inherited them, so:
class FRARecordA(FRARecord):
__table_args__ = {'schema' : 'A_schema'}
This doesn't seem to work, because I get the error:
"Can't place __table_args__ on an inherited class with no table."
Meaning that I can't set that argument after the db.Model (in its parent) was already declared
2) So I tried to do the same with multiple inheritance,
class FRARecord():
recnr = Column(db.Integer, primary_key = True)
fra_code = Column(db.Integer)
fra_first_name = Column(db.String)
class FRARecordA(Base, FRARecord):
__tablename__ = 'tb_fra_credentials'
__table_args__ = {'schema' : 'A_schema'}
but got the predictable error:
"CompileError: Cannot compile Column object until its 'name' is assigned."
Obviously I can't move the Column objects to the FRARecordA model without having to repeat them for B as well (and there are actually 4 databases and a lot more models).
3) Finally, I'm considering doing some sort of sharding (which seems to be the correct approach), but I can't find an example of how I'd go about this. My feeling is that I'd just use a single object like this:
class FRARecord(Base):
__tablename__ = 'tb_fra_credentials'
#declared_attr
def __table_args__(cls):
#something where I go through the values in bind keys like
for key, value in self.db.app.config['SQLALCHEMY_BINDS'].iteritems():
# Return based on current session maybe? And then have different sessions in the content provider?
recnr = Column(db.Integer, primary_key = True)
fra_code = Column(db.Integer)
fra_first_name = Column(db.String)
Just to be clear, my intention for accessing the different databases was as follows:
app.config['SQLALCHEMY_DATABASE_URI']='postgresql://%(user)s:\
%(pw)s#%(host)s:%(port)s/%(db)s' % POSTGRES_A
app.config['SQLALCHEMY_BINDS']={'B':'postgresql://%(user)s:%(pw)s#%(host)s:%(port)s/%(db)s' % POSTGRES_B,
'C':'postgresql://%(user)s:%(pw)s#%(host)s:%(port)s/%(db)s' % POSTGRES_C,
'D':'postgresql://%(user)s:%(pw)s#%(host)s:%(port)s/%(db)s' % POSTGRES_D
}
Where the POSTGRES dictionaries contained all the keys to connect to the data
I assumed with the inherited objects, I'd just connect to the correct one like this (so the sqlalchemy query would automatically know):
class FRARecordB(FRARecord):
__bind_key__ = 'B'
__table_args__ = {'schema' : 'B_schema'}
Finally found a solution to this.
Essentially, I didn't create new classes for each database, I just used different database connections for each.
This method on its own is pretty common, the tricky part (which I couldn't find examples of) was handling schema differences. I ended up doing this:
from sqlalchemy import create_engine
from sqlalchemy.orm import sessionmaker
Session = sessionmaker()
class ContentProvider():
db = None
connection = None
session = None
def __init__(self, center):
if center == A:
self.db = create_engine('postgresql://%(user)s:%(pw)s#%(host)s:%(port)s/%(db)s' % POSTGRES_A, echo=echo, pool_threadlocal=True)
self.connection = self.db.connect()
# It's not very clean, but this was the extra step. You could also set specific connection params if you have multiple schemas
self.connection.execute('set search_path=A_schema')
elif center == B:
self.db = create_engine('postgresql://%(user)s:%(pw)s#%(host)s:%(port)s/%(db)s' % POSTGRES_B, echo=echo, pool_threadlocal=True)
self.connection = self.db.connect()
self.connection.execute('set search_path=B_schema')
def get_fra_list(self):
logging.debug("Fetching fra list")
fra_list = self.session.query(FRARecord.fra_code)
return fra_list

Sqlalchemy + Postgres: synthetic/artificial id mixin with sequence

I've found the mixin pattern to be really handy for staying DRY, but I am having trouble with sequences. Note, I'm using postgres.
We use alembic migrations, and I'd really like the --autogeneration to work with this sequence, though I understand this might not be possible right now. However, it looks like setting up the sequence without an ORM identifier, prevents the sequence from being dropped later if I wanted to perform a downgrade.
Through googling, I found some explanation on how to properly setup a sequence. Essentially: separate the id and its sequence.
Current Code looks a bit like this:
import sqlalchemy as sa
from sqlalchemy.ext.declarative import declared_attr
class AutoIdMixin(object):
"""Generates an synthetic identifier primary key.
"""
# See: http://docs.sqlalchemy.org/en/latest/core/defaults.html#associating-a-sequence-as-the-server-side-default
#declared_attr
def id_seq(cls):
bases = cls.__bases__
Base = bases[0]
sequence_prefix = 'seq'
schema = cls._schema_name
sequence_id = '_'.join((sequence_prefix, schema, cls.__tablename__, 'id'))
sequence = sa.Sequence(sequence_id, 1, 1, metadata=Base.metadata)
return sequence
#declared_attr
def id(cls):
column_id = sa.Column(sa.types.Integer, cls.id_seq.next_value(), primary_key=True)
return column_id
With the code above, I end up with a non-helpful error:
AttributeError: Neither 'next_value' object nor 'Comparator' object has an attribute '_set_parent_with_dispatch'
In an RTM moment, it looks like I missed a keyword: server_default.
#declared_attr
def id(cls):
sequence = cls.id_seq
column_id = sa.Column(sa.types.Integer, server_default=sequence.next_value(), primary_key=True)
return column_id

Spyne model for existing Database structure

I have an issue with defining model in spyne to generate several levels "in" SOAP11.
I used example at first, but my task is to generate service for tables already existing, so I got stuck and try to understand wheter to seek in Spyne properties or Sqlalchemy.
To be precise, i'll take example from site and show what i'm trying to reach:
class Permission(TableModel):
__tablename__ = 'permission'
id = UnsignedInteger32(pk=True)
application = Unicode(values=('usermgr', 'accountmgr'))
operation = Unicode(values=('read', 'modify', 'delete'))
perm_user_id = integer
last field is the FK for user table, but its name is different from user_id
class User(TableModel):
__tablename__ = 'user'
id = UnsignedInteger32(pk=True)
user_name = Unicode(32, min_len=4, pattern='[a-z0-9.]+', unique=True)
full_name = Unicode(64, pattern='\w+( \w+)+')
email = Unicode(64, pattern=r'[a-z0-9._%+-]+#[a-z0-9.-]+\.[A-Z]{2,4}')
last_pos = Point(2, index='gist')
permissions = Array(Permission).store_as('table')
--- SQL generated tries to add "WHEN user.id = permission.user_id" but I need another field (perm_user_id) to be filtered
Help me to define class to get correct inner tags.. actually it'll be about 3 more classes deep.
Thanx in Advance, Yury
Your answer is correct. Just as an alternative for simple tables, you can omit column definitions and let sqlalchemy's reflection engine figure it out.
meta = TableModel.Attributes.sqla_metadata
meta.reflect()
class User(TableModel):
__table__ = meta.tables['user']
The User class will be reconstructed using as much information as possible from the table columns and their types.
Found it myself, sorry to disturb anyone,
from spyne.model.complex import table
Permissions= Array(permission).customize(store_as=table(right='perm_user_id'))

Django1.8 (Django Rest Framework3.3.1) and Postgresql 9.3 - Programming Error

I've created views in my Postgres Database that have links in Django Rest Framework.
I have about 20 views altogether. On 7 of them - I keep getting this programming error:
ProgrammingError at /api/reports/
column report.event_type_id_id does not exist
LINE 1: SELECT "report"."id", "report"."ev...
All 7 have the same exact error message. All of the views are based off one table with all the same column names. The column referenced in the table is event_type_id. NOT event_type_id_id. So I'm not sure where it's getting that from. If it had the same error on all of them - it would make a little more sense but it's only 7.
I'm not sure where to begin even correcting this issue because I can't pinpoint what the exact problem is. I'm assuming it's on the database side and how django expects to receive something from the database - but I'm not entirely sure. Any ideas??
Thanks in advance!
UPDATE:
Exception Location:
/usr/local/lib/python2.7/dist-packages/django/db/backends/utils.py in execute
def execute(self, sql, params=None):
self.db.validate_no_broken_transaction()
with self.db.wrap_database_errors:
if params is None:
return self.cursor.execute(sql)
else:
return self.cursor.execute(sql, params) ...
def executemany(self, sql, param_list):
self.db.validate_no_broken_transaction()
with self.db.wrap_database_errors:
return self.cursor.executemany(sql, param_list)
Report Model Update:
class Report(models.Model):
event_type_id = models.ForeignKey(EventTypeRef, default='01')
event_at = models.DateTimeField("Event Time")
xxxxxx_id = models.ForeignKey(xxxxxx)
xxxx = models.BigIntegerField(blank=True, null=True)
color = models.IntegerField(blank=True, null=True)
xxxxx_info = models.CharField(db_column='xxxxxInfo', max_length=56, blank=True)
xxxx_tag = models.ForeignKey(xxxxxxxx, blank=True, null=True)
hidden = models.BooleanField(default=False)
def __unicode__(self): # __unicode__ on Python 2
return self.event_type_id
class Meta:
managed= False,
db_table = u'report'
verbose_name_plural = "XXXXX Reports"
According to the Django ForeignKey documentation:
Behind the scenes, Django appends "_id" to the field name to create
its database column name. In the above example, the database table for
the Car model will have a manufacturer_id column. (You can change this
explicitly by specifying db_column) However, your code should never
have to deal with the database column name, unless you write custom
SQL. You’ll always deal with the field names of your model object.
So, you should rename event_type_id to event_type