I would like to save contacts on AppEngine datastore from the Google API v3. I want to know what is the best way to store these data and especially if there is already a model!
Looking at the sources of gdata, I found a very interesting beginning. But this is the modeling of the data only in python and not for the datastore.
Question : Is this model already exists in python?
If not:
Question : What is the best way to start from scratch?
Beginning example of a contact in Python :
class Contact(db.Model):
"""
https://developers.google.com/gdata/docs/2.0/elements?hl=fr#gdContactKind
https://developers.google.com/appengine/docs/python/datastore/datamodeling
"""
content = db.Text()
"""atom:content Notes about the contact."""
link = db.ListProperty(Link,indexed=False,default=[])
"""atom:link* Links to related information. Specifically, atom:link[#rel='alternate'] links to an HTML page describing the contact."""
title = db.StringProperty()
"""atom:title Contact's name. This field is read only. To modify the contact's name, see gd:name."""
email = db.ListProperty(Email,indexed=False,default=[])
"""gd:email* Email addresses."""
"""etc..."""
class Link(db.Model):
"""
Link
"""
link = db.LinkProperty()
class Email(db.Model):
"""
Email
"""
email_address = db.EmailProperty()
class EmailImParent(db.Model):
address = db.StringProperty()
label = db.StringProperty()
rel = db.StringProperty()
primary = db.StringProperty()
class Email(db.Model,EmailImParent):
"""
The gd:email element.
"""
email = db.EmailProperty()
display_name = db.StringProperty()
I think everyone is rolling their own. It is easy enough to do, you can take a look at AE-BaseApp/Python and check out the code from the Github link. I have some new code that will be updated in the near future that contains some improvements to the contact model. (the updated code is currently broken due to hacking to get logins working on both http and https here)
Related
I am currently working on a small flask app that will be connecting to an api and processing data pulled from that api.
Users are able to login to my flask app and then also define their credentials to interact with the api. Any given user may have one or more API credentials associated with their user.
I've created db models to store user and Api credentials in the database as follows.
I'm using the flask-login module which has the "current_user" object which provides me with the User model of the user that is currently logged in across my entire app.
Models:
class User(UserMixin, db.Model):
__tablename__ = 'users'
id = db.Column(db.Integer, primary_key=True)
username = db.Column(db.String(64), index=True, unique=True)
email = db.Column(db.String(128), index=True, unique=True)
firstname = db.Column(db.String(55))
lastname = db.Column(db.String(55))
password = db.Column(db.String(128))
creds = db.relationship('ApiCredential', backref='owner', lazy='dynamic')
class ApiCredential(db.Model):
__tablename__ = 'api_credentials'
id = db.Column(db.Integer, primary_key=True)
site = db.Column(db.String(140))
user = db.Column(db.String(140))
username = db.Column(db.String(100), index=True, unique=True)
password = db.Column(db.String(55))
base = db.Column(db.String(100))
owner_id = db.Column(db.Integer, db.ForeignKey('users.id'))
active = db.Column(db.Boolean)
I would like to know how to create a similar "global variable" for my API credentials that is specific only to the logged in user and not to all users of the application
NOTE*** It seems as though "current_user" is something called a local proxy which i am not at all familiar with and cannot seem to find any decent documentation or explanation of what it is and how to use it for my needs.
You're in for a fun ride, at the end of which you might choose to do something less magic.
First, it helps to understand how current_user works. The source (as of this moment) is here. It's a werkzeug.local.LocalProxy, which wraps a lambda that calls flask_login.utils._get_user.
LocalProxy is pretty cool, and understanding it is a great way to level-up on Python, but flask-login uses a thin slice of it. The source (as of this moment) is here. It looks scary, but if you trace the code, it merely invokes the local arg (the lambda from flask-login).
That gets us back to _get_user (here, as of this moment), which loads a user if there isn't one (in the top of the current request context), and then returns the user from the top of the request context.
You could follow that pattern, and write a package that exports current_credentials. You'd follow the same pattern, using a werkzeug.local.LocalProxy to wrap a lambda that invoked, say, _get_credentials. The trick would be to import current_user from flask-login, using it with _get_credentials to get to user with which to construct the query to join to your ApiCredentials table.
Or you could take a simple approach, and write utility method for your views to use, which would use current_user to get the user and then do the join to get API credentials for that user.
One method could be to create a new route in your flask app, when the user get requests the page then you can check which user it is, once you know which user it is, you can query using your api credentials model and filter by current_user.id.
creds = ApiCredentials.query.filter_by(owner_id=current_user.id).first_or_404()
Then you can do as you please with the information stored in your API Credentials table.
I don't see why you would want to replicate the user loader functionality. This is the function you will have included at some point when you set up Flask login. Very short function that returns the current user object from the user model.
You could display or return your api keys. Display them on a page as HTML or for more autonomous jobs, you could use jsonify to return the keys as a json string.
I'm sorry this doesn't directly answer your question, but I hope my suggestion might lead you to a slightly less complex answer and you can continue developing your web app. Perhaps it would be worth revisiting at a later date.
Note: this is off the top of my head. The code line I provided might need to be as follows
creds = ApiCredentials.query.filter_by(owner_id==current_user.id).first()
Furthermore, you may not want to use .first() if they have multiple api credentials stored in the table.
In which case this would be more suitable:
creds = ApiCredentials.query.filter_by(owner_id==current_user.id).all()
I am trying to figure out the best method of accessing all the matching microseries found in the Assessment class (table) in my database. I am trying to create a link that will send a user to those matching microseries. I am new and want to better understand the nuts and bolts of front-end engineering. I also have not seen a similar question asked here on Stacks.
I am not using JSON or XML yet, so this is a static HTML process. I have a few routes that access assessments at the moment, e.g.:
config.add_route('assessments', '/assessments')
config.add_route('assessment', '/assessments/{id:\d+}')
What I would like to better understand while implementing a method of finding matching microseries in the Assessment table and sending the user to a new page with those matching series:
How routes work, especially when accessing an attribute of a class, e.g. Assessment.microseries.
The goal of View code to convey the method mentioned above.
Pyramid links and Pyramid on Routes and URL Dispatch
Using: Python 2.7, SQLAlchemy, Pyramid
Assessment table:
class Assessment(Base):
__tablename__ = 'assessments'
id = Column(Integer, primary_key=True)
name = Column(String(50), unique=True)
text = Column(String(2000))
microseries = Column(Integer)
# more code
def __init__(self, name, text, user, video, categories, microseries):
# more code
API for interacting with an assessment is based on CRUD- create, retrieve, update and delete.
View Code:
this is not doing what I need it to do as I don't have a form of link to send the user to the matching series, e.g. Link1 would send a user to a new view with GET for all subseries of Link1: 1a, 1b, 1c....
#view_config(route_name='assessments', request_method='GET', renderer='templates/unique_assessments.jinja2', permission='create')
def view_unique_microseries_group(request):
logged_in_userid = authenticated_userid(request)
if logged_in_userid is None:
raise HTTPForbidden()
all_assessments = api.retrieve_assessments() #all assessments in a list
assessments_by_microseries = {} #dictonary
for x in all_assessments:
if x.microseries in assessments_by_microseries:
print("Already seen this microseries: %s" % x.microseries)
else:
assessments_by_microseries[x.microseries] = x
unique_assessments = sorted(assessments_by_microseries.values()) #.values() method to get the, err, values of the dict.
print 'unique_assessments:', unique_assessments
#a = HTTPSeeOther(location=request.route_url('view_microseries'))
return {'logged_in': logged_in_userid, 'unique_assessments': unique_assessments} #need to send some kind of list that can be shown on the template to send a user to the appropriately matching set of microseries
I am starting an App Engine application.
I started defining some simple models I will need.
I want to write tests for my application (that would be the first time I've done that).
I cannot see what I should be testing for.
I already looked to how to do this (https://developers.google.com/appengine/docs/python/tools/localunittesting), but I just don't know what to test...
Here is my code so far:
class User(db.Model):
email = db.EmailProperty()
name = db.StringProperty()
class Service(db.Model):
name = db.StringProperty(required=True)
class UserService(db.Model):
user_id = db.ReferenceProperty(User,
required=True,
collection_name='user_services')
service_id = db.ReferenceProperty(Service,
required=True)
access_token = db.StringProperty(required=True)
refresh_token = db.StringProperty(required=True)
class LocalServer(db.Model):
authentication_token = db.StringProperty(required=True)
class Task(db.Model):
user_service_id = db.Reference(UserService,
required=True,
collection_name='tasks')
local_server_id = db.ReferenceProperty(LocalServer,
required=True,
collection_name='tasks')
creation_date = db.DateTimeProperty(auto_now_add=True,
required=True)
completion_date = db.DateTimeProperty(required=True)
number_of_files = db.IntegerProperty(required=True)
status = db.StringProperty(required=True,
choices=('created', 'validated', 'in_progress', 'done'))
Quoting Wikipedia:
Intuitively, one can view a unit as the smallest testable part of an application.
Now, I don't know exactly what your application is supposed to do, but in general you don't have to test each specific class/model. What does this mean? Well, you don't need to test a feature like this: "what happens when I add two users, and then I want to filter them by a specific name?". You don't have to test it, because in that case you would test a GAE function, .filter(). Now, why should you test it? :) Google pays its developers for that!
But what if you write a "filter" method? What if you customize the filter() method? Then you must test them.
I suggest you to read this answer. The question is about Django models, but actually it is valid for every framework or programming language.
Hi I am kind of trying to get the concept behind DataStore as a No-SQL database, what I am trying to fetch is a list of object wich have been "reference" by another. As this
class Person(db.Model):
name = db.StringProperty(required=True)
class Contact(db.Model):
name = db.StringProperty(required=True)
email = db.StringProperty()
trader = db.ReferenceProperty(Person)
This works fine and they get to be saved when I use person.put() without any problem. But when I try to retrieve it and encoded as json it nevers shows me the contact as a list in fact it totally ignores it.
persons_query = Person.all()
persons = persons_query.fetch(50)
data = json.encode(persons)
I would expect person to have a collection of Contact but it doesn't any ideas on how to solve this problem?
To make it clearer currently i am getting something like this:
[
{
name: "John Doe"
}
]
I would like to be
[
{
name: "John Doe"
contacts: [{name:"Alex", email:'alex#gmail.com'}]
}
]
Edit
Thanks all you were right I needed to fetch the collection of contacts there was only one issue for this is that when Contact was being encoded it recursively tried to encode the Trader object and this it's contact and so on.
So I got an obvious error recursive error, the solution to this was clearly to remove the trader object from the Contact when it's being encoded.
Make a custom toJson function in your class
class Person(db.Model):
name = db.StringProperty(required=True)
def toJson(self):
contact = self.contact_set #this is the default collection name for your class
d = {"name":self.name,"contact":contact}
return json.dumps(d)
class Contact(db.Model):
name = db.StringProperty(required=True)
email = db.StringProperty()
trader = db.ReferenceProperty(Person)
then you may do the ff:
persons_query = Person.all()
persons = persons_query.fetch(50)
data = person.toJson()
To fetch all the contacts you will need to write a custom json encoder, which fetches all of the reverse of the reference property.
ReferenceProperties automatically get a reverse query. From the docs "collection_name is the name of the property to give to the referenced model class. The value of the property is a Query for all entities that reference the entity. If no collection_name is set, then modelname_set (with the name of the referenced model in lowercase letters and _set added) is used."
So you would add a method to resolve the reverse reference set query.
class Person(db.Model):
name = db.StringProperty(required=True)
def contacts(self):
return self.contact_set.fetch(50) # should be smarter than that
Then use it in your custom json encoder.
If you want to find all the contacts that include a person you will need to issue a query for it.
contacts = Contact.all().filter("trader =", person)
I am trying to understand the 1-to-many relationships in datastore; but I fail to understand how query and update the record of a user when the model includes ReferenceProperty. Say I have this model:
class User(db.Model):
userEmail = db.StringProperty()
userScore = db.IntegerProperty(default=0)
class Comment(db.Model):
user = db.ReferenceProperty(User, collection_name="comments")
comment = db.StringProperty()
class Venue(db.Model):
user = db.ReferenceProperty(User, collection_name="venues")
venue = db.StringProperty()
If I understand correctly, the same user, uniquely identified by userEmail can have many comments and may be associated with many venues (restaurants etc.)
Now, let's say the user az#example.com is already in the database and he submits a new entry.
Based on this answer I do something like:
q = User.all()
q.filter("userEmail =", az#example.com)
results = q.fetch(1)
newEntry = results[0]
But I am not clear what this does! What I want to do is to update comment and venue fields which are under class Comment and class Venue.
Can you help me understand how this works? Thanks.
The snippet you posted is doing this (see comments):
q = User.all() # prepare User table for querying
q.filter("userEmail =", "az#example.com") # apply filter, email lookup
- this is a simple where clause
results = q.fetch(1) # execute the query, apply limit 1
the_user = results[0] # the results is a list of objects, grab the first one
After this code the_user will be an object that corresponds to the user record with email "az#example.com". Seing you've set up your reference properties, you can access its comments and venues with the_user.comments and the_user.venues. Some venue of these can be modified, say like this:
some_venue = the_user.venues[0] # the first from the list
some_venue.venue = 'At DC. square'
db.put(some_venue) # the entry will be updated
I suggest that you make a general sweep of the gae documentation that has very good examples, you will find it very helpful:
http://code.google.com/appengine/docs/python/overview.html
** UPDATE **: For adding new venue to user, simply create new venue and assign the queried user object as the venue's user attribute:
new_venue = Venue(venue='Jeferson memorial', user=the_user) # careful with the quoting
db.put(new_venue)
To get all Comments for a given user, filter the user property using the key of the user:
comments = Comment.all().filter("user =", user.key()).fetch(50)
So you could first lookup the user by the email, and then search comments or venues using its key.