GAE (Python) Defining entity relationships in ndb - python

How would you go about creating a relationship between two different entity models?
When I try this I get an error:
class Spec(ndb.Model):
userKey = ndb.KeyProperty(kind=User)
class User(ndb.Model):
specs = ndb.KeyProperty(kind=Spec, repeated=True)
The error as I understand stems from referencing User before it is defined.
I did the following to solve it, and I use a get_by_id, but I do not like this solution:
class Spec(ndb.Model):
userKey = ndb.IntegerProperty()
class User(ndb.Model):
specs = ndb.KeyProperty(kind=Spec, repeated=True)
How would you solve this so I can define my models as in the first example? Even better, how would you go about to define each class in its own file/module.
I tried following this article, but it seems to be be outdated and not relevant to ndb.
https://developers.google.com/appengine/articles/modeling
Thank you

As the docs show, the kind argument can be a string. So use kind='User'.

Related

How can I create functions that work for different Model classes in GAE?

I have multiple classes for which I have special functions that query ndb in a shorter way, like in this example:
class SomeModel(ndb.Model):
xcode = ndb.StringProperty('c')
descr = ndb.StringProperty('d')
client = ndb.KeyProperty('cl')
order = ndb.IntegerProperty('o')
mod = ndb.DateTimeProperty(auto_now=True)
#classmethod
def q_base(cls, ancestor):
return cls.query(ancestor=ancestor).order(cls.codigo)
The function q_base saves some space and makes the code in the handlers look clearer. But since quite a few models need this exact function, I have to repeat it multiple times, which is a problem.
How can I solve it? Can I just make a BaseClass(ndb.Model), add the functions there and make every other model inherit from it? Or do I have to use PolyModel for that? How would that look? Also, I would appreciate any insight as to what would happen to any existint entities.
I have no experience with GAE but unless they do some very strange things, the canonical solution would be to use either an abstract base class inheriting from ndb.Model - if ndb supports abstract model classes - or a mixin:
class QBaseMixin(object):
#classmethod
def q_base(cls, ancestor):
return cls.query(ancestor=ancestor).order(cls.codigo)
class MyModel(ndb.Model, QBaseMixin):
# model code here

is it possible to make a query lookup for given model inheritance?

Below are my models and I am using InheritanceManager of django-model-utils. i decided the field user to be in the subclasses because i need to access the Child subclass via the relation like user.child1_set.all().
class Mother(models.Model):
objects = InheritanceManager()
class Child1(Mother):
user = models.ForiegnKey(User)
class Child2(Mother):
user = models.ForiegnKey(User)
the problem is, when i want to query starting from Mother class, there seems to be no query that makes it.
i've tried these codes.
Mother.objects.filter(user=SOMEUSER)
Mother.objects.filter(child1__user=SOMEUSER)
Mother.objects.select_subclasses().filder(user=SOMEUSER)
Mother.objects.select_subclasses().filder(child1__user=SOMEUSER)
any advice would be appreciated.

Can I change DB table name from the default automatically on Django?

I would like to change the DB table names on Django1.9. I know we can change the standard issue with "db_table".
Class Foo_Bar:
class Meta:
db_table = "foo_bar"
But I need to write that in every single class and it is tiresome.
I want Django creates a table whose name is lower-cased class name automatically.
But I have no idea how to do.
I even tried to use
self.__class__.name__.lower()
but, I didn't know how Meta works well.
Any advice is helpful.
Thank you.
A very hack-ish method but this code will give you the outer (since you want to get Foo_Bar, not Meta) class name:
import traceback
Class Foo_Bar:
...
class Meta:
db_table = traceback.extract_stack()[-2][2].lower()

Order of defining models in django

I have some problem with order of defining models in django,so i want some thing like this :
class Album(models.Model):
mainTrack = models.OneToOneField(Track)
class Track(models.Model):
albumID = models.ForeignKey(Album)
and in this way when i want run makemigration command,django give this error:
Track is not defined
there is exist any way to solve that??
As you already noticed this line
mainTrack = models.OneToOneField(Track)
references Track but obviously Track is not defined at this time.
Solution:
Reference to the Track model using a string:
mainTrack = models.OneToOneField('Track')
This is also mentioned in the docs:
If you need to create a relationship on a model that has not yet been defined, you can use the name of the model, rather than the model object itself.
You should add related_name="track" to your ForeignKey call.
class Album(models.Model):
mainTrack = models.OneToOneField(Track)
class Track(models.Model):
albumID = models.ForeignKey('Album', related_name="track")

Bi-directional relationship in mongoengine

I need to use a bi-directional relationship in Mongoengine which is something like the below.
from mongoengine import *
class Notification(Document):
desc = StringField()
from_user = ReferenceField('User')
class User(Document):
Name = StringField()
notifications = ListField(EmbeddedDocumentField(Notification))
I know we can put single quoted class name there when the class has not yet defined.
from_user = ReferenceField('User')
However, we got a problem here. Seems like in runtime it interprets our class as mongoengine.django.auth.user instead of our custom user class. (This is just what I guess but in runtime during debug mode I find that it misinterprets it as mongoengine.django.auth.user although the record in the collections should belong to the custom user class)
So is there any way for me to specify a fully qualified class name there?
Thanks!
In this instance you'd need to declare the User class after the Notification class.
Internally mongoengine uses a class registry, which is populated via the Document metaclass. Unfortunately, namespacing isn't the same as in the java world (I never thought I'd say that!) so as far as I know its not possible to determine the full location name for a class eg: myapp.models.User
Are you using the django User class? as well as another User class - this will cause issues with the registry as currently you can only have one class per name.

Categories