App Engine - Datastore - Python: Delete element within a StructuredProperty - google-app-engine

I have a StructuredProperty that looks like this:
userDB(key=Key('userDB', 5580090230439936), name=u'Super User', orgs=[providers(name=u'Comp, Inc.', password=u'1111111', url=None, username=u'111111', value=u'comp'), providers(name=u'Systems, Inc.', password=u'2222222', url=None, username=u'222222', value=u'system')], update=None, userID=u'super#example.com')
I would like to delete every provider who's 'value' == 'system'.
class providers(EndpointsModel):
name = ndb.StringProperty()
value = ndb.StringProperty()
url = ndb.StringProperty()
username = ndb.StringProperty()
password = ndb.StringProperty()
class userDB(EndpointsModel):
userID = ndb.StringProperty(required=True, indexed=True)
name = ndb.StringProperty(required=True, indexed=True)
update = ndb.DateTimeProperty(auto_now_add=True, indexed=True)
orgs = ndb.StructuredProperty(providers, repeated=True, indexed=True)
system = ndb.StructuredProperty(system, repeated=True, indexed=True)
comp = ndb.StructuredProperty(comp, repeated=True, indexed=True)
I tried this:
def delOrgs(key, X): #Key is a userDB key and X is a list ['system']
for B in X:
for A in key[0].get().orgs:
del_provider = key[0].get().query(A.value == B).fetch(keys_only=True)
#del_provider[0].delete()
logging.info(del_provider)
but i get the following error:
TypeError: Cannot filter a non-Node argument; received False
Any help would be greatly appreciated.

Your query should look like:
userDB.query(userDB.orgs.value == 'system)
This will return all of the userDBs which have a provider with value == 'system'.
You'll then need to update the 'orgs' property of each, removing any that you don't want, and then re-put the entities:
users = query.fetch()
for user in users:
user.orgs = filter(lambda provider: provider.value != 'system', user.orgs)
ndb.put_multi(users)
Structured properties don't (or shouldn't) exist as independent entities, so you can't fetch them independently of the entity that contains them, and can't delete them directly.

Related

How to create an object attribute without writing to database -- peewee -- python

Maybe i have an understanding problem. I try to make 2 tabeles in one database. But additionaly i need to have some temporary values in one class that i doen´t want to write to the database.
I try to switch to peewee and read the dokumentation but i find no solution at my own.
without peewee i would make an init method where i write my attributes. But where did i have to write them now?
from peewee import *
import datetime
db = SqliteDatabase('test.db', pragmas={'foreign_keys': 1})
class BaseModel(Model):
class Meta:
database = db
class Sensor(BaseModel):
id = IntegerField(primary_key=True)
sort = IntegerField()
name = TextField()
#def __init__(self):
#self.sometemporaryvariable = "blabla"
def meineparameter(self, hui):
self.hui = hui
print(self.hui)
class Sensor_measure(BaseModel):
id = ForeignKeyField(Sensor, backref="sensorvalues")
timestamp = DateTimeField(default=datetime.datetime.now)
value = FloatField()
class Meta:
primary_key = CompositeKey("id", "timestamp")
db.connect()
db.create_tables([Sensor_measure, Sensor])
sensor1 = Sensor.create(id=2, sort=20, name="Sensor2")
#sensor1.sometemporaryvariable = "not so important to write to the database"
sensor1.save()
Remember to call super() whenever overriding a method in a subclass:
class Sensor(BaseModel):
id = IntegerField(primary_key=True)
sort = IntegerField()
name = TextField()
def __init__(self, **kwargs):
self.sometemporaryvariable = "blabla"
super().__init__(**kwargs)

django how to save a big model with for loop in views.py?

I have a very big model in models.py:
simplified version is:
class MyModel(models.Model):
item_1 = models.FloatField(null=True, blank=True)
...
item_20 = models.FloatField(null=True, blank=True)
in views.py:
def form_valid(self, form_class):
instance = form_class.save(commit=False)
for i in range(1, 20):
name = 'item_' + str(i)
instance.name = i
With this the field name 'item_1' ... to 'item_20' in instance is not recogniced. Instead 'name' is added to instance like other new field...
How can I iterate and save my model?
Any suggestion?
Thanks!!!
You should probably use setattr in order to loop through the fields and set the values in them. Try this:
def form_valid(self, form_class):
instance = form_class.save(commit=False)
for i in range(1, 20):
name = 'item_' + str(i)
setattr(instance, name, value) # Where value is the data you wanted to save in the field `name`
Similary user getattr() to get the data by looping through the class instance.

