Datastore query two entity kinds, on a common property? - google-app-engine

Say I have two entity kinds:
class image(db.Model):
url = db.LinkProperty()
date= db.DateTimeProperty()
class video(db.Model):
url = db.LinkProperty()
date= db.DateTimeProperty()
Which each may have some other (unimportant here) properties.
What I want to do is somehow merge the queries:
i = image.gql('ORDER BY date LIMIT 10')
v = video.gql('ORDER BY date LIMIT 10')
Such that I am left with a single GqlQuery object that is the result as if image and video were the same kind.
Is it possible without doing something like:
merged = ([a for a in i] + [b for b in v]).sort(key=lambda x: x.date)[:10]
Being left with an actual GqlQuery object instead of a list of entities would be a plus, though I have everything I need from the latter.

The only way with inheritance and different classes is to use a PolyModel then your class hierarchy would be
class Media(db.Model):
url = db.LinkProperty()
date= db.DateTimeProperty()
class Image(Media):
pass
class Video(Media):
pass
Then in GQL and preferably Query objects
To get all media types
query = Media.query().order(Media.date)
To just get Video
query = Video.query().order(Video.date)
Or don't have different classes. Have a single Media class and a field that denotes a media type.
Docs for PolyModel can be found here - https://developers.google.com/appengine/docs/python/ndb/polymodelclass

Related

Problems with StructuredProperty and StringProperty

i am doing the finally degree work in Google App Engine, but i am having problems when i try this:
class Predicate(ndb.Model):
name = ndb.StringProperty()
parameters = ndb.JsonProperty()
class State(ndb.Model):
predicates = ndb.StructuredProperty(Predicate, repeated=True)
class Action(ndb.Model):
name = ndb.StringProperty()
parameters = ndb.StringProperty(repeated=True)
preconditions = ndb.StructuredProperty(Predicate, repeated=True)
predicatesToAdd = ndb.StructuredProperty(Predicate, repeated=True)
predicatesToDel = ndb.StructuredProperty(Predicate, repeated=True)
class Plan(ndb.Model):
plan = ndb.StructuredProperty(Predicate, repeated=True)
class Problem(ndb.Model):
initialState = ndb.StructuredProperty(Predicate)
goalState = ndb.StructuredProperty(Predicate)
actions = ndb.StructuredProperty(Action, repeated=True)
i get this error:
TypeError: This StructuredProperty cannot use repeated=True because its model class (Predicate) contains repeated properties (directly or indirectly).
StructuredProperty, if it contains repetitions, can not be replicated another StructuredProperty. But I need this structure models. How can i solve this?
And sorry for my bad english :(
I solved this problem using LocalStructuredProperty, but I think it will not work at all
The problem with your design is that ndb does not allow nested repeated properties. In other words, you cannot have a repeated structured property, which in turn has its own repeated property. If you remove the repeated=True from the parameters property, it will work.
You will need to re-think your design to work around this. One possible solution may be to use a JsonProperty for parameters, and store the list of strings as a JSON string. You won't be able to query them then of course, but it may work out depending on your requirements.

Replace Django ManyToMany fields with chained strings or convert to first normal form

Suppose that I have a Position table that specifies a user's position (leader, assistant, member, ...):
class Position(models.Model):
name = CharField(max_length=20)
A document has a title and privileges, namely, create, modify, and so on. We may specify which user positions may perform which privileges; e.g., a leader or an assistant may create a document:
class Document(models.Model):
title = CharField(max_length=50)
create = ManyToManyField(Position)
modify = ManyToManyField(Position)
...
Of course, the above arrangement is not acceptable in Django because there should be only one ManyToManyField in a model.
I wonder which one of the followings is a better solution:
(a) Chain the positions (provided the number of positions are not great and the position data will not change):
class = Document(...):
...
create = CharField(max_length=100)
modify = CharField(max_length=100)
where create may be leader-assistance-member, which means a leader, an assistance, or a member may create a document. All we have to do is to split the string to obtain a list of positions.
(b) Convert to 1NF:
class = Document(...)
title = ...
class Create(...):
document = ForeignKey(Document)
position = ForeignKey(Position)
class Modify(...):
document = ForeignKey(Document)
position = ForeignKey(Position)
I know this question is old, but per Django docs, you could have multiple many-to-many fields referencing the same model. You'd just need to specify a related_name to differentiate them.
class Document(models.Model):
title = models.CharField(max_length=50)
create = models.ManyToManyField(Position, related_name='create_positions')
modify = models.ManyToManyField(Position, related_name='modify_positions')
...

Google App Engine NDB repeated property additional info

For example: I have an Article model with a repeated "title" property that stores translations in different languages of the original title:
class Article(ndb.Model):
title = ndb.StringProperty(repeated=True)
How can I store, besides the title property, the language code of the title, so I can get specific versions of the title, something like this:
en_title = article.title['en']
It is important to have the same property name since I don't know in what language the article title will be queried by.
You can use repeated structure property:
class Title(ndb.Model):
title = ndb.StringProperty()
lang = ndb.StringProperty()
class Article(ndb.Model):
titles = ndb.StructuredProperty(Title, repeated=True)
Are you querying on the titles or languages? If not, you can use PickleProperty or JsonProperty to store a dict.

How to retrieve Google App Engine entities by ancestor

I have the following 2 models in my Google App Engine datastore:
class Search(db.Model):
what = db.StringProperty()
class SearchResult(db.Model):
search = db.ReferenceProperty(Search)
title = db.StringProperty()
content = db.StringProperty()
And, I am trying to retrieve all SearchResult entities for a given Search entity in the following function:
def get_previous_search_results(what='', where=''):
search_results = None
search = db.GqlQuery("SELECT * FROM Search WHERE what = :1", what).fetch(1)
if search:
search_results = db.GqlQuery("SELECT * FROM SearchResult WHERE ANCESTOR IS :1", search[0].key()).fetch(10)
return search_results
However, it always returns an empty set.
Any ideas what I am doing wrong? I've read through the Python Datastore API docs and this seem like the correct way to do this, but it's not working.
Are you creating the Search entities with a parent? The ReferenceProperty doesn't create an ancestor relationship, and it seems likely you might want search.searchresult_set, which will be a Query for SearchResult objects that have a reference to the Search object 'search'.

What is the best way to store multiple date strings in Django?

I'm building a Django app that needs to store multiple selected dates for an event. The first thing that came to mind was build the event model:
class Event(models.Model):
title = models.CharField(max_length=200)
creator = models.ForeignKey(User)
modified = models.DateTimeField(auto_now=True, auto_now_add=False)
created = models.DateTimeField(auto_now=False, auto_now_add=True)
def __unicode__(self):
return self.title
class Meta:
ordering = ('title',)
Then build a separate table of EventDates:
class EventDate(models.Model):
event = models.ForeignKey(Event)
date = models.DateField()
modified = models.DateTimeField(auto_now=True, auto_now_add=False)
created = models.DateTimeField(auto_now=False, auto_now_add=True)
def __unicode__(self):
return "%s / %s" % (self.event, self.date)
class Meta:
ordering = ('created',)
But is this the best way? Is there a better performing alternative, like a comma separated string?
The best way is the one that best serves your purposes. There is no built-in comma separated field in Django, but you can easily roll your own one - the problem is if this is what you really need.
For example - if you need to filter events based on their dates, I'm not sure how you could easily do this with such comma separated field, but I can clearly see how you could do this with your current approach:
Event.objects.filter(eventdate_set__date=my_date)
-- so unless you specify your planned usage pattern, I don't think there is a general answer.

Resources