Following backreferences of unknown kinds in NDB

2024/9/28 13:28:15

I'm in the process of writing my first RESTful web service atop GAE and the Python 2.7 runtime; I've started out using Guido's shiny new ndb API.

However, I'm unsure how to solve a particular case without the implicit back-reference feature of the original db API. If the user-agent requests a particular resource and those resources 1 degree removed:

host/api/kind/id?depth=2

What's the best way to discover a related collection of entities from the "one" in a one-to-many relationship, given that the kind of the related entity is unknown at development time?

  • I'm unable to use a replacement query as described in a previous SO inquiry due to the latter restriction. The fact that my model is definable at runtime (and therefore isn't hardcoded) prevents me from using a query to filter properties for matching keys.

  • Ancestor and other kindless queries are also out due to the datastore limitation that prevents me from filtering on a property without the kind specified.

Thus far, the only idea I've had (beyond reverting to the db api) is to use a cross-group transaction to write my own reference on the "one", either by updating an ndb.StringProperty(repeat=True) containing all the related kinds when an entity of a new kind is introduced or by simply maintaining a list of keys on the "one" ndb.KeyProperty(repeat=True) every time a related "many" entity is written to the datastore.

I'm hoping someone more experienced than myself can suggest a better approach.

Given jmort253's suggestion, I'll try to augment my question with a concrete example adapted from the docs:

class Contact(ndb.Expando):""" The One """# basic infoname = ndb.StringProperty()birth_day = ndb.DateProperty()# If I were using db, a collection called 'phone_numbers' would be implicitly # created here.  I could use this property to retrieve related phone numbers # when this entity was queried.  Since NDB lacks this feature, the service # will neither have a reference to query nor the means to know the # relationship exists in the first place since it cannot be hard-coded.  The# data model is extensible and user-defined at runtime; most relationships# will be described only in the data, and must be discoverable by the server.# In this case, when Contact is queried, I need a way to retrieve the# collection of phone numbers.# Company info.company_title = ndb.StringProperty()company_name = ndb.StringProperty()company_description = ndb.StringProperty()company_address = ndb.PostalAddressProperty()class PhoneNumber(ndb.Expando):""" The Many """# no collection_name='phone_numbers' equivalent exists for the key propertycontact = ndb.KeyProperty(kind='Contact')number = ndb.PhoneNumberProperty()
Answer

Interesting question! So basically you want to look at the Contact class and find out if there is some other model class that has a KeyProperty referencing it; in this example PhoneNumber (but there could be many).

I think the solution is to ask your users to explicitly add this link when the PhoneNumber class is created.

You can make this easy for your users by giving them a subclass of KeyProperty that takes care of this; e.g.

class LinkedKeyProperty(ndb.KeyProperty):def _fix_up(self, cls, code_name):super(LinkedKeyProperty, self)._fix_up(cls, code_name)modelclass = ndb.Model._kind_map[self._kind]collection_name = '%s_ref_%s_to_%s' % (cls.__name__,code_name,modelclass.__name__)setattr(modelclass, collection_name, (cls, self))

Exactly how you pick the name for the collection and the value to store there is up to you; just put something there that makes it easy for you to follow the link back. The example would create a new attribute on Contact:

Contact.PhoneNumber_ref_contact_to_Contact == (PhoneNumber, PhoneNumber.contact)

[edited to make the code working and to add an example. :-) ]

https://en.xdnf.cn/q/71337.html

Related Q&A

How to enable math in sphinx?

I am using sphinx with the pngmath extension to document my code that has a lot of mathematical expressions. Doing that in a *.rst file is working just fine.a \times b becomes: However, if I try the sa…

How to set the xticklabels for date in matplotlib

I am trying to plot values from two list. The x axis values are date. Tried these things so faryear = [20070102,20070806,20091208,20111109,20120816,20140117,20140813] yvalues = [-0.5,-0.5,-0.75,-0.75,…

PyParsing: Is this correct use of setParseAction()?

I have strings like this:"MSE 2110, 3030, 4102"I would like to output:[("MSE", 2110), ("MSE", 3030), ("MSE", 4102)]This is my way of going about it, although I h…

Indent and comments in function in Python

I am using Python 2.7 and wrote the following:def arithmetic(A):x=1 """ Some comments here """ if x=1:x=1elif x=2:x=2return 0But it has the indentation issue:if x=1:^ Ind…

Read a large big-endian binary file

I have a very large big-endian binary file. I know how many numbers in this file. I found a solution how to read big-endian file using struct and it works perfect if file is small:data = []file = open(…

SWIG Python Structure Array

Ive been searching for a few days trying to figure out how to turn an array of structures into a Python list. I have a function that returns a pointer to the beginning of the array.struct foo {int memb…

Hashing tuple in Python causing different results in different systems

I was practicing tuple hashing. In there I was working on Python 2.7. Below is the code:num = int(raw_input()) num_list = [int(x) for x in raw_input().split()] print(hash(tuple(num_list)))The above cod…

ctypes pointer into the middle of a numpy array

I know how to get a ctypes pointer to the beginning of a numpy array:a = np.arange(10000, dtype=np.double) p = a.ctypes.data_as(POINTER(c_double)) p.contents c_double(0.0)however, I need to pass the po…

Extracting unsigned char from array of numpy.uint8

I have code to extract a numeric value from a python sequence, and it works well in most cases, but not for a numpy array.When I try to extract an unsigned char, I do the followingunsigned char val = b…

How to hold keys down with pynput?

Im using pynput and I would like to be able to hold keys down, specifically wasd but when I try and run this code it only presses the key and doesnt hold it for 2 seconds. If anyone knows what Im doing…