Query for repeated ndb.KeyProperty not working

What's wrong with my query?
Here are my models:
class Positions(ndb.Model):
title = ndb.StringProperty(indexed=True)
summary = ndb.TextProperty()
duties = ndb.TextProperty()
dateCreated = ndb.DateTimeProperty(auto_now_add=True)
dateUpdated = ndb.DateTimeProperty(auto_now=True)
class Applicants(ndb.Model):
name = ndb.StringProperty(indexed=True)
position = ndb.KeyProperty(kind=Positions,repeated=True)
file = ndb.BlobKeyProperty()
dateCreated = ndb.DateTimeProperty(auto_now_add=True)
dateUpdated = ndb.DateTimeProperty(auto_now=True)
Here is my query:
class AdminPositionInfoHandler(BaseHandler):
def get(self,positionKeyId):
user = users.get_current_user()
if users.is_current_user_admin():
positionKey = ndb.Key('Positions',int(positionKeyId))
position = positionKey.get()
applicants = Applicants.query(position=position.key).fetch() # the query
values = {
'position': position,
'applicants': applicants,
}
self.render_html('admin-position-info.html',values)
else:
self.redirect(users.create_login_url(self.request.uri))
What seems to be wrong in using the query:
applicants = Applicants.query(position=position.key).fetch()
I got this error:
File "C:\xampp\htdocs\angelstouch\main.py", line 212, in get
applicants = Applicants.query(position=position.key).fetch()
...
TypeError: __init__() got an unexpected keyword argument 'position'
I also tried using positionKey instead of position.key:
applicants = Applicants.query(position=positionKey).fetch()
I got this from "Ancestor Queries" section of GAE site:
https://developers.google.com/appengine/docs/python/ndb/queries
You don't pass arguments to query like that - ndb uses overridden equality/inequality operators, so you can express queries more 'naturally', with '==', '<', '>' etc., so:
applicants = Applicants.query(Applications.position==position.key).fetch()
The section in the on Filtering by Property Values gives some more examples.
(ancestor is a special-case for queries - it isn't a model property)

How to solve some sort of chicken egg relation within ndb.Models?

I have two entities (events and users). Each user has several events, but I don't want them to be stored within a StructuredProperty, because in future it should be possible to have multiple creators/admins. Now I have the problem, that User needs the Event Class for definition and vice versa. How can I implement the intended structure?
Two models with mutual relations.
class Event(EndpointsModel):
_message_fields_schema = ("id", "name", "creator",
"datetime", "place", "category", "participants")
creator = ndb.KeyProperty(kind=User)
participants = ndb.KeyProperty(kind=User, repeated=True)
name = ndb.StringProperty()
datetime = ndb.DateTimeProperty(auto_now_add=True)
place = ndb.GeoPtProperty()
category = ndb.StringProperty(choices=('all', 'drinking'))
class User(EndpointsModel):
_message_fields_schema = ("id", "name", "password", "events")
name = ndb.StringProperty()
password = ndb.StringProperty()
events = ndb.KeyProperty(kind=Event, repeated=True)
def create_event(self, e_name, e_datetime, e_place, e_category):
event = Event(name=e_name, creator = self.key, datetime=e_datetime, place=e_place, category=e_category)
event.put()
self.events.append(event)
self.put()
def get_events(self):
return ndb.get_multi(self.events)
Error Message:
NameError: name 'User' is not defined
EDIT 1:
I changed the kind to a string, containing the class name, like Greg suggested it. But it does not work too.
class Category(EndpointsModel):
_message_fields_schema = ("id", "name", "parent")
name = ndb.StringProperty()
parent = ndb.KeyProperty(kind='Category', default=None)
class Event(EndpointsModel):
_message_fields_schema = ("id", "name", "creator", "datetime",
"place", "category")
participants = ndb.KeyProperty(kind='User', repeated=True)
creator = ndb.KeyProperty(kind='User')
name = ndb.StringProperty()
datetime = ndb.DateTimeProperty(auto_now_add=True)
place = ndb.GeoPtProperty()
category = ndb.KeyProperty(Category)
class User(EndpointsModel):
_message_fields_schema = ("id", "name", "password")
name = ndb.StringProperty()
password = ndb.StringProperty()
events = ndb.KeyProperty(Event, repeated=True)
Now I receive the following stack trace:
ERROR 2014-01-21 09:38:39,764 service.py:191] Encountered unexpected error from ProtoRPC method implementation: BadValueError (Expected Key, got [])
Traceback (most recent call last):
File "/home/chris/Downloads/google_appengine/lib/protorpc-1.0/protorpc/wsgi/service.py", line 181, in protorpc_service_app
response = method(instance, request)
File "/home/chris/Downloads/google_appengine/lib/endpoints-1.0/endpoints/api_config.py", line 1321, in invoke_remote
return remote_method(service_instance, request)
[...]
value = self._call_shallow_validation(value)
File "/home/chris/Downloads/google_appengine/google/appengine/ext/ndb/model.py", line 1227, in _call_shallow_validation
return call(value)
File "/home/chris/Downloads/google_appengine/google/appengine/ext/ndb/model.py", line 1274, in call
newvalue = method(self, value)
File "/home/chris/Downloads/google_appengine/google/appengine/ext/ndb/model.py", line 1927, in _validate
raise datastore_errors.BadValueError('Expected Key, got %r' % (value,))
BadValueError: Expected Key, got []
You can use strings in the KeyProperty constructor to refer to kinds that don't have a model definition:
class Event(ndb.Model):
participants = ndb.KeyProperty(kind='User', repeated=True)
You can not create such references to the entities. Here is somo solutions:
1. You must use normal StringProperty for Event.creator or other id for User instance
2. Remove evens from class User - you can reach to evens by index on class Events
3. Use third entity model like this:
class EventCreator(EndpointsModel):
creator = ndb.KeyProperty(kind=User)
event = ndb.KeyProperty(kind=Event)
and from class User remove creator & from class Event remove
You could specify the key properties without the kind parameter (it is optional) and then do a manual check in your constructor or a pre-put hook or something like that -- or maybe not even worry about the kind:
class Event(EndpointsModel):
creator = ndb.KeyProperty()
# Constructor option
def __init__(self, *args, **kwargs):
super(Event, self).__init__(*args, **kwargs)
if 'creator' in kwargs and kwargs['creator'] != 'User':
raise Exception('oh no')
# Hook option
_pre_put_hook(self):
if self.creator and self.creator.kind() != 'User':
raise Exception("oh no")
The actual syntax will probably be slightly different. Feel free to edit.

