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.
Related
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.
I want to scan all records to check if there is not errors inside data.
How can I disable BadValueError to no break scan on lack of required field?
Consider that I can not change StringProperty to not required and such properties can be tenths in real code - so such workaround is not useful?
class A(db.Model):
x = db.StringProperty(required = True)
for instance in A.all():
# check something
if something(instance):
instance.delete()
Can I use some function to read datastore.Entity directly to avoid such problems with not need validation?
The solution I found for this problem was to use a resilient query, it ignores any exception thrown by a query, you can try this:
def resilient_query(query):
query_iter = iter(query)
while True:
next_result = query_iter.next()
#check something
yield next_result
except Exception, e:
next_result.delete()
query = resilient_query(A.query())
If you use ndb, you can load all your models as an ndb.Expando, then modify the values. This doesn't appear to be possible in db because you cannot specify a kind for a Query in db that differs from your model class.
Even though your model is defined in db, you can still use ndb to fix your entities:
# Setup a new ndb connection with ndb.Expando as the default model.
conn = ndb.make_connection(default_model=ndb.Expando)
# Use this connection in our context.
ndb.set_context(ndb.make_context(conn=conn))
# Query for all A kinds
for a in ndb.Query(kind='A'):
if a.x is None:
a.x = 'A more appropriate value.'
# Re-put the broken entity.
a.put()
Also note that this (and other solutions listed) will be subject to whatever time limits you are restricted to (i.e. 60 seconds on an App Engine frontend). If you are dealing with large amounts of data you will most likely want to write a custom map reduce job to do this.
Try setting a default property option to some distinct value that does not exist otherwise.
class A(db.Model):
x = db.StringProperty(required = True, default = <distinct value>)
Then load properties and check for this value.
you can override the _check_initialized(self) method of ndb.Model in your own Model subclass and replace the default logic with your own logic (or skip altogether as needed).
I have a Permissions class for which I need to create a static method to get the corresponding element based on the POST method in my views.py. The choices are done via checkboxes, in which you can select either of those, a pair or all of them, based on your preferences. That creates a list of strings (u'OWNER'), which should be processed in the static method and return the corresponding Permissions.OWNER, Permissions.HR, Permissions.USER_ADMIN
My views.py's POST method looks like this:
permissions = self.request.get_all('permissions')
user.new_permission = Permissions.get_permission(permissions)
Model looks like this:
class Permissions(object):
OWNER = 'OWNER'
HR = 'HR'
USER_ADMIN = 'USER_ADMIN'
descriptions = {
OWNER: """Company owner (full admin)""",
HR: """Human Resources administrator (access to special fields within job and submissions)""",
USER_ADMIN: """Add/Delete users, change user permissions""",
}
What I have so far on the static method:
#staticmethod
def get_permissions(permissions):
new_perms = []
for permission in permissions:
name = permission
if permission ==
new_perms.append(permission)
return new_perms
I really do not know how can I compare a string to the value in the model... Nor I am sure if I have titled the question correctly.
Thank you in advance,
Borislav
There are a whole bunch of things wrong with your code, and it seems to be overcomplicated.
I suggest you do some python tutorials. I m not sure how the class definition was ever going to work. Any way here is one way you could do it.
class Permissions(object):
_perms = {
'OWNER': """Company owner (full admin)""",
'HR': """Human Resources administrator (access to special fields within job and submissions)""",
'USER_ADMIN': """Add/Delete users, change user permissions""",
}
#classmethod
def get_permissions(cls,permissions):
new_perms = []
for choice in permissions:
if choice in cls._perms:
new_perms.append(choice)
return new_perms
#classmethod
def get_description(cls,permission)
return cls._perm.get(permission)
Actually on re-reading your question I am not sure what you are really trying to do. You mention a model, but the permissions class you provide doesn't reflect that, and I assume you need to query for the object. In fact if you where using a model to define permissions you would have a Permission object for each possible Permission - maybe.
alternate strategy, but there are many and without looking in more detail at how you really plan to use permissions. (I use repose.who/what for a fairly well developed permission model). At its most basic you can use getattr with your existing class. However I not keen on it, as there are no checks in place.
class Permissions(object):
OWNER = 'OWNER'
HR = 'HR'
USER_ADMIN = 'USER_ADMIN'
#classmethod
def get_permission(cls,permission):
if hasattr(cls,permission):
return getattr(cls,permission)
else:
raise KeyError("No permission %s" % permission) # Some better exception should be used.
I have the following objects: L1User, L2User, L3User (all inherits from User) and Document.
Every user can create the document but depending on the user type, the document will have a different status. So in case it's L1User, the document will be created with L1 status and so on:
Solution 1
Please note that after document is created, it will be saved in the database, so it should be natural to have a method create_document(User user) in Document object. In the method body I could check which type is the user and set manually appropriate status. Such approach seems rather not OOP to me.
Solution 2
Ok, so the next approach would be to have all users implement a common method (say create_document(Document doc)) which will set a status associated with the user and save the document in the database. My doubt here is that the document should be saved in it's own class, not the user.
Solution 3
So the final approach would similar to the above, except that the user will return modified document object to it's create_document(User user) method and save will be performed there. The definition of the method would be like this:
create_document(User user)
{
this = user.create_document(this);
this->save();
}
It also doesn't seems right to me...
Can anyone suggest a better approach?
I think that both Solutions 2 and 3 are ok from the OO point of view, since you are properly delegating the status assignment to the user object (contrary to solution 1, whare you are basically doing a switch based on the user type). Whether to choose 2 or 3 is more a matter of personal tastes.
However, I have a doubt: why do you pass a document to a create_document() method? I would go for a message name that best describes what it does. For example, in solution 3 (the one I like the most) I would go for:
Document>>create_document(User user)
{
this = user.create_document();
this->save();
}
and then
L1User>>create_document()
{
return new Document('L1');
}
or
Document>>create_document(User user)
{
this = new Document()
this = user.set_document_type(this);
this->save();
}
and then
L1User>>set_document_type(document)
{
document.setType('L1');
}
Edit: I kept thinking about this and there is actually a fourth solution. However the following approach works only if the status of a document doesn't change through its lifetime and you can map the DB field with a getter instead of a property. Since the document already knows the user and the status depends on the user, you can just delegate:
Document>>getStatus()
{
return this.user.getDocumentStatus();
}
HTH
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.