How does peewee's get method knows how to generate where clause? - python

Python's peewee orm library allows me to query database using the get method like this:
grandma = Person.get(Person.name == 'Grandma L.')
This query will filter the resultset based on Person's name doing a sql where behind the scenes.
I know the expression Person.name == 'Grandma L.' is evaluated first and the get method receives just a boolean value.
How does the get method inspect it's arguments to detect that the filter needs to be applyed to the 'name' field ?
PS: I read peewee's source but couldn't have any clue how it does that.

I know the expression Person.name == 'Grandma L.' is evaluated first and the get method receives just a boolean value.
I don't know Peewee specifically but I do know how this sort of thing is done.
Basically, the second part of your sentence isn't true. name is of a custom type. Its __eq__ method doesn't return just a Boolean value, but rather an object that contains information on what comparison was actually done. (This class might even derived from bool so it works like a Boolean in other contexts.) Its other rich comparison methods are similar.
But how does Person.name know that its name is name? The answer to that is that Person probably doesn't actually have a name attribute. Instead, it has a __getattr__() method that returns the name object, which is the custom class that has the __eq__ method I just described.
Since Person.__getattr__() receives the name of the attribute, it can bake that name into the value it returns for name. Then the custom __eq__ method on name returns a Boolean-like object that contains some representation of name == 'Grandma L.' inside it. And Person.get() uses this representation to put together the query.

Related

Django how to query objects one by one

I have to query an object from a model, this object is called "exercise" and has many fields(title, body, answers, etc.) I need to get "exercise objects" one by one with all their fields, do some rendering on them and give back a pdf of the exercise as result.
The problem is, if I do:
exercises = ExerciseModel.objects.all()
I get all of them. If I do:
some_exercises = ExerciseModel.objects.filter(something=something)
I get "some of them" depending on filter. And if i do:
exercise = ExerciseModel.objects.get()
I get
error get() returned more than one exercise
How can I get them one by one? I must be able to use them as input for another function.
If you need to perform the task on only 1 exercise, use get() instead. In such case, you need a criteria to make sure get() will return 1 and only 1 result.
Example:
ex = ExerciseModel.objects.get(pk=123)
From the doc:
Returns the object matching the given lookup parameters, which should be in the format described in Field lookups.
get() raises MultipleObjectsReturned if more than one object was found. The MultipleObjectsReturned exception is an attribute of the model class.
get() raises a DoesNotExist exception if an object wasn’t found for the given parameters. This exception is an attribute of the model class.
When you have a QuerySet with filters that ensure the underlying SQL request will return only 1 row, you can call get() without argument on the QuerySet. This return the row as model instance, instead of returning it as a list containing 1 elemnt.
Original answer:
Both filter() and all() methods return a QuerySet instance. You can iterate on it to perform a task for each "exercise" returned by your request
for exercise in ExerciseModel.objects.filter(something=something):
# ... do what you need on your exercise
From the documentation:
A QuerySet is iterable, and it executes its database query the first time you iterate over it. For example, this will print the headline of all entries in the database
What you need is .iterator() which will turn a queryset to an iterator:
exercises = ExerciseModel.objects.all().iterator()
then you get iterate over it in a for loop:
for exercise in exercises:
...
This will improve performance when you have large number of items. However, it has some downsides as well as stated in the docs
Hope it helps!
.get() must return a single object, not a QuerySet instance. If you want to get a single exercise then you must pass a parameter to the .get instance. For example, retrieving an object by name would require the following code:
exercise = ExerciseModel.objects.get(name="an_exercise")
If you want to iterate through all the objects without actually retrieving a QuerySet containing the objects, you could use the following code:
for i in range(Exercise.objects.all().count()):
exercise = Exercise.objects.get(pk=i)
... operate on object ...

Purpose of .query in python

I am trying to understand the code used in my new job's web-application. In their models.py file, I see that they call a lot of classes with the .query method, which will then be set equal to a new variable. For example:
def child_variant(self):
#for checking if the current variant is an original variant and has a child variant (the hidden variant record) and if so returning it
child_variant = Variant.query.filter(Variant.original_variant_id==self.id).first()
if child_variant:
return child_variant
else:
return False
I am not sure if the .query method has a special purpose, for example running through their database, and is referring to a sort of SQL command, or if it is referring to some sort of jQuery command.

Filter by an object in SQLAlchemy

I have a declared model where the table stores a "raw" path identifier of an object. I then have a #hybrid_property which allows directly getting and setting the object which is identified by this field (which is not another declarative model). Is there a way to query directly on this high level?
I can do this:
session.query(Member).filter_by(program_raw=my_program.raw)
I want to be able to do this:
session.query(Member).filter_by(program=my_program)
where my_program.raw == "path/to/a/program"
Member has a field program_raw and a property program which gets the correct Program instance and sets the appropriate program_raw value. Program has a simple raw field which identifies it uniquely. I can provide more code if necessary.
The problem is that currently, SQLAlchemy simply tries to pass the program instance as a parameter to the query, instead of its raw value. This results in a Error binding parameter 0 - probably unsupported type. error.
Either, SQLAlchemy needs to know that when comparing the program, it must use Member.program_raw and match that against the raw property of the parameter. Getting it to use Member.program_raw is done simply using #program.expression but I can't figure out how to translate the Program parameter correctly (using a Comparator?), and/or
SQLAlchemy should know that when I filter by a Program instance, it should use the raw attribute.
My use-case is perhaps a bit abstract, but imagine I stored a serialized RGB value in the database and had a property with a Color class on the model. I want to filter by the Color class, and not have to deal with RGB values in my filters. The color class has no problems telling me its RGB value.
Figured it out by reading the source for relationship. The trick is to use a custom Comparator for the property, which knows how to compare two things. In my case it's as simple as:
from sqlalchemy.ext.hybrid import Comparator, hybrid_property
class ProgramComparator(Comparator):
def __eq__(self, other):
# Should check for case of `other is None`
return self.__clause_element__() == other.raw
class Member(Base):
# ...
program_raw = Column(String(80), index=True)
#hybrid_property
def program(self):
return Program(self.program_raw)
#program.comparator
def program(cls):
# program_raw becomes __clause_element__ in the Comparator.
return ProgramComparator(cls.program_raw)
#program.setter
def program(self, value):
self.program_raw = value.raw
Note: In my case, Program('abc') == Program('abc') (I've overridden __new__), so I can just return a "new" Program all the time. For other cases, the instance should probably be lazily created and stored in the Member instance.

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.

How do I get the key value of a db.ReferenceProperty without a database hit?

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.

Categories