create unique profile page for each user python - python

I am using google app engine in python with a Jinja2 template engine.
This may be a silly solution but I have a list of a few thousand users and right now they can only access their own profile pages and have to be logged in to do it. I would like to give every user a unique URL for their profile page and I am wondering how to do it. I am not sure if this would work but could something like this be feasible?
class ProfilePage
userlist = GQL query to return all users in the system
user = users.get_by_id()
for user in userlist:
id = user.federated_id
posts = GQL query to return all posts by that user
self.render('/profile/id', posts=posts)
app = webapp2.WSGIApplication([('/', MainPage),
('/profile/([0-9]+)', ProfilePage),])
My HTML for the profile page just displays the user's name and then displays all of their recent posts.
Update:
So here is my current code but I am just getting a 404 error:
class ProfilePage(webapp2.RequestHandler):
def get(self, profile_id):
user = User.get_by_id(profile_id)
#profile_id = some unique field
if user:
#Get all posts for that user and render....
theid = user.theid
personalposts = db.GqlQuery("select * from Post where theid =:1 order by created desc limit 30", theid)
else:
personalposts = None
global visits
logout = users.create_logout_url(self.request.uri)
currentuser = users.get_current_user()
self.render('profile.html', user = currentuser, visits = visits, logout=logout, personalposts=personalposts)
How can I test it out I tried just entering www.url.com/profile/https://www.google.com/accounts/o8/id?id=AItOawlILoSKGNwU5RuTiRtXug1l8raLEv5-mZg
Update:
The ID I was retrieving was not their OpenID URL but rather a app specific id that each user is given and thus that is the correct to use

An easy way to do this would be to assign a unique URL identifier to each user (or use their key name), that way you can query the user by their ID or do a query based on a unique URL identifier property. You can also use their federated_id if you wanted.
Example:
class User(ndb.Model):
unique_identifier = ndb.StringProperty()
...
class ProfilePage(webapp2.RequestHandler):
def get(self, profile_id):
#profile_id = key name of user
user = User.get_by_id(profile_id)
#profile_id = some unique field
#user = User.query(User.unique_identifier == profile_id).get()
if user:
#Get all posts for that user and render....
app = webapp2.WSGIApplication([('/', MainPage),
('/profile/<profile_id>', ProfilePage),])

Related

Mongoengine ValidationError You can only reference documents once they have been saved to the database

