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.
Related
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()
How can I get corresponding Python type of a Django model's field class ?
from django.db import models
class MyModel(models.Model):
value = models.DecimalField()
type(MyModel._meta.get_field('value')) # <class 'django.db.models.fields.DecimalField'>
I'm looking how can I get corresponding python type for field's value - decimal.Decimal in this case.
Any idea ?
p.s. I've attempted to work around this with field's default attribute, but it probably won't work in all cases where field has no default value defined.
I don't think you can decide the actual python type programmatically there. Part of this is due to python's dynamic type. If you look at the doc for converting values to python objects, there is no hard predefined type for a field: you can write a custom field that returns object in different types depending on the database value. The doc of model fields specifies what Python type corresponds to each field type, so you can do this "statically".
But why would you need to know the Python types in advance in order to serialize them? The serialize modules are supposed to do this for you, just throw them the objects you need to serialize. Python is a dynamically typed language.
An ugly alternative is to check the field's repr():
if 'DecimalField' in repr(model._meta.get_field(fieldname)):
return decimal.Decimal
else:
...
However, you have to this for all types seperatly.
I am leveraging ndb's to_dict method to convert an object's properties into a python dict. From everything I can tell, this method does not include the object's key or parent within the dict as per the documentation:
https://developers.google.com/appengine/docs/python/ndb/modelclass#Model_to_dict
However for my situation I need the key to be in the dict. My preference would be to leverage the builtin method and subclass it or something similar rather than create my own to_dict method.
What is the best way to accomplish this or am I missing something obvious? Thanks in advance.
FYI: I am not leveraging django for this project but instead straight python deployed up to gae.
You're not missing anything ;-)
Just add the key to the dictionary after you call to_dict, and yes override the method.
If you have multiple models that don't share the same base class with your custom to_dict, I would implement it as a mixin.
to define to_dict as a method of a Mixin class. you would
class ModelUtils(object):
def to_dict(self):
result = super(ModelUtils,self).to_dict()
result['key'] = self.key.id() #get the key as a string
return result
Then to use it.
class MyModel(ModelUtils,ndb.Model):
# some properties etc...
Another easy way to achieve that (without having to override to_dict) is to add a ComputedProperty that returns the id, like so:
class MyModel(ndb.Model):
# this property always returns the value of self.key.id()
uid = ndb.ComputedProperty(lambda self: self.key.id(), indexed=False)
# other properties ...
A ComputedProperty will be added to the result of to_dict just like any other property.
There are just two constraints:
Apparently the name of the property can not be key (since that would conflict with the actual key) and id doesn't work either.
This won't work if you don't specify a key or id when you create the object.
Also, the computed value will be written to the data store when you call put(), so it consumes some of your storage space.
An advantage is that this supports the include and exclude arguments of to_dict() out of the box.
I'm writing an interface to be used by two applications. This interface should use some DoSomethingRequest and DoSomethingResponse classes to do the communication.
Is there any library that does some model validation, for example like Django's Model?
I basically want to be able to say something like:
Object A must have a "text" property of type str(), a "number" property of type int(), an "items" property of type list(). In a DRY way.
I'm looking for something like the following, or better:
class MyEmbeddedModelClass(EmbeddedModel):
text = TextField(required = True)
class MyModel(Model):
text = TextField(required = True)
number = IntField(default = 0)
items = ListField(EmbeddedModel)
a = MyModel()
a.text = "aaaa"
a.number = 1
a.items = [
MyEmbeddedModelClass("bbbb"),
MyEmbeddedModelClass("cccc"),
MyEmbeddedModelClass("dddd")
]
a.validate()
I know I can write my own, but I'd rather use a library if available, I'm a bit new to this.
If you want to enforce interfaces, or use design-by-contract, then you probably want the zope.interface library. Despite the name, which reflects its origins in Zope, it's not actually tied to that framework at all and is quite usable outside.
I think decorators could be used for this.
check this link
Combining Descriptors with Class Decorators for Validation
For a different approach check Duck typing
Because python is dynamic, the convention is to require an object to behave like an instance of a particular class rather than enforce a specific type.
Somewhere in your code, preferably at the point where you need to access those properties, but as early as possible assert that the object has those properties and further assert that those properties are what you expect them to be.
This raises an AssertionError exception if the object o, regardless of type, if it is missing the 'someattribute' attribute:
assert(hasattr(o, 'someattribute'))
Further, if o.someattribute is not a string:
assert(isinstance(o.someattribute, basestring))
Is there a way to get the key (or id) value of a db.ReferenceProperty, without dereferencing the actual entity it points to? I have been digging around - it looks like the key is stored as the property name preceeded with an _, but I have been unable to get any code working. Examples would be much appreciated. Thanks.
EDIT: Here is what I have unsuccessfully tried:
class Comment(db.Model):
series = db.ReferenceProperty(reference_class=Series);
def series_id(self):
return self._series
And in my template:
more
The result:
more
Actually, the way that you are advocating accessing the key for a ReferenceProperty might well not exist in the future. Attributes that begin with '_' in python are generally accepted to be "protected" in that things that are closely bound and intimate with its implementation can use them, but things that are updated with the implementation must change when it changes.
However, there is a way through the public interface that you can access the key for your reference-property so that it will be safe in the future. I'll revise the above example:
class Comment(db.Model):
series = db.ReferenceProperty(reference_class=Series);
def series_id(self):
return Comment.series.get_value_for_datastore(self)
When you access properties via the class it is associated, you get the property object itself, which has a public method that can get the underlying values.
You're correct - the key is stored as the property name prefixed with '_'. You should just be able to access it directly on the model object. Can you demonstrate what you're trying? I've used this technique in the past with no problems.
Edit: Have you tried calling series_id() directly, or referencing _series in your template directly? I'm not sure whether Django automatically calls methods with no arguments if you specify them in this context. You could also try putting the #property decorator on the method.