GAE Datastore query - google-app-engine

I'm trying to list all the Users that are entered into my datastore in my test GAE app and print out the usernames of each one. However, when I run the code below I get an error saying
self.query = User.all()
AttributeError: type object 'User' has no attribute 'all'
I thought that self.query = User.all() would return all the users in my database?
My code is below.
Thanks in advance!
PS. I know my userfinder form is asking for a username and doing nothing with it, but filtering is a task for later - I just want to make sure I've got the basic query going first.
from google.appengine.ext import ndb
import webapp2
import uuid
class User(ndb.Model):
db_UID = ndb.StringProperty(indexed = True)
db_username = ndb.StringProperty(indexed = True)
db_password = ndb.StringProperty(indexed = True)
db_email = ndb.StringProperty(indexed = True)
db_resetID = ndb.StringProperty(indexed = True)
class UsersPage(webapp2.RequestHandler):
def get(self):
self.response.write('<html><body><h1>User Info Page</h1>')
self.response.write("""
<form method = "post">
Username: <input type = "textarea" name = "user_username"></input><br>
Password: <input type = "textarea" name = "user_password"></input><br>
Email address: <input type = "textarea" name = "user_email"></input><br>
<input type = "submit"></input>
</form>""")
self.response.write('</body></html>')
def post(self):
UNIQUE_ID_STRING = str(uuid.uuid1())
self.user = User(db_UID = UNIQUE_ID_STRING ,
db_username = self.request.get('user_username'),
db_password = self.request.get('user_password'),
db_email = self.request.get('user_email'))
self.user.put()
self.redirect('/user')
class UserFinder(webapp2.RequestHandler):
def get(self):
self.response.write('<html><body><h1>Search username</h1>')
self.response.write("""
<form method = "post">
Username: <input type = "textarea" name = "user_username"></input><br>
<input type = "submit"></input>
</form>""")
self.response.write('</body></html>')
def post(self):
self.query = User.all()
self.response.write('<html><body><h1>Search username</h1>')
for self.user in self.query:
self.response.write('<p>%s</p>' % self.User.db_username)
self.response.write('</body></html>')
application = webapp2.WSGIApplication([
('/user', UsersPage),
('/userfinder', UserFinder),
], debug = True)

Unlike the basic 'db' version, NDB Models don't use all() for querying, they use query(), so
self.query = User.query()
The NDB docs on queries might be useful.
As an aside, using self as much as you are is a little unusual; aside from the calls to self.response.write and to self.redirect, just using local variables will be a lot less confusing (good if you have to post more questions!), and will save you typing.
So your post method would become:
query = User.all()
self.response.write('<html><body><h1>Search username</h1>')
for user in query:
self.response.write('<p>%s</p>' % user.db_username)
self.response.write('</body></html>')

Related

Using Django formset displaying related names in template

