Question

class Student(db.Model):
    teacher = db.ReferenceProperty(Teacher, collection_name='students')
    name = db.StringProperty(required=True)
    zip_code = db.IntegerProperty(required=True)
    square_footage = db.IntegerProperty(required=True)
    month_entries = db.IntegerProperty(required=True)  

class Bill(db.Model):
    student = db.ReferenceProperty(Student, collection_name='bills')
    bill_month = db.DateProperty(required=True)
    energy = db.IntegerProperty(required=True)

From my models setup shown above... I can easily show all the Bills stored using something like this:

bill = models.Bill.all()
for stubs in bill:
    print stubs.energy
    print stubs.student.name

But how do I list what Bills each student has? In SQL I would say something like:

SELECT * FROM Bill WHERE Student.Name = Samuel

I guess I don't understand how to retrieve the Bills given by ReferenceProperty. It doesn't seem so simple in GQL. How do I query by Reference Property?

Was it helpful?

Solution

The ReferenceProperty creates an automatic query in the referenced entity (using the collection_name if you provided one, which you did):

sams_bills = Student.all().filter("name =", "Samuel").get().bills

sams_bills is now a db.Query for the bills, which you can call .fetch() on to retrieve one or more bills.

OTHER TIPS

I think the hardest thing for people with SQL experience to grok about App Engine is that a lot of stuff requires two queries to get the results you want.

student = Student.all().filter('name =', 'Samuel').get()
bill = Bill.all().filter('student =', student.key()).get()

The second hardest thing for people with SQL experience to grok is that hardly anyone uses GQL. ;)

The collection_name parameter of the db.ReferenceProperty "student" in the Bill class has already set up a query for you. So all you have to do is this:

student = Student.all().filter('name =', 'Samuel').get()
for bill in student.bills:
    logging.info('Student %s Month:%s Energy:%d' % (student.name, str(bill.bill_month), bill.energy)

Now the results returned by the back-referenced query are unordered. You can (if you have your indexes set up right) use .order() to return them in a particular order, or you can put them into a Set and sort them in memory (very fast) like this:

sorted_bills = []
for bill in student.bills:
    sorted_bills.append(bill)

# Sort additions by month then by amount (secondary key sorts first in code)
sorted_bills = sorted(sorted_bills, key=lambda Bill: Bill.energy, reverse=True)
sorted_bills = sorted(sorted_bills, key=lambda Bill: Bill.bill_month, reverse=False)

In this example, if a student had more than one bill with the same bill_month value, the largest bills would be sorted first (note the reverse=True parameter).

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top