Referencing a related object in Pyramids/Python/SQLAlchemy - python

I'm not sure how to title this question. I've also simplified my code so it's easier to ask. Say I have the following code in myproject.models in Pyramid:
class Links(Base):
__tablename__ = 'links'
id = Column(Integer, primary_key=True)
link = Column(Text)
def __init__(self, link):
self.link = link
class Submissions(Base):
__tablename__ = 'submissions'
id = Column(Integer, primary_key=True)
title = Column(Text)
link_id = Column(Integer, ForeignKey('links.id'))
link = relationship(Links)
def __init__(self, title, link):
self.title = title
self.link = link
The view will be very simple:
def my_view(request):
dbsession = DBSession()
submissions = dbsession.query(Submissions)
return {'submissions':submissions}
I want to return this on my page using Chameleon:
<p tal:repeat="thing submissions">
${thing.title} ${thing.link}
</p>
However, ${thing.link} doesn't show the link of the site.
Questions:
How do I reference thing.link's link? Intuitively, I would type ${thing.link.link}, but that doesn't work.
How do I reference an arbitrary subclass? I want to be able to extract any attribute from an object's subclass, for example, thing.link.link, thing.link.domain, thing.link.created, etc.
BTW, someone please tell me a better title to give this question.

In your example, you are missing the .all() after your .query(). You can check in your view if your submissions are really loaded by doing something like
for submission in submissions:
print submission.id, submission.title
and then watch your console when loading the page.
Then, when you confirmed you really have them loaded, you can access the link object with submission.link. In the link object, you can access the link attribute with .link.
for submission in submissions:
print submission.link.link
So in your template, you could write ${thing.link.link}.

Assuming you do have the link object attached (given the fact that the link_id column is not nullable), most probably you need to (eager)load the relationship to Links because the session is alread closed when you populate your view.
See Relationship Loading Techniques for more information. The code below should do it:
submissions = dbsession.query(Submissions).options(joinedload('link'))

Related

if value already exist in mongodb delete it, else add it to end of the list (mongoengine)

I use Mongoengine and wanna delete a tag if it exists. If the tag doesnt exist, I want to add it. But my code is not really working.
try:
Project.objects.filter(literature__oid=id).update_one(
pull__literature__S__tags=tag_name)
print("wanna delete "+tag_name)
except:
Project.objects.filter(literature__oid=id).update_one(
push__literature__S__tags=tag_name)
print("wanna add"+tag_name)
this code only deletes the tag from the database but he doesn't jump into the except part if the tag doesn't exist. So he always runs the delete part even if the tag doesn't exist. Is there any other method I could use? I haven't found anything so far...
the tags field of literature is a ListField. So tags looks in mongoDB for example like this:
"tags": ["irrelevant", "relevant", "test"]
My Models basically look like this:
class Literature(EmbeddedDocument):
oid = ObjectIdField(required=True, default=ObjectId,
unique=True, primary_key=True, sparse=True)
tags = ListField()
class Project(Document):
project_name = StringField(unique=True, required=True)
literature = ListField(EmbeddedDocumentField(Literature))
So e.g. I have a literature object with the oid=1 and an literature object with the oid=2 and oid=1 has tags=["irrelevant", "test"] and oid=2 has tags =["relevant"]. I now would like to have the python function:
def LiteratureTag(id, tag_name):
#add tag_name to literature object with the passed id if the tag_name
#does't already exist in literature tags and if the tag does exist delete
#the tag from the literature object
so e.g. if I call LiteratureTag(1, "relevant") it should add the tag "relevant" from the literature object with the oid=1 and if I call LiteratureTag(2, "test") it should add the tag "test" to the literature object with oid=2. If I call LiteratureTag(2, "relevant") the tag "relevant" should get deleted from literature object with oid=2
Thanks
I prefer that you should not use try and except. You only go into except when your try block raises an error. It won't raise an error in your case. You can try to write your code by checking if the tag exists.
Taking your schema into account:
class Literature(EmbeddedDocument):
oid = ObjectIdField(required=True, default=ObjectId,
unique=True, primary_key=True, sparse=True)
tags = ListField()
class Project(Document):
project_name = StringField(unique=True, required=True)
literature = ListField(EmbeddedDocumentField(Literature))
I will write my query given your literature id is valid Object_id:
tag_name=<String> #type string
id=<Object_id> #type objectId
if Project.objects.filter(literature__oid=id,literature__tags__in=[tag_name]):
#your tag exists, so remove it
Project.objects.filter(literature__oid=id).update(pull__literature__S__tags=tag_name)
else:
#tag does not exist, push it
Project.objects.filter(literature__oid=id).update(push__literature__S__tags=tag_name)
The above query is totally aligned to your schema.

Is there a way to query.all() in peewee?

