delete a particular row in datastore GAE - python

I am trying to delete a particular row in the datastore google app engine. The list of entries are displayed in the web page and the user clicks a button to delete a particular entry, this should reflect the datastore. From the jinja template i'm passing the ID of the entry when the delete-button is clicked by user. The below python code should handle the delete action in the datastore.
def post(self,id):
q = db.GqlQuery('SELECT * FROM Input WHERE ID=:1', id)
for msg in q:
db.delete(msg) # msg.delete() #I tried these both stil not working
It is not showing any error message to me and shows HTTP 200 message. But when I check the datastore the enrty isn't deleted :(
Please help me to fix this.

I'm guessing that one of two things are happening: One is that id isn't what you expect, and the query isn't returning entities (some logging will suss that out). The other is that you're seeing the effects of "eventual consistency", which is described in some detail here. A test for that is whether you still see entity that after some time has elapsed. The fix for the second problem is to deleted entities from within a transaction.

Related

Scraping ASPX after login with Python but every login gives you a different URL

I'm trying to get the exam result data from my college website for every Roll No. in my class.
Normally you can POST url (www.example.com/login.aspx)with login information, and GET a fixed url after login(www.example.com/home.aspx).
But the page I'm trying to get has a different URL for every Roll no. entered. The URL of login page look like this: "www.example.com/View.aspx". After login, the URL of the result page looks like: "www.example.com/ovengine.aspx?enc=BunchOfNumbersandAlphabets". And those numbers and alphabets are different for each roll number.
So I can't put a URL in my code to get the final result. I don't know how to get the page that comes automatically after the login, without mentioning it's URL.
But the page I'm trying to get has a different URL for every Roll no. entered
No, it is the same URL, and the URL has a parameter. You see this in URL's all the time.
So, for a temperature site it might look like
www.TheWeatherSite.com/?City=Rome
So, the above URL is always the same, but the web site "city" parameter is for the City of Rome. The web code behind can thus use/get/grab/consume that parameter in the code behind. That way we don't create a web page for EACH weather for each city.
so you create ONE page, and then and then PASS the web page a city value that the code behind can consume and use. (say query temperature data from a database for city = above value).
And thus you have to know ahead of time what city you want the weather for. Of course this approach is great since you don't have to create a new web site page to just show/display the weather in a given city.
You are in effect passing a value to some code behind that will run, and use that passed value.
The same goes for your example URL. You note there is ONE parameter called "enc".
So, the web site code behind would:
Grab, get, set the users ID. However, the users ID would be from the security system and the authentication provider. Unless you logged in as that particular user, then you not get that user id.
So, both a user ID (limited to the internal code).
And the "enc" value as the parameter in the URL you have would be required.
So, note in the above sql, we VERY likely need both a studentID and ALSO the "enc" value that some OTHER code from another page gets/grabs from the database.
Now that funny "GUID" (please do google what a GUID is), from a programmers point of view WOULD be sufficient to pull this one row of data from the database, but by ALSO using in the query the users logged on internal id?
Well, then only a given logged on user would be able to see their own set of values that belong to them.
In other words?
Only a drunken un-employed Rodeo clown would JUST require that GUID for pulling out that data. Since if that was the case, then any user could type in that GUID and see others peoples marks. However, there is "some" security by using a GUID, since a user could never guess that value.
If they used "city" like my first URL and parameter example? Then yes, you could guess and know the city value to type in. Or they could have used say student name, or even student number - those you COULD guess with relative ease.
But, for such data, no doubt the user adopted something MUCH more difficult then a starting number like a row number or PK id from a database. So, when the code added the results to that table? They also added a GUID of some type and saved that as a row in the database also.
So you NOT only need JUST the GUID, but that URL will ONLY work for a given pair of values. (the student ID - which is ONLY internal to the code and pulled FROM the authenticated provider. That was this line of code:
= Membership.GetUser.ProviderUserKey
So that above value is going to be the users logon internal ID.
The enc (external) exposed value in the web URL as a parameter, and ALSO the internal logged on value. So the code behind (asp.net) would look something like this:
Dim strSQL As String
strSQL = "SELECT * from tblStudentMarks where StudentID = #pID " &
" AND TestResultsGID = #GID"
Dim cmdSQL As New SqlCommand(strSQL, GetCon)
cmdSQL.Parameters.Add("#pID", SqlDbType.Int).Value = Membership.GetUser.ProviderUserKey
cmdSQL.Parameters.Add("#GID", SqlDbType.VarChar).Value = Request.QueryString("enc")
Dim dReader As New SqlDataAdapter(cmdSQL)
Dim rstData As DataTable
dReader.Fill(rstData)
Note the code:
Request.QueryString("enc")
That allows the code behind to get/grab the parameter (enc) from the URL. But, as I stated, it is high unlikely that JUST the "enc" number is required here. It is possible that ONLY this value is required to pull the data from the row, but then that would be a security hole the size of a open barn door.
Think of your on-line banking.
www.mybank.com/?CustomerNumber=1234
Well, if we JUST use the above CustomerNumber as the means to pull bank data, then I could go to the site and type in YOUR number, or someone's else's number.
So, for this to work?
You will need to obtain a list of enc values (that messy funny long string). Without that parameter then you not be able to set the parameter in the URL.
However, as I stated, you ALSO very likely need some internal "user" logon id that is NOT included in the public exposed URL to ALSO grab that one row of data from the database.
And, even more important? Such web pages usually cannot be hit UNLESS you are a logged in as an authenticated user. In other words that web page will ONLY be dished out to logged in users - if you not logged in, then the server security will automatic NOT dish out the web page unless you are logged in user.
So, for this to work, you need to contact the web site developers, and obtain that list of "enc" values. Once you have that list, then you can generate some code to process that list and insert the correct parameter in the URL. However, you also need to ask if that URL and parameter value will work for JUST you the logged in user, or if that this URL and parameter ONLY works for a give logged in user. Without these values, and without knowing if the URL and parameter will work for any user? (which I doubt it would), then just using a URL to get these values will not work.
It would be even BETTER to have the web site folks create a web service that you can call and in one command it would return all of the data you need anyway, as opposed to over and over having to send the "enc" value, which you don't have anyway.

Not able to retrieve data from firebase in django

I've been trying to get data from Firebase into my Django app the issue i face is that some of the documents are retrieved and some aren't. A really weird thing I noticed is when on the admin page the documents that can be accessed are highlighted in a darker shade than the ones that we aren't able to get from the database.
The highlighted issue is shown in the image above. The first document is highlighted but the second isn't and the first is read by the django function below
def home(request, user=""):
db = firestore.client()
docs = db.collection(u'FIR_NCR').stream()
for doc in docs:
print(doc.id,end="->")
s = db.collection(u'FIR_NCR').document(u'{}'.format(doc.id)).collection(u'all_data').get()
print(s[0].id,end="->")
print(s[0].to_dict())
return render(request, "home.html", {"user":user})
In this docs is not able to get the complete list of the documents necessary and hence the issue.
It would be wonderful if someone could help me understand what I'm doing wrong. T.I.A.
The document ID isn't actually highlighted. The difference between the first and the second ID is that the second one is in italics. That means there is no actual document with that ID. The reason why the Firestore console shows you a document ID at all for a missing document is because it has a nested subcollection. You can click into that missing document, then again click into the subcollection.
In Firestore, you can have subcollections nested under documents that don't exist. This is OK. Just be aware that these missing documents can't be discovered by a normal query in the collection where you see them in the console.

Redirect loading old content?

a little bit of a weird issue. To simplify the problem for explanation purposes. A user goes onto /Total page and gets the count of the records in the datastore with "steve" as the name, at the moment there is 2, he can then presses increment and the user gets redirected to /Increment so another record is added into the nbd, the user is then once again redirected to /Total however it still shows 2! If he simply refreshes the page, it then shows 3. I assume it's because the redirect back to /Total happens before the entity is fully committed into the datastore? If not, here's the code, please let me know what's wrong. Thank you!
PYTHON:
#app.route("/Total", methods=['GET', 'POST'])
def total():
data = Logins.query(Logins.name == "steve").count()
return render_template('Total.html', count=count)
#app.route("/Increment", methods=['GET', 'POST'])
def incre():
new_data = oAuthLogins()
new_data.name = "steve"
new_data.put()
return redirect(url_for('total'))
Total.html:
{{count}}
<a href={{url_for('incre')}}> Increment! </a>
This can happen for a bunch of reasons: slow db update (eventually consistent), caching, etc.
But, is this a good user experience?
If a user sees a number (2) then presses increment, but that record has changed, is it better to show the user the number they expect (3), or the actual number (which may be much higher than 3 by the time they click increment)?
For UX, I would think the user should see the number 3. He/she can always see the latest number with another refresh.
With that in mind, you solve this by changing the /increment call to be done via AJAX and simply increment the number on the front end when you get a 200 response.
You're obtaining the count from a (Logins kind) query which is always eventually consistent unless it's an ancestor query.
You could display the correct count if you transform the method of getting it into a strongly consistent one, for example by storing it in a property of the user entity which you can always obtain by key lookup (or some other equivalent entity kind always in a 1-to-1 relationship with the user entity, see re-using an entity's ID for other entities of different kinds - sane idea?)
I have tried to replicate the issue and it worked for me. I am not sure if this is what you are looking for but here is my example code in GitHub.
When running the code follow these steps:
Navigating to localhost:8080 will print Hello World
Navigate to localhost:8080/add for the first time to enter the first value in entity. (Will add number 2)
Go to the Entities in the GCP page and get the id from the record
Replace that id with the one in the code ENTITY_KEY
Navigate to localhost:8080/get will print the number saved in the entity
Navigate to localhost:8080/update will get that number, add 1 to that number and will save the number again.
After that it will automatically redirect to localhost:8080/get and will show you the updated value in the entity

Django: How to save a record in a new table before saving (user udates) the original

Scenario:
Developing a question answer app.
Here are different users can answer the questions.
Each question may have several fields to response (2 or 3 yes/No checkboxes) and any user can update any of those any time.
Problem:
I need to keep a log (with time and user name) in a different log table every time the records got any changes.
The log table is just a look alike of the original model (e.g. ChangeLogModel) just with 2 extra fields as logDate and ChangingUser.
This will help me to check the log and find the status of the question in any specific date.
Possible Solutions:
Using signals (...Not used to with signals, lack of detailed tutorials, documentation is not detailed too)
making the backup before doing any ".save()" (... Have o idea how to do that)
Install any external app (...Trying to avoid installing any app)
Summary:
Basically What I am asking for is a log table where the 'state' of the original record/row/tuple would be saved to another table (i.e. logTable) prior to hit the "form.save()" trigger.
So, every time the record got updated so the LogTable will get a new row with a datestamp.
You could use an django package for audit and history, any of those in this overview for example.
I had success using django-simple-history.
I think that the best way is just to do it straight forward. You can save the user's answer and right after that the log, wrap it with database transaction and rollback if something goes wrong.
Btw if the logs table has the same fields like the original model you might consider using foreign key or inheritance, depends on your program logic.

What does a GQL Query Return

I have been working on a project using Google App Engine. I have been setting up users and have to check if a username is taken yet.
I used the following code to try to test whether it is taken or not
usernames = db.GqlQuery('select username from User')
taken = username in usernames
This never caught duplicate usernames. I tried a few variants of this on the GQL query line. I tried using .get() which caused an error because it returned something that wasn't iterable. I also tried putting list() around the request, which returned the same error. I tried writing the value of usernames but never got any response. If it returns a query instance, then is there any way to turn it into a list or tuple?
For starters you should revisit the docs https://cloud.google.com/appengine/docs/python/datastore/gqlqueryclass?hl=en
db.GqlQuery('select username from User') is calling a constructor not a function so it returns an instance of a GqlQuery object. See docs referred to above.
Secondly what you are doing will never work reliably due to eventual consistancy . Please read https://cloud.google.com/appengine/docs/python/datastore/structuring_for_strong_consistency to understand why.
Lastly you are starting out with appengine, so move away from db and use ndb unless you have a significant existing code base.

Categories