GAE - Model not saving while another model doing something similar does? - python

I'm having trouble getting a model to save (or be put()) correctly. The interesting part is that a model doing a very similar save before it works. Below are the relevant parts of the code. At the two logging points the first correctly returns the email of the user. However, the second one results in the error AttributeError: 'NoneType' object has no attribute 'c_user'. Obviously the setting and un-setting of the variables in this is not the correct way to do things, I've just added these to hunt down the problem to discover that the model isn't being saved. Any suggestions? Thank you much!
class Source(db.Model):
current_user = db.UserProperty()
class SourceMember(db.Model):
c_user = db.UserProperty()
x_position = db.IntegerProperty()
y_position = db.IntegerProperty()
...
user = users.get_current_user()
if user:
source_key = self.request.get('g')
if not source_key:
source_key = user.user_id()
source = Source(key_name = source_key,
current_user = user)
source.put()
else:
source = Source.get_by_key_name(source_key)
source = None
source = Source.get_by_key_name(source_key)
logging.warning(source.current_user)
if source:
sourceMember = SourceMember.get_by_key_name(user.user_id() + source_key)
if not sourceMember:
sourceMember = SourceMember(parent = source.key(),
key_name = user.user_id() + source_key,
c_user = user,
x_position = None,
y_position = None)
sourceMember.put()
sourceMember = None
sourceMember = SourceMember.get_by_key_name(user.user_id() + source_key)
logging.warning(sourceMember.c_user)

When you create the SourceMember you're giving it a parent, but then when you get it, the parent is missing. Source doesn't have a parent, so getting it just from its id works.

Related

How to update field for EmbeddedDocument in graphene mongo python

I'm trying to update one field of IgThread EmbeddedDocument, and error occurs:
'IgThread' object has no attribute 'save'
I've tried some weird solutions, non of them work.
There is bug in current code
Mutation:
def mutate(self, _, **kwargs):
ig_pk = kwargs['ig_pk']
thread_input = kwargs['ig_thread']
lead_ = Lead.objects(ig__pk=ig_pk).first()
for thread in lead_.messages.ig:
Lead.objects(
ig__pk=ig_pk,
messages__ig__thread_id=thread_input.thread_id,
).update(
push_all__messages__ig__S__messages=new_messages,
)
thread.last_activity_at = thread_input.last_activity_at
thread.save()
Parent:
class Lead(Document):
id = fields.ObjectIdField()
messages = fields.EmbeddedDocumentField(Messages)
Nested EmbeddedDocument:
class Messages(EmbeddedDocument):
ig = fields.EmbeddedDocumentListField(IgThread)
Deeper:
class IgThread(EmbeddedDocument):
thread_id = fields.StringField()
last_activity_at = fields.StringField()
I want to update last_activity_at
Pls, help, I have to fix that bug and no one cant help mi with this in the office :<
Solved! It was easy...
def mutate(self, _, **kwargs):
ig_pk = kwargs['ig_pk']
thread_input = kwargs['ig_thread']
lead_ = Lead.objects(ig__pk=ig_pk).first()
for thread in lead_.messages.ig:
Lead.objects(
ig__pk=ig_pk,
messages__ig__thread_id=thread_input.thread_id,
).update(
push_all__messages__ig__S__messages=new_messages,
)
lead_ = Lead.objects(ig__pk=ig_pk).first() <--------
thread.last_activity_at = thread_input.last_activity_at
lead_.save() <--------

UnprojectedPropertyError in google app engine

The following is a working code in google app engine. This is used to display some records from a SentMail Model. The SentMail have a large no of fields, here i only showed the fields we now need. Since for displaying data i do not require to take the complete record. Hence i used projection. Note: This code is working
class SentMail(ndb.Model):
to_email = ndb.StringProperty()
bounced = ndb.BooleanProperty(default=False)
bounce_type = ndb.StringProperty()
bounceSubType = ndb.StringProperty()
#staticmethod
def get_bounced_emails():
db_query = SentMail.query(SentMail.bounced==True, projection=['to_email', 'bounce_type'], distinct=True).order(SentMail.bounce_type).order(SentMail.to_email).fetch()
return db_query if len(db_query) > 0 else None
class BounceCompaintRender(session_module.BaseSessionHandler):
"""docstring for BounceCompaintRender"""
def get(self):
bounced_emails = self.get_data('complete_bounced_rec')
template_values = {
'bounced_emails': bounced_emails
}
path = os.path.join(os.path.dirname(__file__), 'templates/bounce_complaint_emails.html')
self.response.out.write(template.render(path, template_values))
else:
self.redirect('/login')
def get_data(self, key):
data = memcache.get(key)
if data is not None:
for each in data:
logging.info(each)
return data
else:
data = SentMail.get_bounced_emails()
memcache.add(key="complete_bounced_rec", value=data, time=3600)
return data
Here the only change I made is in SentMail.get_bounced_emails()
#staticmethod
def get_bounced_emails():
db_query = SentMail.query(SentMail.bounced==True, projection=['to_email', 'bounceSubType'], distinct=True).order(SentMail.bounceSubType).order(SentMail.to_email).fetch()
return db_query if len(db_query) > 0 else None
I now get an error UnprojectedPropertyError: Property bounceSubType is not in the projection. I checked the logs and i found in the projection field one parameter is missing and eventhough it has a value None(None is not the only value). I tried clearing memcache but the problem still arises. The following is the log
SentMail(key=Key('SentMail', 655553213235462), bounceSubType=None, to_email=u'test#example.com', _projection=('to_email',))
This error is due to the difference in the model SentMail wrote in models.py and in datastore (i.e., properties are different in both). For this you need to update all records in datastore related to SentMail then datastore and model will have the same fields.