Summary: (Python+Flask+MongoDB) Defined two models - User and Post. Post references User. Trying to create a Post by referencing a saved User but getting You can only reference documents once they have been saved to the database error.
Detail
Hello! I'm following a python (installed v3.7), flask (installed v1.1.2), MongoDB (installed mongoengine v0.23.0) tutorial to write a simple blogging app.
I have a User model and a Post model. A User may register, login and write Posts. I am able to create and save Users. However, when I try to create a Post by referencing a (previously created & saved) User, I get a Mongoengine ValidationError You can only reference documents once they have been saved to the database
The User object referenced in the Post object is present in the DB - confirmed that via the Mongo shell.
Any pointers/help/inputs would be much appreciated. I am new to MongoDB.
Code
# models.py
from flask_mongoengine import MongoEngine
db = MongoEngine()
class User(db.Document):
_id = db.ObjectIdField()
username = db.StringField(required = True)
email = db.EmailField(required = True)
class Post(db.Document):
_id = db.ObjectIdField()
created_by = db.ReferenceField(User)
title = db.StringField(required = True)
body = db.StringField(required = True)
# blog.py
""" Module that creates blog posts
from app.models import User, Post
def create():
if request.method == 'POST':
title = request.form['title']
body = request.form['body']
user = User.objects.get(_id=g.user['_id'])
# check user fetched by printing object id
# user[_id] matches the User ObjectID obtained via the mongo shell
print('user id = ' + str(user['_id']))
post = Post(title=title, body=body)
post.created_by = user
post.save() # --> this line generates the error
return redirect(url_for('blog.index'))
return render_template('blog/create.html')
Error
File "/Users/<my_username>/.pyenv/versions/3.7.3/lib/python3.7/site-packages/mongoengine/base/document.py", line 433, in validate
raise ValidationError(message, errors=errors)
mongoengine.errors.ValidationError: ValidationError (Post:None) (You can only reference documents once they have been saved to the database: ['created_by'])
Based on this Stackoverflow question, I was able to make this work by saving the User and then passing the DBRef of the User into the Post.
user = User.objects.get(_id=g.user['_id'])
user.save()
post = Post(title=title, body=body)
post.created_by = user.to_dbref()
post.save()

Create django object using a view with no form

I was wondering how I would be able to create an object in a database based the URL a user is going to.
Say for example they would go to /schedule/addbid/1/ and this would create an object in the table containing the owner of the bid, the schedule they bidded on and if the bid has been completed. This here is what I have for my model so far for bids.
class Bids(models.Model):
id = models.AutoField("ID", primary_key=True, editable=False,)
owner = models.ForeignKey(User)
biddedschedule = models.ForeignKey(Schedule)
complete = models.BooleanField("Completed?", default=False)
The biddedschedule would be based on the number in the URL as the 1 in this case would be the first schedule in the schedule table
Any ideas on how to do this?
You should get the id parameter using urls.py:
#urls.py
from appname.views import some_view
urlpatterns = patterns('',
url(r'^schedule/addbid/(?P<id>\d+)$', some_view),
...
)
Take a look at the documentation about capturing parameters in the urlconf.
And then, in views.py you should construct a Bids Object using the id passed in the URL, the currently logged in user (request.user), and the biddschedule from your DB. For example:
#views.py
def some_view(request, id):
if request.user.is_authenticated():
# get the biddschedule from your DB
# ...
bids = models.Bids(id=id, owner=request.user, biddedschedule=biddedschedule)
bids.save()
return HttpResponse("OK")
return Http404()
Catch the number via the urlconf. Get the current user via request.user. Create a model instance by calling its constructor, and save it to the database via its save() method.
`#view.py under a post or get method`
new_bird, created = Bids.objects.get_or_create(
owner = user_obj,
biddedschedule = biddedschedule_obj,
complete = bool
)
new_bird.save()

How do I get user email using Facebook Graph API in GAE Python?

I'm using Facebook Graph API on Google App Engine. I was able to fetch all the basic info from an user. However when I tried to fetch any user info that requires permission, email for exemple, it always appears as None. I've followed the whole tutorial available at the developers blog.
Here's my code:
class User(db.Model):
id = db.StringProperty(required=True)
created = db.DateTimeProperty(auto_now_add=True)
updated = db.DateTimeProperty(auto_now=True)
name = db.StringProperty(required=True)
email = db.StringProperty(required=True)
profile_url = db.StringProperty(required=True)
access_token = db.StringProperty(required=True)
class BaseHandler(webapp.RequestHandler):
"""Provides access to the active Facebook user in self.current_user
The property is lazy-loaded on first access, using the cookie saved
by the Facebook JavaScript SDK to determine the user ID of the active
user. See http://developers.facebook.com/docs/authentication/ for
more information.
"""
#property
def current_user(self):
if not hasattr(self, "_current_user"):
self._current_user = None
cookie = facebook.get_user_from_cookie(
self.request.cookies, FACEBOOK_APP_ID, FACEBOOK_APP_SECRET)
if cookie:
# Store a local instance of the user data so we don't need
# a round-trip to Facebook on every request
user = User.get_by_key_name(cookie["uid"])
if not user:
graph = facebook.GraphAPI(cookie["access_token"])
profile = graph.get_object("me")
user = User(key_name=str(profile["id"]),
id=str(profile["id"]),
name=profile["name"],
email=profile["email"],
profile_url=profile["link"],
access_token=cookie["access_token"])
user.put()
elif user.access_token != cookie["access_token"]:
user.access_token = cookie["access_token"]
user.put()
self._current_user = user
return self._current_user
And here is the template/HTML:
<fb:login-button autologoutlink="true" perms="email"></fb:login-button>
{% if current_user %}
<p><img src="http://graph.facebook.com/{{ current_user.id }}/picture?type=square"/></p>
<p>Hello, {{ current_user.name|escape }}</p>
<p>email: {{ current_user.email }} </p>
{% endif %}
Is there something wrong? Is there other way to get user email?
Email is written on User creation. Maybe you are trying to access users that were created when you didn't have email permission, therefore the written email was None. Does the problem appear also for new User object?
Just gave up using facebook.py and facebookoauth.py and made my own OAuth 2 client using urlfetch. See 'Authenticating Users in a Web Application' in Facebook docs.
Also, I put scope='email' in requests to https://graph.facebook.com/oauth/authorize? and https://graph.facebook.com/oauth/access_token?.
Your code looks correct so I would assume that you don't have the correct extended permissions. You must ask for the "email" extended permission if you are going to try to get the email address. You can find the list of extended permissions here. You must ask for these permissions before you can read these properties using the Graph API.

Datastore query outputting for Django form instance

I'm using google appengine and Django. I'm using de djangoforms module and wanted to specify the form instance with the information that comes from the query below.
userquery = db.GqlQuery("SELECT * FROM User WHERE googleaccount = :1", users.get_current_user())
form = forms.AccountForm(data=request.POST or None,instance=?????)
I've found a snippet in a sample app that does this trick, but I can't modify it to work with the query I need.
gift = User.get(db.Key.from_path(User.kind(), int(gift_id)))
if gift is None:
return http.HttpResponseNotFound('No gift exists with that key (%r)' %
gift_id)
form = RegisterForm(data=request.POST or None, instance=gift)
Could anyone help me?
If you know the userquery will only have one User object in it (or if you only care about the first one if there are duplicates), you can modify your code like so:
userquery = db.GqlQuery("SELECT * FROM User WHERE googleaccount = :1", users.get_current_user())
user = userquery.get() # Gets the first User instance from the query, or None
form = forms.AccountForm(data=request.POST or None, instance=user)

Unable to query from entities loaded onto the app engine datastore

I am a newbie to python. I am not able to query from the entities- UserDetails and PhoneBook I loaded to the app engine datastore. I have written this UI below based on the youtube video by Brett on "Developing and Deploying applications on GAE" -- shoutout application. Well I just tried to do some reverse engineering to query from the datastore but failed in every step.
#!/usr/bin/env python
import wsgiref.handlers
from google.appengine.ext import db
from google.appengine.ext import webapp
from google.appengine.ext.webapp import template
import models
class showPhoneBook(db.Model):
""" property to store user_name from UI to persist for the session """
user_name = db.StringProperty(required=True)
class MyHandler(webapp.RequestHandler):
def get(self):
## Query to get the user_id using user_name retrieved from UI ##
p = UserDetails.all().filter('user_name = ', user_name)
result1 = p.get()
for itr1 in result1:
userId = itr.user_id
## Query to get the phone book contacts using user_id retrieved ##
q = PhoneBook.all().filter('user_id = ', userId)
values = {
'phoneBookValues': q
}
self.request.out.write(
template.render('phonebook.html', values))
def post(self):
phoneBookuser = showPhoneBook(
user_name = self.request.get('username'))
phoneBookuser.put()
self.redirect('/')
def main():
app = webapp.WSGIApplication([
(r'.*',MyHandler)], debug=True)
wsgiref.handlers.CGIHandler().run(app)
if __name__ == "__main__":
main()
This is my models.py file where I've defined my UserDetails and PhoneBook classes,
#!/usr/bin/env python
from google.appengine.ext import db
#Table structure of User Details table
class UserDetails(db.Model):
user_id = db.IntegerProperty(required = True)
user_name = db.StringProperty(required = True)
mobile_number = db.PhoneNumberProperty(required = True)
#Table structure of Phone Book table
class PhoneBook(db.Model):
contact_id = db.IntegerProperty(required=True)
user_id = db.IntegerProperty(required=True)
contact_name = db.StringProperty(required=True)
contact_number = db.PhoneNumberProperty(required=True)
Here are the problems I am facing,
1) I am not able to call user_name (retrieved from UI-- phoneBookuser = showPhoneBook(user_name = self.request.get('username'))) in get(self) method for querying UserDetails to to get the corresponding user_name.
2) The code is not able to recognize UserDetails and PhoneBook classes when importing from models.py file.
3) I tried to define UserDetails and PhoneBook classes in the main.py file itself, them I get the error at result1 = p.get() saying BadValueError: Unsupported type for property : <class 'google.appengine.ext.db.PropertiedClass'>
I have been struggling since 2 weeks to get through the mess I am into but in vain. Please help me out in straightening out my code('coz I feel what I've written is a error-prone code all the way).
I recommend that you read the Python documentation of GAE found here.
Some comments:
To use your models found in models.py, you either need to use the prefix models. (e.g. models.UserDetails) or import them using
from models import *
in MyHandler.get() you don't lookup the username get parameter
To fetch values corresponding to a query, you do p.fetch(1) not p.get()
You should also read Reference properties in GAE as well. I recommend you having your models as:
class UserDetails(db.Model):
user_name = db.StringProperty(required = True)
mobile_number = db.PhoneNumberProperty(required = True)
#Table structure of Phone Book table
class PhoneBook(db.Model):
user = db.ReferenceProperty(UserDetails)
contact_name = db.StringProperty(required=True)
contact_number = db.PhoneNumberProperty(required=True)
Then your MyHandler.get() code will look like:
def get(self):
## Query to get the user_id using user_name retrieved from UI ##
user_name = self.request.get('username')
p = UserDetails.all().filter('user_name = ', user_name)
user = p.fetch(1)[0]
values = {
'phoneBookValues': user.phonebook_set
}
self.response.out.write(template.render('phonebook.html', values))
(Needless to say, you need to handle the case where the username is not found in the database)
I don't quite understand the point of showPhoneBook model.
Your "session variable" being stored to the datastore isn't going to follow your redirect; you'd have to fetch it from the datastore in your get() handler, although without setting a session ID in a cookie or something this isn't going to implement sessions at all, but rather allow anyone getting / to use whatever value was send with a POST request whether it was sent by them or someone else. Why use the redirect at all; responding to a POST request should be done in the post() method, not through a redirect to a GET method.

Categories

Resources