My app, Datastore, webapp2, and form-specific "responses" are all working :) but I need the page to load without displaying previous visitor's query results. I need query results only for current form-submitter, after they submit form. Is this a session or headers solution, or can I edit the GqlQuery to accomplish this?
messages = db.GqlQuery("SELECT * "
"FROM Visitor "
"ORDER BY date DESC LIMIT 1") #obviously shows previous form submit
for message in messages:
if message.name == "" or message.mood == "":
self.response.out.write("<div class='textright'>Type name and select.</div>")
self.response.out.write("</body></html>")
elif message.mood == "bad" and message.name != "":
self.response.out.write("<body><html>")
self.response.out.write("<div class='textright'>Stay the course
^ ^ this last section is my "response" that needs to appear only after current visitor submits form.
I would strongly recommend you to go through the Getting Started and especially the templates section, until you will understand how it works.
But you if you just want to see your example in action try this (read more):
class Process(webapp.RequestHandler):
def post(self):
name = self.request.get("name")
mood = self.request.get("mood")
if mood == "bad" and name != "":
self.response.out.write("<html><body>")
self.response.out.write("<h1>Welcome to the Internet!</h1>")
self.response.out.write("<p>My mood is %s and my name is %s</p>" % (mood, name))
self.response.out.write("</body></html>")
else:
self.response.out.write("<html><body>")
self.response.out.write("<h1>Welcome to the Internet anyway!</h1>")
self.response.out.write("</body></html>")
Also never use print in your GAE applications, use the logger instead for debugging and more.
If you want to emit values for debugging purposes, particularly if you want that before an <html> tag is written, try
self.response.out.write("<!-- name: %s -->" % self.request.get("name"))
Otherwise, the browser might get confused.
print from a handler will never to what you expect.
In your snippet, you haven't shown where var7 and var9 come from.
I do realize that post/.put form values to Datastore automatically redirects user to new page
I think you misunderstand. You haven't shown us where your code does a put() or a redirect. A post() handler does not automatically do either.
Which tutorial are you looking at? Perhaps we need to tighten up vague wording.
Related
So this is my first time coding an actual project that isn't a small coding task. I've got a bot that runs and responds to a message if it says "hello". I've read the API documentation up and down and really only have a vague understanding of it and I'm not sure how to implement it.
My question right now is how would I go about creating a command that takes informationn from a message the command is replying to (sender's name, message content) and stores it as an object. Also, what would be the best way to store that information?
I want to learn while doing this and not just have the answers handed to me ofc, but I feel very lost. Not sure where to even begin.
I tried to find tutorials on coding discord bots that would have similar functions to what I want to do, but can't find anything.
Intro :
Hi NyssaDuke !
First of all, prefer to paste your code instead of a picture. It's easier for us to take your code and try to produce what you wish.
In second, I see an "issue" in your code since you declare twice the bot. You can specify the intents when you declare your bot as bot = commands.Bot(command_prefix="!", intents=intents)
Finally, as stated by #stijndcl , it's against TOS, but I will try to answer you at my best.
filesystem
My bot needs to store data, like users ID, language, and contents relative to a game, to get contacted further. Since we can have a quite big load of requests in a small time, I prefered to use a file to store instead of a list that would disappear on crash, and file allow us to make statistics later. So I decided to use pytables that you can get via pip install pytables. It looks like a small DB in a single file. The file format is HDF5.
Let say we want to create a table containing user name and user id in a file :
import tables
class CUsers (tables.IsDescription) :
user_name = StringCol(32)
user_id = IntCol()
with tables.open_file("UsersTable.h5", mode="w") as h5file :
groupUser = h5file.create_group("/", "Users", "users entries")
tableUser = h5file.create_table(groupUser, "Users", CUsers, "users table")
We have now a file UsersTable.h5 that has an internal table located in root/Users/Users that is accepting CUsers objects, where, therefore, user_name and user_id are the columns of that table.
getting user info and storing it
Let's now code a function that will register user infos, and i'll call it register. We will get the required data from the Context that is passed with the command, and we'll store it in file.
#bot.command(name='register')
async def FuncRegister (ctx) :
with tables.open_file("UsersTable.h5", mode="a") as h5file :
tableUser = h5file.root.Users.Users
particle = tableUser.row
particle['user_name'] = str(ctx.author)
particle['user_id'] = ctx.author.id
particle.append()
tableUser.flush()
The last two lines are sending the particle, that is the active row, so that is an object CUsers, into the file.
An issue I got here is that special characters in a nickname can make the code bug. It's true for "é", "ü", etc, but also cyrillic characters. What I did to counter is to encode the user name into bytes, you can do it by :
particle['user_name'] = str(ctx.author).encode()
reading file
It is where it starts to be interesting. The HFS5 file allows you to use kind of sql statements. Something you have to take in mind is that strings in the file are UTF-8 encoded, so when you extract them, you have to call for .decode(utf-8). Let's now code a function where a user can remove its entry, based on its id :
#bot.command(name="remove")
async def FuncRemove(ctx) :
with tables.open_file("UsersTable.h5", mode="a") as h5file :
tableUser = h5file.root.Users.Users
positions = tableUser.get_where_list("(user_id == '%d')" % ctx.author.id)
nameuser = tableUser[positions[0]]['user_name'].decode('utf-8')
tableUser.remove_row(positions[0])
.get_where_list() returns a list of positions in the file, that I later address to find the right position in the table.
bot.fetch_user(id)
If possible, prefer saving ID over name, as it complicates the code with encode() and decode(), and that bots have access to a wonderful function that is fetch_user(). Let's code a last function that will get you the last entry in your table, and with the id, print the username with the fetch method :
#bot.command(name="last")
async def FuncLast(ctx) :
with tables.open_file("UsersTable.h5", mode="r") as h5file :
tableUser = h5file.root.Users.Users
lastUserIndex = len(tableUser) - 1
iduser = tableUser[lastUserIndex]['user_id']
member = await bot.fetch_user(iduser)
await ctx.send(member.display_name)
For further documentation, check the manual of discord.py, this link to context in particular.
Per the API documentation, manipulating the vales of "start" and "end" will result in different data sets being returned. Strangely, changing the values of start and end resulted in the same result being returned. What am I missing? Thanks!
qopts = {'query': '/automotive and vehicles',
'aggregation' : '[term(yyymmdd).term(docSentiment.type,count:3)]',
'return': 'docSentiment.type,yyyymmdd',
'count': '50',
'start': 'now-2w',
'end' : 'now-1w',
'offset': my_offset}
my_query = discovery.query(my_disc_environment_id, my_disc_collection_id, qopts)
I hope it is helpful for you.
I am not sure if this is right answer for you because I have limited information.
First of all, please check the number of return-sets. if the return-set has more then 50 dataset, result could be same. (might count param. -1 = unlimited in the rest API of WCA (Watson Context Analytics)
Second, if you can check the log from the server side, you can see the full query which manipulated from WATSON engine.
Last, I am not really sure that watson REST-API can recognize 'now-2w' style start-end form. Would you please link the tutorial? In my previous project, I wrote the start-end date by Y-M-D form.
Good Luck
I have the following objects: L1User, L2User, L3User (all inherits from User) and Document.
Every user can create the document but depending on the user type, the document will have a different status. So in case it's L1User, the document will be created with L1 status and so on:
Solution 1
Please note that after document is created, it will be saved in the database, so it should be natural to have a method create_document(User user) in Document object. In the method body I could check which type is the user and set manually appropriate status. Such approach seems rather not OOP to me.
Solution 2
Ok, so the next approach would be to have all users implement a common method (say create_document(Document doc)) which will set a status associated with the user and save the document in the database. My doubt here is that the document should be saved in it's own class, not the user.
Solution 3
So the final approach would similar to the above, except that the user will return modified document object to it's create_document(User user) method and save will be performed there. The definition of the method would be like this:
create_document(User user)
{
this = user.create_document(this);
this->save();
}
It also doesn't seems right to me...
Can anyone suggest a better approach?
I think that both Solutions 2 and 3 are ok from the OO point of view, since you are properly delegating the status assignment to the user object (contrary to solution 1, whare you are basically doing a switch based on the user type). Whether to choose 2 or 3 is more a matter of personal tastes.
However, I have a doubt: why do you pass a document to a create_document() method? I would go for a message name that best describes what it does. For example, in solution 3 (the one I like the most) I would go for:
Document>>create_document(User user)
{
this = user.create_document();
this->save();
}
and then
L1User>>create_document()
{
return new Document('L1');
}
or
Document>>create_document(User user)
{
this = new Document()
this = user.set_document_type(this);
this->save();
}
and then
L1User>>set_document_type(document)
{
document.setType('L1');
}
Edit: I kept thinking about this and there is actually a fourth solution. However the following approach works only if the status of a document doesn't change through its lifetime and you can map the DB field with a getter instead of a property. Since the document already knows the user and the status depends on the user, you can just delegate:
Document>>getStatus()
{
return this.user.getDocumentStatus();
}
HTH
This is ridicolously trivial but i've spent half an hour trying to solve it.
class SocialPost(model.Model):
total_comments=model.IntegerProperty(default=0)
def create_reply_comment(self,content,author):
...
logging.info(self)
self.total_comments=self.total_comments+1
self.put()
In the logfile, i can see how total_comments is 0 but in the admin console, it is 1. The other fields are correct, except for this one.
Probably there's something wrong in that "default=0" but i can't find what is wrong.
Edit: full code of my function
def create_reply_comment(self,content,author):
floodControl=memcache.get("FloodControl-"+str(author.key))
if floodControl:
raise base.FloodControlException
new_comment= SocialComment(parent=self.key)
new_comment.author=author.key
new_comment.content=content
new_comment.put()
logging.info(self)
self.latest_comment_date=new_comment.creation_date
self.latest_comment=new_comment.key
self.total_comments=self.total_comments+1
self.put()
memcache.add("FloodControl-"+str(author.key), datetime.now(),time=SOCIAL_FLOOD_TIME)
Where i call the function:
if cmd == "create_reply_post":
post=memcache.get("SocialPost-"+str(self.request.get('post')))
if post is None:
post=model.Key(urlsafe=self.request.get('post')).get()
memcache.add("SocialPost-"+str(self.request.get('post')),post)
node=node.get()
if not node.get_subscription(user).can_reply:
self.success()
return
post.create_reply_comment(feedparser._sanitizeHTML(self.request.get("content"),"UTF-8"),user)
You're calling memcache.add before you make your change to total_comments, so when you read it back from memcache on subsequent calls, you're getting an out-of-date value from the cache. Your create_reply_comment needs to either delete or overwrite the "SocialPost-"+str(self.request.get('post') cache key.
[edit] Though your post title says you're using NDB (model.Model though? Hmm.), so you could just skip the memcache bits entirely, and let NDB do it's thing?
On this question I solved the problem of querying Google Datastore to retrieve stuff by user (com.google.appengine.api.users.User) like this:
User user = userService.getCurrentUser();
String select_query = "select from " + Greeting.class.getName();
Query query = pm.newQuery(select_query);
query.setFilter("author == paramAuthor");
query.declareParameters("java.lang.String paramAuthor");
greetings = (List<Greeting>) query.execute(user);
The above works fine - but after a bit of messing around I realized this syntax in not very practical as the need to build more complicated queries arises - so I decided to manually build my filters and now I got for example something like the following (where the filter is usually passed in as a string variable but now is built inline for simplicity):
User user = userService.getCurrentUser();
String select_query = "select from " + Greeting.class.getName();
Query query = pm.newQuery(select_query);
query.setFilter("author == '"+ user.getEmail() +"'");
greetings = (List<Greeting>) query.execute();
Obviously this won't work even if this syntax with field = 'value' is supported by JDOQL and it works fine on other fields (String types and Enums). The other strange thing is that looking at the Data viewer in the app-engine dashboard the 'author' field is stored as type User but the value is 'user#gmail.com', and then again when I set it up as parameter (the case above that works fine) I am declaring the parameter as a String then passing down an instance of User (user) which gets serialized with a simple toString() (I guess).
Anyone any idea?
Using string substitution in query languages is always a bad idea. It's far too easy for a user to break out and mess with your environment, and it introduces a whole collection of encoding issues, etc.
What was wrong with your earlier parameter substitution approach? As far as I'm aware, it supports everything, and it sidesteps any parsing issues. As far as the problem with knowing how many arguments to pass goes, you can use Query.executeWithMap or Query.executeWithArray to execute a query with an unknown number of arguments.