I have a model M contains three manytomanyfields(a,b,c) to three different models in django.
class M (models.Model):
name = models.CharField()
a = models.ManyToManyField(A)
b = models.ManyToManyField(B)
c = models.ManyToManyField(C)
Now, I want to handle any changes on my model M and send an HttpRequest to an url correspondingly.
as you know in post-save signal of model M the values of attributes for a,b and c are not set yet because they will be set when saving model M has been finished.(the rule of ManyToManyField)
I write a single handler for my model to handle any changes(either create a new instance or update a field/fields)
#receiver(post_save, sender=M)
#receiver(m2m_changed, sender=M.a.through)
#receiver(m2m_changed, sender=M.b.through)
#receiver(m2m_changed, sender=M.c.through)
def M_changes_handler(sender, **kwargs):
is_instance_set_compeletly(kwargs['instance']):
#send_and_HttpRequest(url, data = instance)
def is_instance_set_compeletly(kwargs['instance']):
if M.a.all() is not None and M.b.all() is not None and
M.c.all()is not None
flag = True
else:
flag = False
return flag
Now consider an update request (which changes all fields) on model M will send signals for all fields a,b and c; so three httpRequests would send to my sender with three different versions of instance! on the other hand when user just changes a field for example b of the model M this function will send only one httpRequest.
I want to handle this problem dynamically and just send one request per ANY TYPE of CHANGE on my model M.
I was wondering if somebody could help me :)
*Note the code above is just a draft and may contains syntax error so ignore them ;)
Update: My problem solved!
The process of saving a model containing m2mfields is interesting!
First of all the fields of M which are not m2m fields type e.g. are char field, foreign key or etc. had been set before calling post_save. So in post_save their values are updated
Although m2mfields wont be set till the saving of the model would be finished. Then m2mchange signals called to set m2mfields
The only way to have an updated version of your model is to overriding form save in admin.py because the "form save" will be called after finishing all m2mfields have been set
Solution:
For all stack-overflow users and Dear Blake Gibbs
If a model contains manytomany fields and you want to access all the data of a saved record, you cannot access those m2m fields because they will save after finishing the process of saving model(consider M in my example), then assign that Id to other self-created m2m table to bind that Id to m2m fields (e.g. A in my example). so overriding the save method of a model in admin.py does not work in this case.
I simply override the save function of my form in Forms.py
class MForm(forms.ModelForm):
class Meta:
model = M
exclude = []
def save(self, commit=True):
query = ""
old_instance = super(MForm, self).save(commit=False)# if you need the old instance
#otherwise return super(MForm, self).save(commit=True)
instance = super(MForm,self).save(commit=True)
in this case the "instance" is really saved completely and you can access m2m fields by using ".all()"
hope it helped!
you can hold previously instance of M and in post_save with new M check field have changed according to that you can send request.
Related
For a few days now, I've been designing a social network database structure and I've been optimizing over and over again the data structures.
What I am trying to achieve in Neo4j:
I am trying to create a relationship between two nodes which has a property called "history" and one called "currentStatus". The problem is that both are (should be) arrays. Something like:
MATCH (u:User {username: 'john.snow#gmail.com'}), (uu:User {username: 'sansa.stark#gmail.com'})
MERGE u-[rel:FRIENDSHIP]->uu
ON CREATE SET rel.previousFriendshipUpdates = [], rel.currentFriendshipStatus = [sentTime: timestamp(), status: '0']
ON MATCH SET rel.previousFriendshipUpdates = [rel.previousFriendshipUpdates + rel.currentFriendshipStatus], rel.currentFriendshipStatus = [sentTime: timestamp(), status: '1']
I want to keep a history of whatever actions regarding they're friendship take place (sender sent friend request at x time, receiver rejected friend request at x time, sender sent friend request (again) at x time, receiver accepted at x time, receiver unfriended sender at x time, etc).
Thank you in advance.
To add values to array (collection) property arr on relationship r you can do
SET r.arr = r.arr + 'newvalue'
or
SET r.arr = r.arr + ['onevalue', 'nothervalue']
(see How to push values to property array Cypher-Neo4j)
But arrays cannot contain values like sentTime: timestamp(). That looks like a property and an array can't have properties.
Nodes can have properties, however, and both the structure of your example query and the description of your model suggests that you represent the friendship as a node instead. Let each :Friendship node have [:MEMBER] relationships to two :User nodes. Then keep the friendship status as a property on that node. A good way to model relationship history could be to create a node for each update and keep these in a "linked list" that extends from the :Friendship node.
I'm wondering what the right pattern should be to update an existing datastore object using endpoints-proto-datastore.
For example, given a model like the one from your GDL videos:
class Task(EndpointsModel):
detail = ndb.StringProperty(required=True)
owner = ndb.StringProperty()
imagine we'd like to update the 'detail' of a Task.
I considered something like:
#Task.method(name='task.update',
path='task/{id}',
request_fields=('id', 'detail'))
def updateTask(self, task):
pass
However, 'task' would presumably contain the previously-stored version of the object, and I'm not clear on how to access the 'new' detail variable with which to update the object and re-store it.
Put another way, I'd like to write something like this:
def updateTask(self, task_in_datastore, task_from_request):
task_in_datastore.detail = task_from_request.detail
task_in_datastore.put()
Is there a pattern for in-place updates of objects with endpoints-proto-datastore?
Thanks!
See the documentation for details on this
The property id is one of five helper properties provided by default
to help you perform common operations like this (retrieving by ID). In
addition there is an entityKey property which provides a base64
encoded version of a datastore key and can be used in a similar
fashion as id...
This means that if you use the default id property your current object will be retrieved and then any updates from the request will replace those on the current object. Hence doing the most trivial:
#Task.method(name='task.update',
path='task/{id}',
request_fields=('id', 'detail'))
def updateTask(self, task):
task.put()
return task
will perform exactly what you intended.
Task is your model, you can easily update like this:
#Task.method(name='task.update',
path='task/{id}',
request_fields=('id', 'detail'))
def updateTask(self, task):
# Task.get_by_id(task.id)
Task.detail = task.detail
Task.put()
return task
It might be the most dumb question and my apologies for the same but I am confused
I have the following entity:
class Profile(ndb.Model):
name = ndb.StringProperty()
identifier = ndb.StringProperty()
pic = ndb.BlobKeyProperty() # stores the key to the profile picture blob
I want to delete the "pic" property value of the above entity so that it should look as fresh as if "pic" was never assigned any value. I do not intend to delete the complete entity. Is the below approach correct:
qry = Profile.query(Profile.identifier==identifier)
result_record_list = qry.fetch()
if result_record_list:
result_record_list[0].pic.delete() # or result_record_list[0].pic = none # or undefined or null
I am deleting the actual blob referred by this blob key separately
assign None to it and put it back to the datastore.
result_record_list[0].pic = None
result_record_list[0].put()
The datastore is an OO schemaless databse. So you can add and remove properties from the the Kind (ndb.Model) without the need of a schema update.
If you also want to cleanup the entities look at this anwser from Guido
Update
This was my best effort creating the following scheme
user = self.auth.store.user_model.create_user(email,
password_raw=newpasswd)
if not user[0]: # user is a tuple
return user[1] # Error message
else:
# User is created, let's try making the references
okuser = auth_models.User.get_by_id(long(user[1].key.id()))
okuser.sponsor = auth_models.User.get_by_id(long(sponsor_id)).auth_ids
Original question
How can I make a selfreference with an expando class to indicate which User is the "sponsor" of which? The "sponsor" is the one who invited the new User so at creation we must store that and it would be much neater to store it as a referenceproperty than a string or a stringlist.
I can create a new user but I don't know how to make a reference so that I can tell for one User who another User is who is the sponsor of the first user and I suppose a way to model this is with selfreferenceproperty since both objects are users but the complication is that it is an expando model so I don't know how to use the reference property. Could you tell me how to do it or give me a clue how I can solve this problem in the best way?
user = self.auth.store.user_model.create_user(email,
password_raw=newpasswd)
if not user[0]: # user is a tuple
return user[1] # Error message
else:
# User is created, let's try making the reference
okuser = auth_models.User.get_by_id(user[1].key.id())
okuser.sponsor = db.SelfReferenceProperty(User,
collection_name='matched_images', verbose_name='Sponsor')
I don't know how to do the last part, to store the actual referenceproperty with an epando model. How can it be done?
Update
It seems it can't be done:
NotImplementedError: Property sponsor does not support <class 'google.appengine.ext.db.ReferenceProperty'> types.
Code:
user = self.auth.store.user_model.create_user(email,
password_raw=newpasswd)
if not user[0]: # user is a tuple
return user[1] # Error message
else:
# User is created, let's try redirecting to login page
okuser = auth_models.User.get_by_id(long(user[1].key.id()))
okuser.sponsor = db.SelfReferenceProperty(auth_models.User.get_by_id(sponsor_id),collection_name='matched_distributor')
okuser.put()
It forces me do use a string instead of a reference and then a solution is feasible:
user = self.auth.store.user_model.create_user(email,
password_raw=newpasswd)
if not user[0]: # user is a tuple
return user[1] # Error message
else:
# User is created, let's try redirecting to login page
okuser = auth_models.User.get_by_id(long(user[1].key.id()))
okuser.sponsor = sponsor_id
okuser.put()
You can't assign an instance of a Property class to an instance of a model - property classes define properties, they don't represent individual values.
By far the easiest way to do what you want is to add the property as you would on a regular model. Just because you're using expandos (why, by the way?) doesn't mean you can't have regular properties on them as well.
I have a python program in Google App Engine
When finding an object in the datastore when I have the key as a string, how can I do a direct read. Below is my code which is performing a loop, not good.....
class Opportunity(db.Model):
customer = db.ReferenceProperty(Customer,collection_name='opportunitys')
BNusername = db.StringProperty()
opportunity_no = db.StringProperty()
# etc etc etc.....
#BnPresets holds the object key as a string
opportunitys = Opportunity.all()
opportunitys.filter('BNusername =',BnPresets.myusername)
for oprec in opportunitys:
if str(oprec.key()) == BnPresets.recordkey:
opportunity = oprec
# I have the object here and can process etc etc
You can instantiate db.Key from string by passing it directly to the constructor:
opportunity_key = db.Key(BnPresets.recordkey)
Once you have that, simply db.get to obtain the entity identified by this key:
opportunity = db.get(opportunity_key)
I guess (by looking at the query you use) that you also want to verify the username of the object you got:
if opportunity.BNusername == BnPresets.myusername
process_opportunity(opportunity)
That should be pretty much it. The bottom line is that you should use the key first - as it uniquely identifies your entity - rather than querying for some other property and iterating through results.