AttributeError: 'list' object has no attribute 'objects'

I am trying to run the following which is throwing an
AttributeError: 'list' object has no attribute 'objects'
script.py
#Get Dota2 Item Rarities
dotaItemRarityUrl = 'http://api.steampowered.com/IEconDOTA2_570/GetRarities/v1?'
dotaItemRarityPayload = {'key': settings.SOCIAL_AUTH_STEAM_API_KEY,
'language': 'en',
}
dotaItemRarityInfo = requests.get(dotaItemRarityUrl, params=dotaItemRarityPayload)
dotaItemRarity = dotaItemRarityInfo.json()
dotaItemRarity = dotaItemRarity['result']['rarities']
print(dotaItemRarity)
#print(dotaItemQualities)
#Populate Database With Item Rarities that do NOT exist already
for rarity in dotaItemRarity:
print rarity
irarityId = rarity['id']
irarityProperName = rarity['localized_name']
irarityInternalName = rarity['name']
irarityColor = rarity['color']
q = dotaItemRarity.objects.filter(rarityId=irarityId)
print q
if len(q) == 0:
newRarity = dotaItemRarity(rarityId=irarityId,
rarityProperName=irarityProperName,
rarityInternalName=irarityInternalName,
rarityColor=irarityColor)
newRarity.save()
models.py
class dotaItemRarity(models.Model):
rarityId = models.IntegerField(max_length=3,primary_key=True)
rarityProperName = models.CharField(max_length=60)
rarityInternalName = models.CharField(max_length=50)
rarityColor = models.CharField(max_length=30)
def __unicode__(self):
return self.rarityInternalName
I am using south to handle migrations and have tried multiple options to fix this e.g. removing the tables and rebuilt them. As far as I can tell this should work, can anyone point me in the right direction.
dotaItemRarity is a list, and it has no objects attribute:
q = dotaItemRarity.objects.filter(rarityId=irarityId)
That's because you bound it to a list from your JSON result:
dotaItemRarity = dotaItemRarityInfo.json()
dotaItemRarity = dotaItemRarity['result']['rarities']
It is not a Django model, as you appear to expect it to be.
If you had the dotaItemRarity Django model imported into script.py, then the name is no longer bound to that model, as you replaced it with the list.
Rename the list to use a different name that doesn't mask the model.
Note that the Python style guide recommends that you use CamelCase names for classes (including Django models), to avoid such mistakes.
Following PEP 8 to refactor your code a little, as well as using some clearer naming an practices:
models.py:
class DotaItemRarity(models.Model):
rarity_id = models.IntegerField(max_length=3, primary_key=True)
rarity_proper_name = models.CharField(max_length=60)
rarity_internal_name = models.CharField(max_length=50)
rarity_color = models.CharField(max_length=30)
def __unicode__(self):
return self.rarity_internal_name
script.py:
#Get Dota2 Item Rarities
url = 'http://api.steampowered.com/IEconDOTA2_570/GetRarities/v1'
payload = {'key': settings.SOCIAL_AUTH_STEAM_API_KEY, 'language': 'en'}
response = requests.get(url, params=payload)
rarities = response.json()['result']['rarities']
for rarity in rarities:
rarity_id = rarity['id']
try:
DotaItemRarity.get(rarity_id=rarity_id)
except DotaItemRarity.DoesNotExist:
new_rarity = DotaItemRarity(
rarityId=rarity_id,
rarity_proper_name=rarity['localized_name'],
rarity_internal_name=rarity['name'],
rarity_color=rarity['color'])
new_rarity.save()

Python populating a database with one-to-many relationship

