How to properly save form data in Google App Engine - python

I have an email form where I'm trying to save the user's email address to the database. The model looks like this:
class EmailForm(db.Model):
email_address = db.EmailProperty
I've been using a few tutorials like this as a guide where the data from the form is saved like this:
title = form.title.data,
content = form.content.data
when I follow the same convention, writing
email = form.email_address.data
there is an error that the EmailProperty does not have a data attribute.
I'm new to Google App Engine but I haven't found an answer in the docs. Thanks!

You are attempting to use a Model as a Form, which are two different things.
You need another step
from flaskext import wtf
from flaskext.wtf import validators
class EmailModel(db.Model):
email_address = db.EmailProperty
class EmailForm(wtf.Form):
email = wtf.TextField('Email Address', validators=[validators.Email()])
Now, in your view you can use the form like so.
#app.route('/register', methods=['POST']
def register():
form = EmailForm()
if form.validate_on_submit():
# This part saves the data from the form to the model.
email_model = EmailModel(email_address = form.email.data)
email.put()

I guess this is what you are looking for:
https://developers.google.com/appengine/docs/python/datastore/typesandpropertyclasses#Email
email_address = db.EmailProperty()
email_address = db.Email("larry#example.com")

You are using the old db class, use instead ndb, just replace db for ndb (https://docs.google.com/document/d/1AefylbadN456_Z7BZOpZEXDq8cR8LYu7QgI7bt5V0Iw/edit?ndplr=1&pli=1)
Use StringProperty instead EmailProperty, so..
class UserEmail(ndb.Model):
email_address = ndb.StringProperty()
To put models in datastore, do this
user = UserEmail(email_address='foobar#gmail.com')
user.put()

Related

Flask Security Confirm Register Form not adding new fields

Below is how I am trying to add extra fields to the confirm register form. When I enter my credentials in my application the application takes all the built in fields, sends it to my data base, and sends me a working confirmation email. However, the name, country, age fields are missing. I know the correct form is being used because the Captcha validate check is being done.
class NHRegisterForm(ConfirmRegisterForm):
name = db.StringField('Full Name', [DataRequired()])
country = db.StringField('Country', [DataRequired()])
age = db.StringField('Age', [DataRequired()])
def validate(self):
if not recaptcha.verify():
self.password.errors = self.password.errors + ("Error completing ReCaptcha below", )
return False
return super(NHRegisterForm, self).validate()
This is how I am passing my custom forms into the flask security initializer.
security = Security(app, user_datastore, confirm_register_form=NHRegisterForm, login_form=NHLoginForm)
Is there something I am missing here?
You need to also override the view to show those fields in the form. See docs on how to override (basically create folder: templates/security) and add register_user.html form override with your new fields.

Using Tagging and Autopopulate with Flask

I am trying to wrap my head around how to use a tagging system with Flask and WTForms.
Basically I have a list of keywords. These keywords have a hierarchy (example: I select Chicago. Illinois and USA get automatically added as additional keywords).
So I'm trying to find a way for users to type into an autopopulating list. This form then produces the keywords and brings it back into flask, where each keyword is used as it's own variable.
With WTForms we need the "id" to bring back into Flask, but in a form like taggle.js or select2 how can we separate each tag into it's own id? Or are there better ways to go about this?
Flask
class ReusableForm(Form):
example4 = StringField('example4')
#app.route("/editor", methods=['GET', 'POST'])
def hello():
form = ReusableForm(request.form)
if request.method == 'POST':
example4 = request.form['example4']
if form.validate():
# Return and do something with each keyword
# tag1 = 'Alaska'
# tag2 = 'Hawaii'
# tag3 = 'California'
You need to use a dynamic form that will accept a variable number of tags being POSTed to Flask.
forms.py:
class TagForm(NoCsrfForm):
tag_id = IntegerField(widget=HiddenInput(), default=0)
tag_name = StringField(widget=HiddenInput(), [InputRequired(), Length(max=256)])
class MyDynamicForm(Form):
some_field = StringField('Foo', [InputRequired()])
some_other_field = TextAreaField('Bar', [InputRequired()])
some_tags = FieldList(FormField(TagForm))
views.py:
#app.route('/')
def index():
form = MyDynamicForm()
if form.validate_on_submit():
if len(form.some_tags.data) >= 1:
# Do something with the received tags.
pass
return render_template('index.html', form=form)
index.html
<input id="some_tags-0-tag_name"></input>
Each input id must use the following syntax: "[some_tags]-[nth tag]-[tag_name]". You should hopefully know best to create inputs and their ids taking into account the js frameworks you have available.
N.B. tag_id = IntegerField(widget=HiddenInput(), default=0) isn't necessary for receiving POSTed input but is useful if you store tags in a database and later want to populate the form with stored tags.

How do i verify user in database in google appengine app ( can anyone recommend the best way to do user authentication for google appengine app)?

I have following code in models.py i can sort database by only key but not by string ?
from google.appengine.ext import ndb
class Roles(ndb.Model):
name = ndb.StringProperty()
owner = ndb.KeyProperty(kind='User')
created = ndb.DateTimeProperty(required=True, auto_now_add = True)
class RESTMeta:
user_owner_property = 'owner'
include_output_properties = ['name']
class Users(ndb.Model):
name = ndb.StringProperty()
email = ndb.StringProperty()
password = ndb.StringProperty()
roles = ndb.KeyProperty(kind='Roles')
owner = ndb.KeyProperty(kind='User')
created = ndb.DateTimeProperty(required=True, auto_now_add = True)
class RESTMeta:
user_owner_property = 'owner'
include_output_properties = ['name']
And the following in api.py
app = webapp2.WSGIApplication([
RESTHandler(
'/api/roles', # The base URL for this model's endpoints
models.Roles, # The model to wrap
permissions={
'GET': PERMISSION_ANYONE,
'POST': PERMISSION_ANYONE,
'PUT': PERMISSION_OWNER_USER,
'DELETE': PERMISSION_ADMIN
},
# Will be called for every PUT, right before the model is saved (also supports callbacks for GET/POST/DELETE)
put_callback=lambda model, data: model
),
RESTHandler(
'/api/users', # The base URL for this model's endpoints
models.Users, # The model to wrap
permissions={
'GET': PERMISSION_ANYONE,
'POST': PERMISSION_ANYONE,
'PUT': PERMISSION_OWNER_USER,
'DELETE': PERMISSION_ADMIN
},
# Will be called for every PUT, right before the model is saved (also supports callbacks for GET/POST/DELETE)
put_callback=lambda model, data: model
)],debug=True, config = config)
I can successfully get by key in api\users?q=roles=key('key')
How do i get specific user by String api\users?q=email=String('String')
The Question is how do I do user auth for google appengine app
You seem to be asking so many questions in one.
To get user by email, simply do this:
users = Users.query(Users.email=='query_email').fetch(1)
#note fetch() always returns a list
if users:
user_exists = True
else:
user_exists = False
Please note, you may need to update your datastore index to support that query. The easiest way to do it is to first run the code in your local development server, and the index will be automatically updated for you.
To answer your second questions, for user authentication I would recommend Django's in-built User Authentication. Please note that you can always run vanilla django on appengine with a Flexible VM using CloudSQL instead of the Datastore.
Alternatively, you could use the Appengine Users API, though your users would need to have Google Accounts.

Can we get the request object data in signal

I am registering the data in user model and also want to save the profile data same time like first_name and last_name in profile model.
So I have used django signals to store the profile information and send the mail to user.
But we are unable to get the first_name and last_name in signal file:
#---------------------------- Create profile at the time of registration --------------------------#
def register_profile(sender, **kwargs):
if kwargs.get('created'):
user = kwargs.get('instance')
request = kwargs.get("request")
if user.id is not None and user._disable_signals is not True:
profile = Profile(user=user)
if user.status is not 1:
#------------------- Send the registration mail to user and it have confirmation link ----------#
salt = hashlib.sha1(str(random.random())).hexdigest()[:5]
activation_key = hashlib.sha1(salt+user.email).hexdigest()
key_expires = datetime.datetime.today() + datetime.timedelta(2)
#print user
profile.activation_key = activation_key
profile.key_expires = key_expires
#--------------------- End -------------------------------------------------------------#
profile.save()
if user.status is not 1:
user = model_to_dict(user)
BaseSendMail.delay(user,type='account_confirmation',key = activation_key)
return
post_save.connect(register_profile, sender=User, dispatch_uid='register_profile')
#-------------------------- End ---------------------------------------------------------------------#
In above code I am unable to get first_name and last_name data which is sent at the time of registration.Also I would like to mention that first_name and last_name fields belong to profile model.
No, and you shouldn't try. Signals could be executed from anywhere: a management script, a Celery task, all sorts of places that might not have a request.
You could store the data on the User instance temporarily, as you do with the _disable_signals attribute. However I suspect that this is not really best done in a signal; since you're saving the result of a form submission, and it depends on the data in that form, you should really do that in the view or the form itself.
I did this and it worked.
Not sure about it's impact on performance etc.
some_file.py:
data = {}
middleware.py:
class MyMiddleware(object):
def process_request(self):
from path.to.some_file import data
data['request'] = self.request
signals / model_method / manager / template tag / any where else:
from path.to.some_file import data
request = data.get('request')

Google App Engine with Python: Unable to update the data entity

I have read, read, and read again the documentation and do many search on the Web but I don't understand yet why my app doesn't work correctly.
When a user connects, he have to complete a form. The code for this works. When the user logs out, and then, logs in, the form fields are filled with his information. So, the data is correctly saved. But, when the user changes the form fields values and submits the form, data are not updated.
My model:
class Members(db.Model):
account = db.UserProperty()
hashtags = db.StringProperty()
Here the class to submit the form:
class Submit(webapp.RequestHandler):
def post(self):
user = users.get_current_user()
if user:
url = users.create_logout_url('/')
url_linktext = 'Logout'
member = db.GqlQuery("SELECT * FROM Members WHERE account = :1", user)
if member.count(1) > 0:
m = Members(account=user)
m.hashtags = ','.join([
self.request.get('hashtag1'),
self.request.get('hashtag2'),
self.request.get('hashtag3')])
m.put()
else:
member = Members()
member.account = user
member.hashtags = ','.join([
self.request.get('hashtag1'),
self.request.get('hashtag2'),
self.request.get('hashtag3')])
member.put()
self.redirect('/')
else:
self.redirect('/')
The problem is you are adding a new record instead of updating the existing record. For your code, the simplest fix would be to change this:
if member.count(1) > 0:
m = Members(account=user)
to:
if member.count(1) > 0:
m = member[0]
The reason your code is updating the existing record is because you have not assigned a key. To learn more about keys, you can read about them in Kinds and Identifiers.

Categories