GAE Python Query ordering won't take certain properties - python

In the official tutorial for GAE guestbook, I'm trying to change the order of query results like so:
greetings_query = Greeting.query(
ancestor=guestbook_key(guestbook_name)).order(Greeting.content)
Greeting looks like this:
class Greeting(ndb.Model):
content = ndb.StringProperty(indexed=False)
date = ndb.DateTimeProperty(auto_now_add=True)
Passing Greeting.date obviously works.
What could be the reason?

Related

How to map an existing python class to a Django model

I'm writing a web scraper to get information about customers and appointment times to visit them. I have a class called Job that stores all the details about a specific job. (Some of its attributes are custom classes too e.g Client).
class Job:
def __init__(self, id_=None, client=Client(None), appointment=Appointment(address=Address(None)), folder=None,
notes=None, specific_reqs=None, system_notes=None):
self.id = id_
self.client = client
self.appointment = appointment
self.notes = notes
self.folder = folder
self.specific_reqs = specific_reqs
self.system_notes = system_notes
def set_appointment_date(self, time, time_format):
pass
def set_appointment_address(self, address, postcode):
pass
def __str__(self):
pass
My scraper works great as a stand alone app producing one instance of Job for each page of data scraped.
I now want to save these instances to a Django database.
I know I need to create a model to map the Job class onto but that's where I get lost.
From the Django docs (https://docs.djangoproject.com/en2.1/howto/custom-model-fields/) it says in order to use my Job class in the Django model I don't have to change it at all. That's great - just what I want. but I can't follow how to create a model that maps to my Job class.
Should it be something like
from django.db import models
import Job ,Client
class JobField(models.Field):
description = "Job details"
def __init__(self, *args, **kwargs):
kwargs['id_'] = Job.id_
kwargs['client'] = Client(name=name)
...
super().__init__(*args, **kwargs)
class Job(models.Model):
job = JobField()
And then I'd create a job using something like
Job.objects.create(id_=10101, name="Joe bloggs")
What I really want to know is am I on the right lines? Or (more likely) how wrong is this approach?
I know there must be a big chunk of something missing here but I can't work out what.
By mapping I'm assuming you want to automatically generate a Django model that can be migrated in the database, and theoretically that is possible if you know what field types you have, and from that code you don't really have that information.
What you need to do is to define a Django model like exemplified in https://docs.djangoproject.com/en/2.1/topics/db/models/.
Basically you have to create in a project app's models.py the following class:
from django import models
class Job(models.Model):
client = models.ForeignKey(to=SomeClientModel)
appointment = models.DateTimeField()
notes = models.CharField(max_length=250)
folder = models.CharField(max_length=250)
specific_reqs = models.CharField(max_length=250)
system_notes = models.CharField(max_length=250)
I don't know what data types you actually have there, you'll have to figure that out yourself and cross-reference it to https://docs.djangoproject.com/en/2.1/ref/models/fields/#model-field-types. This was just an example for you to understand how to define it.
After you have these figured out you can do the Job.objects.create(...yourdata).
You don't need to add an id field, because Django creates one by default for all models.

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());

Query statement in get_by_id (ndb, GAE)

I'm using Google App Engine with webapp2 and Python.
I have a User model with a deleted field:
class User(ndb.Model):
first_name = ndb.StringProperty()
last_name = ndb.StringProperty()
email = ndb.StringProperty()
deleted = ndb.BooleanProperty(default=False)
I'd like to get a User object by calling User.get_by_id() but I would like to exclude objects that have deleted field True. Is it possible to do this with the normal get_by_id() function?
If not, could I override it?
Or should I create a custom class method, smth like get_by_id_2() that does a normal .get() query like this: User.query(User.key.id()==id, User.deleted==False).get()?
Would you reccomend something else instead?
A query is significantly slower than a get, and is subject to eventual consistency. You should probably use the normal get_by_id and check deleted afterwards. You certainly could wrap that up in a method:
#classmethod
def get_non_deleted(cls, id):
entity = cls.get_by_id(id)
if entity and not entity.deleted:
return entity

How to save an embedded object in GAE?

I'm trying to save a datastore entity reference within another:
class Save(webapp2.RequestHandler):
def get(self):
order = Order(parent=ndb.Key('Orders', 'default_orders'))
order.special_request = self.request.get('specialRequirement')
order.product_type = self.request.get('productType')
customer = Customer(parent=ndb.Key('Customer', 'default_customers'))
customer.name = self.request.get('customerName')
customer.email = self.request.get('email')
customer.put()
order.customer = customer
order.put()
The Customer class is simply:
from google.appengine.ext import ndb
class Customer(ndb.Model):
name = ndb.StringProperty()
email = ndb.StringProperty()
Whilst I've done similar with Rails and mongodb before, I'm not sure what this is called in GAE and am having a hard time searching for examples.
Ok, the following seems to have been my oversight, simply passing the key as:
oder.customer = customer.key
I now have a usable reference to the embedded object and both are being saved correctly.

How to update data in google app engine - Python?

How do i update my records in google app engine?
I have my model with the following fields
doc_no = db.IntegerProperty()
title = db.StringProperty()
level = db.StringProperty()
What i want is to update the fields title and level, but i want to access the properties/attributes via a string like JavaScript objects i.e
if i do a select to the model
myRecord = db.GQLQuery('Select * from MyModelAbove where doc_no = 1')
Is it possible to access and update the properties like this;
myRecord['title']='New Tile'
myRecord['level']='Level2'
myRecord.put()
The one i have seen is this(not working for me);
myRecord.title = 'New Title'
NB: By the way google documentation is very scanty on this area
In your code sample, myRecords is a query. You must get the result before any modification:
result = myRecords.get()
Then, if you can't or don't want to access the title property with result.title, you could use setattr(result, 'title', 'New Title') then result.put()

Categories

Resources