I'm a beginner, so please go easy on me. I am working on a script so that I don't have to keep entering in data when I decide to drop the database. My entire script works well, except when I'm dealing with a one-to-many relationship. It will not save to the database. Can anyone tell me what I am doing wrong or point me in the right direction?
SCRIPT:
try:
pmod.Instrument.objects.get(title='kjkjsdfsadfs')
except pmod.Instrument.DoesNotExist:
u = pmod.Instrument()
u.title = 'Bach 42 Trombone'
u.price = 550.00
u.soundDescription = 'Good'
u.functionalityDescription = 'Good'
u.damageDescription = 'Good'
u.accessoryDescription = 'Good'
u.customerName = 'Jake'
u.customerEmail = 'ks#gmail.com'
u.instrumentCategory = 1
print('Good2')
u.save()
print('Instrument1 saved')
MODEL:
class Category(models.Model):
instrumentCategory=models.CharField(max_length=50,blank=True,null=True)
def __str__(self):
return self.instrumentCategory
class Instrument(models.Model):
title = models.CharField(help_text='title',max_length=50,blank=True,null=True)
price = models.DecimalField(max_digits=8, decimal_places=2)
soundDescription=models.CharField(max_length=1000,blank=True,null=True)
functionalityDescription=models.CharField(max_length=1000,blank=True,null=True)
damageDescription=models.CharField(max_length=1000,blank=True,null=True)
accessoryDescription=models.CharField(max_length=1000,blank=True,null=True)
customerName=models.CharField(max_length=50,blank=True,null=True)
customerEmail=models.EmailField(max_length=254,help_text='Enter valid email address')
instrumentCategory=models.ForeignKey(Category)
u.instrumentCategory = 1
That's not how a models.ForeignKey field works in Django. You need to get an instance of the Category object and assign that to u.instrumentCategory.
u.instrumentCategory = pmod.Category.objects.get(id=1)
You may try :
u.instrumentCategory_id = 1

Separating "user-owned" from "other" data in Django template

I have an Openstack-powered, Django-modified application that shows the disk images and snapshots available for a user to launch. The user currently sees both snapshots they created and ones they did not. I would like to separate the current table into two based on whether they are owned by the user or not.
My two table definitions are as follows (note I altered row_actions accordingly):
class UserSnapshotsTable(OldSnapshotsTable):
cloud = tables.Column(get_cloud, verbose_name=_("Cloud"))
class Meta:
name = "usersnapshots"
verbose_name = _("User Snapshots")
table_actions = (DeleteSnapshot,)
row_actions = (LaunchSnapshot, LaunchCluster, EditImage, DeleteSnapshot)
pagination_param = "snapshot_marker"
row_class = UpdateRow
status_columns = ["status"]
class OtherSnapshotsTable(OldSnapshotsTable):
cloud = tables.Column(get_cloud, verbose_name=_("Cloud"))
class Meta:
name = "othersnapshots"
verbose_name = _("Other Snapshots")
table_actions = (DeleteSnapshot,)
row_actions = (LaunchSnapshot, LaunchCluster)
pagination_param = "snapshot_marker"
row_class = UpdateRow
status_columns = ["status"]
I have altered the HTML template to pull the "UserSnapshotsTable" and "OtherSnapshotsTable" tables (I copied the original table and renamed both), but both full tables still generate under the respective headings. There are two functions generating the data:
def get_usersnapshots_data(self):
req = self.request
marker = req.GET.get(UserSnapshotsTable._meta.pagination_param, None)
try:
usersnaps, self._more_snapshots = api.snapshot_list_detailed(req,
marker=marker)
except:
usersnaps = []
exceptions.handle(req, _("Unable to retrieve user-owned snapshots."))
return usersnaps
def get_othersnapshots_data(self):
req = self.request
marker = req.GET.get(OtherSnapshotsTable._meta.pagination_param, None)
try:
othersnaps, self._more_snapshots = api.snapshot_list_detailed(req,
marker=marker)
except:
othersnaps = []
exceptions.handle(req, _("Unable to retrieve non-user-owned snapshots."))
return othersnaps
There are also Edit/Delete options defined for images, and imported for snapshots, that seem to have a key comparison. Here's the "Delete" one (line 7):
class DeleteImage(tables.DeleteAction):
data_type_singular = _("Image")
data_type_plural = _("Images")
def allowed(self, request, image=None):
if image:
return image.owner == request.user.tenant_id
# Return True to allow table-level bulk delete action to appear.
return True
def delete(self, request, obj_id):
api.image_delete(request, obj_id)
How can I separate those tables out? This is my first time asking a question here, so please let me know if I can provide further information. Apologies for the length of it.
As far as I see you are using glanceclient. If that so you can use extra_filters parameter of snapshot_list_detailed() to filter only user images like this:
usersnaps, self._more_snapshots = api.snapshot_list_detailed(
req,
marker = marker,
extra_filters = {"owner": "user_name"}
)
Under cover snapshot_list_detailed uses GET images of Openstack Image Service API.

Categories