Google App Engine - Datastore - GQL Query

class ProjectCategory(db.Model):
name = db.StringProperty("Category name", required = True)
def __str__(self):
return str(self.name)
class Project(db.Model):
name = db.StringProperty("Name", required = True)
category = db.ReferenceProperty(ProjectCategory)
description = db.TextProperty("Description", required = True)
#file_name = db.StringProperty("File name", required = True)
file = db.BlobProperty("Image")
whenstarted = db.DateTimeProperty("Start time")
whenended = db.DateTimeProperty("End Time")
def __str__(self):
return str(self.title)
How to get all Projects where category is CatName
hmm
db.GqlQuery("SELECT * FROM Project WHERE category = :1", "CatName")
don't work ?
The query does not work because you are passing a "CatName" string instead of a ProjectCategory instance's key.
Retrieve your desired ProjectCategory entity from Datastore first with:
pjc = GqlQuery("SELECT * FROM ProjectCategory WHERE name = :1", "CatName").get()
then use it as parameter in the query like this:
db.GqlQuery("SELECT * FROM Project WHERE category = :1", pjc.key())
A second approach is to use the implicit modelname_set Property of the ProjectCategory instance:
pjc = GqlQuery("SELECT * FROM ProjectCategory WHERE name = :1", "CatName").get()
pjc.project_set.fetch(10) #should contains some CatName projects

Resources