One to Many
class Contact ( db . Model ):
# Basic info.
name = db . StringProperty ()
birth_day = db . DateProperty ()
# Address info.
address = db . PostalAddressProperty ()
# The original phone_number property has been replaced by
# an implicitly created property called 'phone_numbers'.
# Company info.
company_title = db . StringProperty ()
company_name = db . StringProperty ()
company_description = db . StringProperty ()
company_address = db . PostalAddressProperty ()
class PhoneNumber ( db . Model ):
contact = db . ReferenceProperty ( Contact ,
collection_name = 'phone_numbers' )
phone_type = db . StringProperty (
choices = ( 'home' , 'work' , 'fax' , 'mobile' , 'other' ))
number = db . PhoneNumberProperty ()
Everytime a reference property is created, an implicit collection property on the referenced class is created. The default name can be over-rode using collection_name.
Now the relationship can be created in the following way.
scott = Contact ( name = 'Scott' )
scott . put ()
PhoneNumber ( contact = scott ,
phone_type = 'home' ,
number = '(650) 555 - 2200' ) . put ()
PhoneNumber ( contact = scott ,
phone_type = 'mobile' ,
number = '(650) 555 - 2201' ) . put ()
Now the phone numbers for a give person can be retrieved in this way.
print 'Content-Type: text/html'
print
for phone in scott . phone_numbers :
print ' % s: % s' % ( phone . phone_type , phone . number )
Many to many
class Group ( db . Model ):
name = db . StringProperty ()
description = db . TextProperty ()
class Contact ( db . Model ):
# ID of user that owns this entry.
owner = db . StringProperty ()
# Basic info.
name = db . StringProperty ()
birth_day = db . DateProperty ()
# Address info.
address = db . PostalAddressProperty ()
# Company info.
company_title = db . StringProperty ()
company_name = db . StringProperty ()
company_description = db . StringProperty ()
company_address = db . PostalAddressProperty ()
# Group affiliation
groups = db . ListProperty ( db . Key )
friends = Group . gql ( "WHERE name = 'friends'" ) . get ()
mary = Contact . gql ( "WHERE name = 'Mary'" ) . get ()
if friends . key () not in mary . groups :
mary . groups . append ( friends . key ())
mary . put ()
class Group ( db . Model ):
name = db . StringProperty ()
description = db . TextProperty ()
@ property
def members ( self ):
return Contact . gql ( "WHERE groups = :1" , self . key ())
The limitations:
Must explicitly retrieve the values on the side of the collection where the list is stored since all you have available are Key objects
Avoid storing overly large lists of keys in a ListProperty
Relationship Model
class Contact ( db . Model ):
# ID of user that owns this entry.
owner = db . StringProperty ()
# Basic info.
name = db . StringProperty ()
birth_day = db . DateProperty ()
# Address info.
address = db . PostalAddressProperty ()
# The original organization properties have been replaced by
# an implicitly created property called 'companies'.
# Group affiliation
groups = db . ListProperty ( db . Key )
class Company ( db . Model ):
name = db . StringProperty ()
description = db . StringProperty ()
company_address = db . PostalAddressProperty ()
class ContactCompany ( db . Model ):
contact = db . ReferenceProperty ( Contact ,
required = True ,
collection_name = 'companies' )
company = db . ReferenceProperty ( Company ,
required = True ,
collection_name = 'contacts' )
title = db . StringProperty ()
mary = Contact . gql ( "name = 'Mary'" ) . get ()
google = Company . gql ( "name = 'Google'" ) . get ()
ContactCompany ( contact = mary ,
company = google ,
title = 'Engineer' ) . put ()
The advantage compared with list-of-keys is can have large collections on either side of the relationship. However, the traversing the connectionso of a collection will require more calls to teh databases.