Using python class variables as dict key is good practice? - python

I wonder if i use class variables as keys in a dictionary can it be considered as good practice?
For example, this is object model in peewee.
class Abc:
name = CharField()
age = IntegerField()
then i declare a configuration dict for it like this
conf = {Abc.name: Config(listable=False, format_on_edit=True), Abc.age: Config()}
I don't want to use string like name, age as dict keys because i'm afraid of mistyping, and want to make sure that Object/ Model field is valid.
I see Sqlalchemy or Peewee are using condition like where(Abc.name=='abc') or filter(User.age == 25) , not where('name', 'abc') like many other orms from Go or PHP since they don't have class variables.
It's quite good for prevent mistyping.
I've tried hash(Abc.name) and it works then class variables are immutable for using as dict keys or not?

You may safely use them. Peewee replaces the field instances you declare as model attributes with special Descriptor objects (which then expose the underlying field instance, which is hashable).
For instance, when performing an insert or update, you can specify the data using the fields as keys:
User.insert({User.username: 'charlie'}).execute()

Related

Get properties of ndb model instance where Python name != datastore name

Goal: get "Python names" of attributes from an instance of Example, where the model was defined with a different datastore name
To provide some context, I have a custom to_dict() method for serializing an NDB Model. The core of the method is as follows:
for key, prop in self._properties.iteritems():
if hasattr(self, key):
value = getattr(self,key)
# do typical to_dict() stuff
If a model is defined as follows, everything is fine:
import Thing
class Example(ndb.Model):
things = ndb.KeyProperty(Thing, repeated=True)
However, there are issues if it defined where the the Python name is things but the datastore name is 'Thing':
# no import req'd
class Example(ndb.Model):
things = ndb.KeyProperty('Thing', repeated=True)
In the first scenario, the key from self._properties.iteritems() would be things. If I have an instance of Example, say example, then hasattr(example,'things') would evaluate to True.
In the second scenario, the key would be Thing and hasattr(example,'Thing') would evaluate to False, since the instance of Example has attributes defined by the Python name 'things'.
How can I get the properties of the instance? TIA.
ndb's own Model._to_dict method does it as follows (simplifying):
for prop in self._properties.itervalues():
name = prop._code_name
values[name] = prop._get_for_dict(self)
So: the name is taken from the _code_name of each property (not its key in self._properties, and the value is delegated to the property itself (via its _get_for_dict method) to allow further tweaking.
As a result, coding both of your examples as Example1 and Example2, whole their _properties.items() are respectively:
[('things', KeyProperty('things', repeated=True, kind='Thing'))]
[('Thing', KeyProperty('Thing', repeated=True))]
their ._to_dict(), as desired, both equal
{'things': [Key('Thing', 'roro')]}

Construct new django model object without loading all related models into memory

I want to be able to construct a new django object by specifying the primary keys of the related objects, rather than loading those related objects into memory to pass to the model's constructor. Is this possible? Is there a model creation factory or something similar that constructs the underlying SQL without actually loading the objects into memory?
Example:
class ObjectChildEntity(models.Model):
myobject = models.ForeignKey(MyObject)
some_data = models.TextField(null=False,blank=False)
related_stuff = models.ForeignKey(StuffModel)
I want to be able to do something like this:
new_child_entity= django.db.models.new(ObjectChildEntity, myobject__id = 123, some_data='foo', related_stuff__id = 456)
This of course isn't a real method, but what I want to accomplish is avoiding the loading of MyObject instance with id 123 into memory and the loading of StuffModel instance with id 456 into memory just for the purpose of passing these two objects into the ObjectChildEntity constructor.
Is there anything similar that exists for Django object creation without having to roll my own custom SQL?
This should work fine using the usual model class constructor and the _id name rather than an __id chained relationship as in your example code for the foreign key id:
new_child_entity = ObjectChildEntity(myobject_id=123, some_data='foo', related_stuff_id=456)
new_child_entity.save()
Or, if you've overridden the db_column field in the model field declaration, that name instead of myobject_id.

App Engine, Cross reference between two entities

i will like to have two types of entities referring to each other.
but python dont know about name of second entity class in the body of first yet.
so how shall i code.
class Business(db.Model):
bus_contact_info_ = db.ReferenceProperty(reference_class=Business_Info)
class Business_Info (db.Model):
my_business_ = db.ReferenceProperty(reference_class=Business)
if you advice to use reference in only one and use the implicitly created property
(which is a query object) in other.
then i question the CPU quota penalty of using query vs directly using get() on key
Pleas advise how to write this code in python
Queries are a little slower, and so they do use a bit more resources. ReferenceProperty does not require reference_class. So you could always define Business like:
class Business(db.Model):
bus_contact_info_ = db.ReferenceProperty()
There may also be better options for your datastructure too. Check out the modelling relationships article for some ideas.
Is this a one-to-one mapping? If this is a one-to-one mapping, you may be better off denormalizing your data.
Does it ever change? If not (and it is one-to-one), perhaps you could use entity groups and structure your data so that you could just directly use the keys / key names. You might be able to do this by making BusinessInfo a child of Business, then always use 'i' as the key_name. For example:
business = Business().put()
business_info = BusinessInfo(key_name='i', parent=business).put()
# Get business_info from business:
business_info = db.get(db.Key.from_path('BusinessInfo', 'i', parent=business))
# Get business from business_info:
business = db.get(business_info.parent())

SQLAlchemy introspection of declarative classes

I'm writing a small sqlalchemy shim to export data from a MySQL database with some lightweight data transformations—mostly changing field names. My current script works fine but requires me to essentially describe my model twice—once in the class declaration and once as a list of field names to iterate over.
I'm trying to figure out how to use introspection to identify properties on row-objects that are column accessors. The following works almost perfectly:
for attr, value in self.__class__.__dict__.iteritems():
if isinstance(value, sqlalchemy.orm.attributes.InstrumentedAttribute):
self.__class__._columns.append(attr)
except that my to-many relation accessors are also instances of sqlalchemy.orm.attributes.InstrumentedAttribute, and I need to skip those. Is there any way to distinguish between the two while I am inspecting the class dictionary?
Most of the documentation I'm finding on sqlalchemy introspection involves looking at metadata.table, but since I'm renaming columns, that data isn't trivially mappable.
The Mapper of each mapped entity has an attribute columns with all column definitions. For example, if you have a declarative class User you can access the mapper with User.__mapper__ and the columns with:
list(User.__mapper__.columns)
Each column has several attributes, including name (which might not be the same as the mapped attribute named key), nullable, unique and so on...
I'd still like to see an answer to this question, but I've worked around it by name-mangling the relationship accessors (e.g. '_otherentity' instead of 'otherentity') and then filtering on the name. Works fine for my purposes.
An InstrumentedAttribute instance has an an attribute called impl that is in practice a ScalarAttributeImpl, a ScalarObjectAttributeImpl, or a CollectionAttributeImpl.
I'm not sure how brittle this is, but I just check which one it is to determine whether an instance will ultimately return a list or a single object.

How can I tell if an Expando subclass has a property defined?

I'm creating an app that I want to have an expandable set of properties (each a RatingProperty) I also want to validate that any dynamic properties are of the RatingProperty type.
In the Expando documentation it says:
Tip: If you want to validate a dynamic property value using a Property class, you can instantiate the Property class and call its validate() method on the value.
So if I want to validate a dynamic property I need to know what the class's non-dynamic properties are. How can I ask my class what it's defined properties are?
I've considered creating a class method that takes a string and returns true if that string is in a list of property names that I create and maintain, but it seems like a hack. I've searched the Google for tips, but haven't had any luck.
Thanks,
Pat
After a bit more research (damn you lazyweb!) I've found a solution that I think is acceptable:
A dynamic property can't be of a db subclassed property type. Thus, there are two distinct steps that must be taken. First you need to create an instance of your property class and validate your value:
test = db.RatingProperty()
if test.validate(valueToSave):
#do your thing
Next you need to check if the property you want to save is a declared property:
if valueToSaveKey not in myObject.properties():
#if not save it as desired
myObject.valueToSaveKey = valueToSave
The down side here is that the value you save isn't stored as the property type you want.
http://code.google.com/appengine/docs/python/datastore/modelclass.html#Model_properties
db.Model has methods to find out all the properties on an instance.
The class exposes a list of Property objects: db.Model.properties()
The instance exposes the dynamic names only: instance.dynamic_properties()
You want to loop through the list and build Property objects, and run p.validate().
for p_name in instance.dynamic_properties():
p = db.RatingProperty()
p.validate() # raises BadValueError, etc.
I may be misunderstanding your question, but if you have a list of properties you expect to find, why not just use a standard db.Model, instead of an Expando? You can add additional properties to a Model class, as long as you either provide a default or don't make them required.
It's actually quite easy!
ExpandoObject implements (IDictionary<String, Object>) so you just need to do this :
dynamic person = new ExpandoObject();
person.FirstName = "Barack";
person.LastName = "Obama"
(((IDictionary<String, Object>)person).Keys
=> { "FirstName", "LastName" }
(((IDictionary<String, Object>)person).ContainsKey("FirstName")
=> true
Note: You need to explicitly cast to (IDictionary<string, object> because ExpandoObject explicitly implements this interface - and the instance itself doesn't have ContainsKey() or Keys.
Don't expect this method to work with all dynamic objects - just ExpandoObject and anything else that implements this interface.

Categories