I need to transfer all data from an SQL table to an html page. In SQLAlchemy I would do something like this:
class Author(db.Model):
id = db.Column(db.Integer, primary_key=True)
first = db.Column(db.String(80))
last = db.Column(db.String(80))
#app.route('/authors')
def get_authors():
authors = Author.query.all()
# Serialize the queryset
result = authors_schema.dump(authors)
return jsonify({'authors': result.data})
Is there a something like authors = Author.query.all() in peewee?
To my knowledge, a direct equivalent does not exist in peewee, though there is an all method in the Dataset extension, documented here. You can do this pretty easily using a list comprehension:
authors = [author for author in Author.select()]
Or even just authors = list(Author). However, if you're trying to return these as JSON, it won't work because your list of authors is populated by instances of Author and Flask's JSONEncoder will not work with this type out of the box. You can get around this by using peewee's dicts() method:
authors = [author for author in Author.select().dicts()]
The full example would look like this:
#app.route('/authors')
def get_authors():
authors = [author for author in Author.select().dicts()]
return jsonify(authors)
Instead of serializing using dicts I often use marshmallow. For example you create an author_schema like so:
from marshmallow import Schema, fields
class AuthorSchema(Schema):
id = fields.Integer(dump_only=True)
first = fields.String()
last = fields.String()
author_schema = AuthorSchema()
and use it like so (not showing imports):
#app.route('/authors')
def get_authors():
authors = author_schema(Author, many=True)
return jsonify(authors)
so i make this.
#app.route('/authors')
def get_authors():
authors = Author.select()
return render_template('aurhors.html', authors=authors)
And in html something like this.
{% for a in authors %}
<p>{{a.author_name}}</p>
{% endfor %}
I only in begining of studying python, so thank for help.
What you're looking for is .dicts(), a method well-hidden in the docs, which returns an iterable peewee-specific type:
response = {'authors': []}
authors = Author.select()
for author in authors.dicts():
response['authors'].append(author)
Something like this should work of you're working with APIs:
return list(Account.select().dicts());

Google App Engine: Defining an entity's parent

I would like to create a datastore model for a book review webapp. This webapp would have two kinds - Book and Review:
class Book(ndb.Model):
title = ndb.StringProperty()
class Review(ndb.Model):
review = ndb.TextProperty()
The Reviewentities should be child entities to the parenting Book entities. Upon viewing a page of a Book entity, its list of Review child entities should also be queried and shown like this:
Review.query(ancestor=book.key).fetch()
The (simplified) handlers below would handle the creation of new entities:
class NewBook(BaseHandler):
def get(self):
self.render('new-book-form.html')
def post(self):
title = self.request.get('title')
b = Book(title = title)
b.put()
class NewReview(BaseHandler):
def get(self):
self.render('new-review-form.html')
def post(self):
book_key = self.get_book_key() # gets book entity's key
review = self.request.get('review')
r = Review(review = review) # Do I define this entity's parent here?
r.put()
According to the documentation, a parent is assigned inside a child entity's key like this:
review = Review(parent=ndbKey(Book, book_id), review = review)
At which point inside the NewReview handler do I define this? I may be missing something very obvious.
You pretty much have it right. Assuming your get_book_key method returns an actual ndb.Key instance, the line you've commented becomes:
r = Review(parent=book_key, review=review)

Google App Engine return object with reference set

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)

Storing wiki revisions on Google App Engine/Django - Modifying This Existing Code

In the past, I created a Django wiki, and it was fairly straightforward to make a Page table for the current wiki entries, and then to store old revisions into a Revision table.
More recently, I decided to set up a website on Google App Engine, and I used some wiki code that another programmer wrote. Because he created his Page model in sort of a complicated way (complicated to me at least) using Entities, I am unsure about how to create the Revision table and integrate it with his Page model.
Here is the relevant code. Could someone help me write the Revision model, and integrate saving the revisions with the Save method of the Page model?
class Page(object):
def __init__(self, name, entity=None):
self.name = name
self.entity = entity
if entity:
self.content = entity['content']
if entity.has_key('user'):
self.user = entity['user']
else:
self.user = None
self.created = entity['created']
self.modified = entity['modified']
else:
# New pages should start out with a simple title to get the user going
now = datetime.datetime.now()
self.content = '<h1>' + cgi.escape(name) + '</h1>'
self.user = None
self.created = now
self.modified = now
def save(self):
"""Creates or edits this page in the datastore."""
now = datetime.datetime.now()
if self.entity:
entity = self.entity
else:
entity = datastore.Entity('Page')
entity['name'] = self.name
entity['created'] = now
entity['content'] = datastore_types.Text(self.content)
entity['modified'] = now
if users.GetCurrentUser():
entity['user'] = users.GetCurrentUser()
elif entity.has_key('user'):
del entity['user']
datastore.Put(entity)
By the way, this code comes from: http://code.google.com/p/google-app-engine-samples/downloads/list
I'm pretty inexperienced with GAE Django models, and mine tend to be very simple. For example, here's my model for a blog Article:
class Article(db.Model):
author = db.UserProperty()
title = db.StringProperty(required=True)
text = db.TextProperty(required=True)
tags = db.StringProperty(required=True)
date_created = db.DateProperty(auto_now_add=True)
The code in your first snippet is not a model - it's a custom class that uses the low-level datastore module. If you want to extend it, I would recommend throwing it out and replacing it with actual models, along similar lines to the Article model you demonstrated in your second snippet.
Also, they're App Engine models, not Django models - Django models don't work on App Engine.
I created this model (which mimics the Page class):
class Revision (db.Model):
name = db.StringProperty(required=True)
created = db.DateTimeProperty(required=True)
modified = db.DateTimeProperty(auto_now_add=True)
content = db.TextProperty(required=True)
user = db.UserProperty()
In the Save() method of the Page class, I added this code to save a Revision, before I updated the fields with the new data:
r = Revision(name = self.name,
content = self.content,
created = self.created,
modified = self.modified,
user = self.user)
r.put()
I have the wiki set up now to accept a GET parameter to specify which revision you want to see or edit. When the user wants a revision, I fetch the Page from the database, and replace the Page's Content with the Revision's Content:
page = models.Page.load(title)
if request.GET.get('rev'):
query = db.Query(models.Revision)
query.filter('name =', title).order('created')
rev = request.GET.get('rev')
rev_page = query.fetch(1, int(rev))
page.content = rev_page.content

Categories

Resources