I am trying to display the state values for each country name in Django app. To save the user response, I am using Django generic CreateView. My models look something like this:
class Question(model.Models):
ques_id = models.AutoField(primary_key=True)
country = models.ForeignKey(Country)
state = models.CharField(max_length=...)
class Test(model.Models):
test = models.AutoField(primary_key=True, )
test_num = models.CharField(max_length=6, )
class Response(model.Models):
response = models.AutoField(primary_key=True)
test_id = models.ForeignKey(Test, related_name='test', )
ques_offered = models.ForeignKey(Question, related_name='choice',
ans_submitted = models.CharField(max_length=240,
To display the available choices for field state for each country value (in the db), I am looping through Django management form for the formset in my template. However, I am unable to get to the values of field state instead I am getting the country values.
Additional info:
The views that I am using to achieve this:
class ResponseCreateView(CreateView):
template_name = ...
model = Test
form_class = # Form_name
def get_context_data(self, **kwargs):
data = super(ResponseCreateView, self).get_context_data(**kwargs)
if self.request.POST:
data['get_response'] = responseFormset(self.request.POST, self.request.FILES)
else:
data['get_response'] = responseFormset()
def form_valid(self, form):
context = self.get_context_data()
get_response = context['get_response']
with transaction.atomic():
if get_response.is_valid():
self.object = form.save()
get_response.instance = self.object
get_response.save()
return redirect('...')
else:
context.update({'get_response': get_response,
})
return self.render_to_response(context)
return super(ResponseCreateView, self).form_valid(form)

Uploading data to user's page in Django using Forms

I'm trying to code the page so that every user has its userpage where they can add their own info ( in this case YCD data). Now I'm trying to code the add button, with which user will be able to add a note to its personal page.
def add_YCD(request):
current_user = request.user
current_profile = Profile.objects.get(user_id = current_user.id)
if request.method == "POST":
if current_user.is_authenticated:
YCD_form = YCDForm(request.POST, instance = current_profile)
if YCD_form.is_valid():
YCD_form.save()
messages.success(request,('Your profile was successfully updated!'))
else:
messages.error(request,('Unable to complete request'))
return redirect("main:homepage")
YCD_form = YCDForm(instance = current_profile)
return render(request = request,
template_name = "main/add_YCD.html",
context = {"YCD_form": YCD_form,
"user": request.user,})
The code works without instance = current_profile, it just saves the note to database but doesn't display it on the userpage. I've also tried using instance = request.user.profile.
But it doesn't work at all.
Here are the Models themselves:
class Yield_Curve_Data(models.Model):
b1 = models.BigIntegerField()
b2 = models.BigIntegerField()
b3 = models.BigIntegerField()
tau = models.BigIntegerField()
Date = models.DateTimeField('date published', default = datetime.now)
class Profile(models.Model):
user = models.OneToOneField(User, on_delete=models.CASCADE)
yield_curve_data = models.ManyToManyField(Yield_Curve_Data, null = True)
#receiver(post_save, sender = User)
def create_user_profile(sender, instance, created, **kwargs):
if created:
Profile.objects.create(user=instance)
#receiver(post_save, sender = User)
def save_user_profile(sender, instance, **kwargs):
instance.profile.save()
And here's the code for forms:
class YCDForm(forms.ModelForm):
class Meta:
model = Yield_Curve_Data
fields =('b1', 'b2', 'b3', 'tau',)
Is there another way to specify the user itself or o I need to change the code completely?
Thanks

Adding methods to GAE database class

I am messing around with GAE. I want to place my database object in one file and call it from another. Here is the DB object:
import webapp2
import os
import jinja2
import json
import logging
import main
from google.appengine.ext import db
class User(db.Model):
user_name = db.StringProperty(required = True)
hashed_password = db.StringProperty(required = True)
email = db.EmailProperty(required = True)
created_dttm = db.DateTimeProperty(auto_now_add = True)
last_modified = db.DateTimeProperty(auto_now = True)
coords = db.GeoPtProperty(required = False)
# def as_dict(self):
# time_fmt = '%c'
# d = {
# 'subject':self.subject,
# 'content':self.content,
# 'created':self.created_dttm.strftime(time_fmt),
# 'last_modified': self.last_modified.strftime(time_fmt)
# }
# return d
def isValueUnique(self,column,value):
result = None
q = User.all()
q.filter(column, value)
result = q.get()
return result
I cannot instantiate the DB because it thinks I'm trying to store data.
I want to call the isValueUnique method from another file like so:
import webapp2
import os
import jinja2
import json
import logging
import main
import database
import validation
from google.appengine.ext import db
class SignUp(main.Handler):
def post(self):
user_username = self.request.get("username")
user_email = self.request.get("email")
user_pass = self.request.get("password")
user_verify = self.request.get("verify")
valid = validation.Valid()
error1=""
error2=""
error3=""
error4=""
q = database.User.all()
q.filter("username =", user_username)
result = q.get()
if result:
error1="Username already taken"
if (not valid.valid_user(user_username)) and (not error1):
error1 = "Enter a valid username"
if not valid.valid_password(user_pass):
error2 = "Enter a valid password"
if not valid.valid_pass_match(user_pass,user_verify):
error3 = "Passwords must match"
# Email Validation
email=valid.valid_email(user_email)
if not email:
error4 = "Invalid email"
email=""
elif not database.User.isValueUnique("email",email):
error4 = "Email already in use, please sign in"
email=""
I get this error:
elif not database.User.isValueUnique("email",email):
TypeError: unbound method isValueUnique() must be called with User instance as first argument (got str instance instead)
I can't instantiate User like I already said. What is the work around here?
database.User.isValueUnique("email",email)
This is attempting to call a method on the database.User class, but isValueUnique is an instance method.
If you decorate isValueUnique with #staticmethod you'll get farther.
Where are you trying to instantiate a User?

GAE python: Get and post request working without submitting a post request through a form

This is a continuation of this question
What follows is an abbreviated version of the original code. I tried to include the most relevant parts and left out the part of the script used by a cron job which updates the Datastore with values.
Then, in the sendFollowUp() handler, a second cron job queries the Datastore for these values, then uses a push task queue to send these values as parameters which are ultimately used in a REST API call to another service that sends people(entities) in the Datastore an email.
What I can't figure out is how to follow-up a get request with a post request in the same handler without submitting a post request through a form. This needs to happen within the sendFollowUp handler. Most of the examples I have found include submitting a form. However, I don't want to do that. I just want it to work automatically with the cron job and task queue.
import webapp2
import datetime
from google.appengine.ext import db
from google.appengine.api import users
from google.appengine.api import taskqueue
import jinja2
import os
jinja_environment = jinja2.Environment(loader=jinja2.FileSystemLoader(os.path.dirname(__file__)))
class emailJobs(db.Model):
""" Models an a list of email jobs for each user """
triggerid = db.StringProperty() #Trig id
recipientid_po = db.StringProperty() # id
recipientlang = db.StringProperty() #Language
fu_email_sent = db.DateTimeProperty()
fuperiod = db.IntegerProperty() # (0 - 13)
fu1 = db.DateTimeProperty()
fu2 = db.DateTimeProperty()
#classmethod
def update_fusent(cls, key_name, senddate):
""" Class method that updates fu messages sent in the GAE Datastore """
emailsjobs = cls.get_by_key_name(key_name)
if emailsjobs is None:
emailsjobs = cls(key_name=key_name)
emailsjobs.fu_email_sent = senddate
emailsjobs.put()
def timeStampFM(now):
d = now.date()
year = d.year
month = d.month
day = d.day
t = now.time()
hour = t.hour
minute = t.minute + 5
second = t.second
today_datetime = datetime.datetime(year, month, day, hour, minute, second)
return today_datetime
class MainPage(webapp2.RequestHandler):
""" Main admin login page """
def get(self):
if users.get_current_user():
url = users.create_logout_url(self.request.uri)
url_linktext = 'Logout'
urla = '/'
url_admin = ""
if users.is_current_user_admin():
url = users.create_logout_url(self.request.uri)
urla = "_ah/admin/"
url_admin = 'Go to admin pages'
url_linktext = 'Logout'
else:
url = users.create_login_url(self.request.uri)
url_linktext = 'Login'
template_values = {
'url': url,
'url_linktext': url_linktext,
'url_admin': url_admin,
'urla': urla,
}
template = jinja_environment.get_template('index.html')
self.response.out.write(template.render(template_values))
class sendFollowUp(webapp2.RequestHandler):
""" Queries Datastore for fu dates that match today's date, then adds them to a task queue """
def get(self):
now = datetime.datetime.now()
now_dt = now.date() #today's date to compare with fu dates
q = emailJobs.all()
q.filter('fuperiod >', 0)
q.filter('fuperiod <', 99)
for part in q:
guid = str(part.recipientid_po)
lang = str(part.recipientlang)
trigid = str(part.triggerid)
if part.fuperiod == 1:
fu1rawdt = part.fu1
fu1dt = fu1rawdt.date()
if fu1dt == now_dt:
follow_up = '1'
if part.fuperiod == 2: # the values go up to 12 in the original code
fu2rawdt = part.fu2
fu2dt = fu2rawdt.date()
if fu2dt == now_dt:
follow_up = '2'
if follow_up != None:
taskqueue.add(queue_name='emailworker', url='/emailworker', params={'guid': guid,
'fu': follow_up,
'lang': lang,
'trigid': trigid,
})
self.redirect('/emailworker')
class pushQueue(webapp2.RequestHandler):
""" Sends fu emails, updates the Datastore with datetime sent """
def store_emails(self, trigid, senddate):
db.run_in_transaction(emailJobs.update_fusent, trigid, senddate)
def get(self):
fu_messages = {'1': 'MS_x01',
'2': 'MS_x02',
# the values go up to 12 in the original code
}
langs = {'EN': 'English subject',
'ES': 'Spanish subject',
}
fu = str(self.request.get('fu'))
messageid = fu_messages[fu]
lang = str(self.request.get('lang'))
subject = langs[lang]
now = datetime.datetime.now()
senddate = timeStampFM(now)
guid = str(self.request.get('guid'))
trigid = str(self.request.get('trigid'))
data = {}
data['Subject'] = subject
data['MessageID'] = messageid
data['SendDate'] = senddate
data['RecipientID'] = guid
# Here I do something with data = {}
self.store_emails(trigid, senddate)
app = webapp2.WSGIApplication([('/', MainPage),
('/cron/sendfu', sendFollowUp),
('/emailworker', pushQueue)],
debug=True)
I'm not sure I really understand your question, but can't you just create a POST request with the requests module?
Post Requests
>>> payload = {'key1': 'value1', 'key2': 'value2'}
>>> r = requests.post("http://httpbin.org/post", data=payload)
Also for easy task use have you seen the deferred library?
The deferred library lets you bypass all the work of setting up dedicated task handlers and serializing and deserializing your parameters by exposing a simple function, deferred.defer(). To call a function later, simply pass the function and its arguments to deferred.defer
Link

How to find out if a model class is db or a ndb

I created a utility to exchange or zip all the entities for a kind. But how can I find out if the model_class used is a db.Model or an ndb.Model?
def _encode_entity(self, entity):
if self.ndb :
entity_dict = entity.to_dict()
self.entity_eid = entity.key.id()
entity_dict['NDB'] = True
else :
entity_dict = db.to_dict(entity)
self.entity_eid = entity.key().name()
entity_dict['NDB'] = False
....
Now I use :
def queryKind(self):
try :
self.query = self.model_class.query()
self.ndb = True
except AttributeError :
self.query = self.model_class.all()
self.ndb = False
return self.make(self._encode_entity) # make a zip or a page
UPDATE : The solution I have used. See also Guido's answer
self.kind = 'Greeting'
module = __import__('models', globals(), locals(), [self.kind], -1)
self.model_class = getattr(module, self.kind)
entity = self.model_class()
if isinstance(entity, ndb.Model):
self.ndb = True
self.query = self.model_class.query()
elif isinstance(entity, db.Model):
self.ndb = False
self.query = self.model_class.all()
else :
raise ValueError('Failed to classify entities of kind : ' + self.kind)
How about import ndb and db, and testing for the entity being an instance of their respective Model classes?
if isinstance(entity, ndb.Model):
# Do it the NDB way.
elif isinstance(entity, db.Model):
# Do it the db way.
else:
# Fail. Not an entity.
you could use an attribute that does exist only in ndb or the other way around.
for example _has_repeated or _pre_get_hook which are properties of the ndb entities.
so you could do:
self.ndb = hasattr(self, '_has_repeated')

Resources