Saving data in a promotion / formotion form - rubymotion

I have a form that displays, and when i click the submit button it logs the values to the console.
How can i persist the settings so i can access them elsewhere in the application and the form is prepopulated when i return to the form screen?
I have my form set up like this
class ChimeScreen < FormotionScreen
title "Chime"
def on_submit(_form)
data = _form.render
# settings.enable = data[:enable]
# settings.alarm_time = data[:alarm_time]
PM.logger.debug data[:alarm_time]
open BrowseScreen
end
def table_data
{
...
}
end

Formotion allows persistent data by setting the persist_as value on the form.
See example here: https://github.com/clayallsopp/formotion/tree/master/examples/Persistence
You can then retrieve this form data as a hash by looking into
App::Persistence["FORMOTION_#{your_symbol_persisting_as_here}"]

OK, i think i was expecting something magical to set up there, when actually it's just straight forward value setting.
def on_submit(_form)
data = _form.render
#defaults = NSUserDefaults.standardUserDefaults
unless data.nil?
#defaults["alarm_time"] = data[:alarm_time]
#defaults["alarm_enabled"] = data[:alarm_enabled]
end
open BrowseScreen
end
and then set the value for each form field...
def table_data
#defaults = NSUserDefaults.standardUserDefaults
{
sections: [{
title: "Set Daily Reminder",
rows: [{
title: "Enable",
key: :alarm_enabled,
type: :switch,
value: #defaults["alarm_enabled"]
},
...etc

Related

Problem in Setting backend data into dropdown using Django

I have a backend data and successfully set the data into dropdown but the thing is whenever click on button then it will give me the desire result but the thing is after getting the result, the drop down is like having null values in it so what can i do.
could someone suggest me whenever i click on dropdown then it will get refress or other methods are appreciable.
Thanks!
views.py
def index(request):
sparqlQueries = get_data()
if(request.POST['Case_name'] and request.method =='POST'):
name_cases = sparqlQueries.nameOfCases()
data = {
"cases_name":name_cases,
'flag2':True,
'suffix':'Cases',
'title':'Name of Cases'
}
return render(request,'index.html',context = data)
if(request.method =='POST'):
casename = request.POST['Case_name']
question = request.POST['Question']
#print(casename)
#print(question)
if(casename == 'xyz' and question == 'pqr'):
judges = sparqlQueries.case2_judge_name()
#print(judges)
data = {
"name":judges,
'flag':True,
'suffix':'judges',
'title':'Judge of Case2'
}
return render(request,'index.html', context = data)
...
You're doing it the wrong way:
first of all you check the request method first then check if variable exists
for request.POST['Case_name'] if the Case_name does not exist will raise a key error internal server error, you don't need that for your project so use request.POST.get('Case_name', optional default value)
now for the null dropdown, it's because you didn't add the context you using in the drop down to the newly rendered template, you are not providing the full code but that's usually the reason

Can I restrict post method in flask restApi from adding another data to the database?

Given with my current data in db, I want to restrict the post method from adding another data to the database. What I want is restrict the post method in adding another data, and just update the existing data within the db.
Code:
def get(self):
predict = PredictModel.query.all()
return {'Predict': list(x.json() for x in predict)}
def post(self):
data = request.get_json()
new_predict = PredictModel(data['timelag1'],data['timelag2'],data['timelag3'],data['timelag4'],data['timelag5'])
db.session.add(new_predict)
db.session.commit()
db.session.flush()
return new_predict.json(),201
Current data in db:
"Predict": [
{
"timelag1":1,
"timelag2": 1,
"timelag3": 1,
"timelag4": 1,
"timelag5": 1
}
]
}
Data in db after a user entered another data:
"Predict": [
{
"timelag1":2,
"timelag2": 2,
"timelag3": 2,
"timelag4": 2,
"timelag5": 2
}
]
}
I recommend reading this answer concerning how to do the database manipulation (especially the later ones):
Flask-SQLalchemy update a row's information
you will need some kind of primary key or unique identifier to specify the row that you want to change - something like "id"
here's some sample code which will probably work if you adapt it to your case:
instance = User.query.filter(User.id==id)
data=instance.update(dict(json_data))
db.session.commit()
or
num_rows_updated = User.query.filter_by(username='admin').update(dict(email='my_new_email#example.com')))
db.session.commit()

How to enter a list in WTForms?

What I'm trying to do
I'm trying to enter a list of tags in flask that should become passable as a list but I can't figure out how to do it in flask, nor can I find documentation to add lists (of strings) in flask_wtf. Has anyone have experience with this?
Ideally I would like the tags to be selectively delete-able, after you entered them. So that you could enter.
The problem
Thus far my form is static. You enter stuff, hit submit, it gets processed into a .json. The tags list is the last element I can't figure out. I don't even know if flask can do this.
A little demo of how I envisioned the entry process:
How I envisioned the entry process:
The current tags are displayed and an entry field to add new ones.
[Tag1](x) | [Tag2](x)
Enter new Tag: [______] (add)
Hit (add)
[Tag1](x) | [Tag2](x)
Enter new Tag: [Tag3__] (add)
New Tag is added
[Tag1](x) | [Tag2](x) | [Tag3](x)
Enter new Tag: [______]
How I envisioned the deletion process:
Hitting the (x) on the side of the tag should kill it.
[Tag1](x) | [Tag2](x) | [Tag3](x)
Hit (x) on Tag2. Result:
[Tag1](x) | [Tag3](x)
The deletion is kind of icing on the cake and could probably be done, once I have a list I can edit, but getting there seems quite hard.
I'm at a loss here.
I basically want to know if it's possible to enter lists in general, since there does not seem to be documentation on the topic.
Your description is not really clear (is Tag1 the key in the JSON or is it Tag the key, and 1 the index?)
But I had a similar issue recently, where I wanted to submit a basic list in JSON and let WTForms handle it properly.
For instance, this:
{
"name": "John",
"tags": ["code", "python", "flask", "wtforms"]
}
So, I had to rewrite the way FieldList works because WTForms, for some reason, wants a list as "tags-1=XXX,tags-2=xxx".
from wtforms import FieldList
class JSONFieldList(FieldList):
def process(self, formdata, data=None):
self.entries = []
if data is None or not data:
try:
data = self.default()
except TypeError:
data = self.default
self.object_data = data
if formdata:
for (index, obj_data) in enumerate(formdata.getlist(self.name)):
self._add_entry(formdata, obj_data, index=index)
else:
for obj_data in data:
self._add_entry(formdata, obj_data)
while len(self.entries) < self.min_entries:
self._add_entry(formdata)
def _add_entry(self, formdata=None, data=None, index=None):
assert not self.max_entries or len(self.entries) < self.max_entries, \
'You cannot have more than max_entries entries in this FieldList'
if index is None:
index = self.last_index + 1
self.last_index = index
name = '%s-%d' % (self.short_name, index)
id = '%s-%d' % (self.id, index)
field = self.unbound_field.bind(form=None, name=name, id=id, prefix=self._prefix, _meta=self.meta,
translations=self._translations)
field.process(formdata, data)
self.entries.append(field)
return field
On Flask's end to handle the form:
from flask import request
from werkzeug.datastructures import ImmutableMultiDict
#app.route('/add', methods=['POST'])
def add():
form = MyForm(ImmutableMultiDict(request.get_json())
# process the form, form.tags.data is a list
And the form (notice the use of JSONFieldList):
class MonitorForm(BaseForm):
name = StringField(validators=[validators.DataRequired(), validators.Length(min=3, max=5)], filters=[lambda x: x or None])
tags = JSONFieldList(StringField(validators=[validators.DataRequired(), validators.Length(min=1, max=250)], filters=[lambda x: x or None]), validators=[Optional()])
I found a viable solution in this 2015 book, where a tagging system is being build for flask as part of a blog building exercise.
It's based on Flask_SQLAlchemy.
Entering lists therefore is possible with WTForms / Flask by submitting the items to the database via, e.g. FieldList and in the usecase of a tagging system, reading them from the database back to render them in the UI.
If however you don't want to deal with O'Rielly's paywall (I'm sorry, I can't post copyrighted material here) and all you want is a solution to add tags, check out taggle.js by Sean Coker. It's not flask, but javascript, but it does the job.

The default ActiveAdmin filter doesn't filter my index table

I have an application where you can fill in metadata of documents. I currently have a problem with the default filtering as it doesn't filter my index table. The filter options are shown on the right side and you can also see the filtering options in the url and params after you choose a filter and hit the button.
utf8=✓&q%5Buser_id_eq%5D=3&commit=Filter&order=id_desc
But somehow the index table doesn't refresh.
The only scope I have is the default:
scope :all, default: true
EDIT
I think it has something to do with the pagination because If i remove pagination the filters work again.
This is my current index method in my app/admin/DocumentType.rb file:
def index
index! do |format|
#document_types = DocumentType.where(archived_at: nil).page(params[:page])
file_name = "document_types_#{DateTime.now.strftime('%a_%d_%b_%Y_%H%M%S').downcase}"
format.xls {
spreadsheet = DocumentTypesSpreadsheet.new #document_types
send_data spreadsheet.generate_xls, filename: file_name + ".xls"
}
end
end
Only document types which are not archived should be displayed in the index therefore i have
#document_types = DocumentType.where(archived_at: nil).page(params[:page])
Now with this my filter don't work. But if I remove this line completely they work again except now it displays also the archived document types. And if I remove the .page(params[:page]) part I get the following error message:
Collection is not a paginated scope. Set collection.page(params[:page]).per(10) before calling :paginated_collection.
Try to update your controller with this
def index
index! do |format|
#document_types = DocumentType.where(archived_at: nil).ransack(params[:q]).result
file_name = "document_types_#{DateTime.now.strftime('%a_%d_%b_%Y_%H%M%S').downcase}"
format.xls {
spreadsheet = DocumentTypesSpreadsheet.new #document_types
send_data spreadsheet.generate_xls, filename: file_name + ".xls"
}
end
end
But you need to be sure, you deisplay the records with this condition as well:
.where(archived_at: nil)
because the exported result will be different with displayed

How to extract multiple rows of data relative to single row in scrapy

I am trying to scrape webpage given in the this link -
http://new-york.eat24hours.com/picasso-pizza/19053
Here I am trying to get all the possible details like address and phone etc..
So, Far I have extracted the name, phone, address, reviews, rating.
But I also want to extract the the full menu of restaurant here(name of item with price).
So, far I have no idea how to manage this data into output of csv.
The rest of the data for a single url will be single but the items in menu will always be of different amount.
here below is my code so far-
import scrapy
from urls import start_urls
class eat24Spider(scrapy.Spider):
AUTOTHROTTLE_ENABLED = True
name = 'eat24'
def start_requests(self):
for x in start_urls:
yield scrapy.Request(x, self.parse)
def parse(self, response):
brickset = response
NAME_SELECTOR = 'normalize-space(.//h1[#id="restaurant_name"]/a/text())'
ADDRESS_SELECTION = 'normalize-space(.//span[#itemprop="streetAddress"]/text())'
LOCALITY = 'normalize-space(.//span[#itemprop="addressLocality"]/text())'
REGION = 'normalize-space(.//span[#itemprop="addressRegion"]/text())'
ZIP = 'normalize-space(.//span[#itemprop="postalCode"]/text())'
PHONE_SELECTOR = 'normalize-space(.//span[#itemprop="telephone"]/text())'
RATING = './/meta[#itemprop="ratingValue"]/#content'
NO_OF_REVIEWS = './/meta[#itemprop="reviewCount"]/#content'
OPENING_HOURS = './/div[#class="hours_info"]//nobr/text()'
EMAIL_SELECTOR = './/div[#class="company-info__block"]/div[#class="business-buttons"]/a[span]/#href[substring-after(.,"mailto:")]'
yield {
'name': brickset.xpath(NAME_SELECTOR).extract_first().encode('utf8'),
'pagelink': response.url,
'address' : str(brickset.xpath(ADDRESS_SELECTION).extract_first().encode('utf8')+', '+brickset.xpath(LOCALITY).extract_first().encode('utf8')+', '+brickset.xpath(REGION).extract_first().encode('utf8')+', '+brickset.xpath(ZIP).extract_first().encode('utf8')),
'phone' : str(brickset.xpath(PHONE_SELECTOR).extract_first()),
'reviews' : str(brickset.xpath(NO_OF_REVIEWS).extract_first()),
'rating' : str(brickset.xpath(RATING).extract_first()),
'opening_hours' : str(brickset.xpath(OPENING_HOURS).extract_first())
}
I am sorry if I am making this confusing but any kind of help will be appreciated.
Thank you in advance!!
If you want to extract full restaurant menu, first of all, you need to locate element who contains both name and price:
menu_items = response.xpath('//tr[#itemscope]')
After that, you can simply make for loop and iterate over restaurant items appending name and price to list:
menu = []
for item in menu_items:
menu.append({
'name': item.xpath('.//a[#class="cpa"]/text()').extract_first(),
'price': item.xpath('.//span[#itemprop="price"]/text()').extract_first()
})
Finally you can add new 'menu' key to your dict:
yield {'menu': menu}
Also, I suggest you use scrapy Items for storing scraped data:
https://doc.scrapy.org/en/latest/topics/items.html
For outputting data in csv file use scrapy Feed exports, type in console:
scrapy crawl yourspidername -o restaurants.csv