Web2Py getting/posting values - python

I'm fairly new to Web2Py and i'm hoping for some help.
I have a reviews DB and a games DB.
At the moment the user can click on a game from a list and they are taken to a page allowing them to leave a review.
I can save the review into the DB but I can't get it to reference the corresponding game.
DB:
db.define_table('games',
Field('title',requires=IS_NOT_EMPTY()),
Field('description','text',requires=IS_NOT_EMPTY()))
db.define_table('reviews',
Field('title',requires=IS_NOT_EMPTY()),
Field('review','text',requires=IS_NOT_EMPTY()))
Default.py:
def review():
getTitle = db.games(request.args(0)) or redirect(URL('default', 'index'))
formReview = SQLFORM(db.reviews,fields = ['title','review']).process()
if formReview.accepted: redirect(URL('index'))
return dict(formReview=formReview, getTitle=getTitle)
Review.html:
{{extend 'layout.html'}}
<h2>Review a game</h2>
<h2>{{=getTitle.title}}</h2>
{{=formReview}}
I'm guessing I need to create a field in 'reviews' that will get the 'request.args' value. But i'm not sure?

You should first expand your review table to hold a foreign key to the games table like this:
db.define_table('reviews',
Field('title',requires=IS_NOT_EMPTY()),
Field('review','text',requires=IS_NOT_EMPTY()),
Field('game_id', 'reference games'))
So you have a reference for which game the review is. With this aditional information you should be able to select all reviews for a game and render them in the view.
for row in db(db.reviews.game_id == 1).select():
print row.title # just an example
And of course you also need to save the corresponding game_id when creating a new review entry ;)
formReview = SQLFORM(db.reviews,fields = ['game_id', 'title','review']).process()

Related

How can I show randomly different data for each user in Django?

I have a tag system in Django with the following model;
class Data(models.Model):
new = models.ChardField()
is_tagged = models.BooleanField(default=False)
class Tag(models.Model):
data = models.ForeignKey(Data,on_delete=models.CASCADE,related_name="data")
status = models.CharField(verbose_name="New Status",max_length=10,null=True)
The tag status holds "positive", "negative", and "pass".
There is a page called "new tags" and around 100 users will enter the page at the same time.
There are 10000 data and users will enter the page and just click "positive", "negative", and "pass".
I want to show different data for each user.
EDIT
New1: id = 1,is_tagged=False
New2: id = 2,is_tagged=False
User 1: Display New1
User 2: Display New1
User 1: Tag: "Positive" and id = 1, is_tagged will be "True"
Because both user open the windows at the same time, after 1 second,
User 2: Tag: "Pass" and id = 1 , is_tagged will be "False"
I want to prevent this situation. It supposed to be;
User 1: Display New1
User 2: Display New2
So each user must display different News Data to tag.
Let's say a user tagged the new as "positive". If I will send the new with random() it can be the same at another user unluckily. And the user can tag as "pass". This status will make "Data" "is_tagged" False. But other users tagged "positive" before.
How can I prevent users see the same data at the same time?
If you need to get a random object, you could do something like:
import random
all_object_ids = Data.objects.all().values_list('id', flat=True) # gets list of all object ids
random_id = random.choice(all_object_ids) # picks a random id from list
random_tag = Data.objects.get(id=random_id)

how to update old records with computed field with store = True

I want to update the "on_hand_qty" field of existing record
_inherit="product.product"
on_hand_qty=fields.Float('onhand', compute='copy_quant' ,store=True)
#api.constrains('qty_available')
def copy_quant(self):
for rec in self:
rec.on_hand_qty = rec.qty_available
I want this field with store =True
but this field is not updated in old records with store= True. please suggest how to achieve this.
user10810227
Make the related field of qty_available
on_hand_qty=fields.Float(related='qty_available', string="Your Field")

Two forms of same class on one page in flask-wtforms

In my website, I have a model Experiment that contains many Activities. I have a view where people can add or remove Activities from an Experiment.
I show a table with Activities that are a part of this Experiment, and a table of Activities not a part of this Experiment. Users can check which Activities they want to add or remove and use a submit button under the table.
However, when I update the list of choices on one form, the list of choices on the other form reflects this. Am I doing something wrong?
For both adding and removing the Activities to/from the Experiment, I use the same form.
class MultiCheckboxField(SelectMultipleField):
widget = ListWidget(prefix_label=False)
option_widget = CheckboxInput()
class ActivityListForm(Form):
activities = MultiCheckboxField(validators=[DataRequired()], choices=[])
submit = SubmitField("Submit")
def populate_activities(self, activities_set):
activities_mapping = {}
for activity in activities_set:
activities_mapping[str(activity.id)] = activity
choice_tuple = (str(activity.id), activity.question)
self.activities.choices.append(choice_tuple)
return activities_mapping
Here is my view:
def settings_experiment(exp_id):
experiment = Experiment.query.get(exp_id)
remove_activities_form = ActivityListForm(prefix="remove")
add_activities_form = ActivityListForm(prefix="add")
remove_activities_mapping = remove_activities_form.populate_activities(
experiment.activities)
add_activities_mapping = add_activities_form.populate_activities(
Activity.query.\
filter(not_(Activity.experiments.any(id=experiment.id))).all())
return render_template("experiments/settings_experiment.html",
experiment=experiment,
update_experiment_form=update_experiment_form,
remove_activities_form=remove_activities_form,
add_activities_form=add_activities_form,
add_activities_mapping=add_activities_mapping,
remove_activities_mapping=remove_activities_mapping)
Although remove_activities_form and add_activities_form have their options set separately to different lists, they both end up containing a union of their two option lists, which messes up my template rendering. Is there a way to keep them separate or am I screwed?
https://github.com/wtforms/wtforms/issues/284
Solution in the above discussion.

Sqlalchemy not committing object changes to postgres DB

I am using the following passage of code:
#app.route('/budget_item/<int:budget_id>/edit', methods=['GET', 'POST'])
def budget_item_edit(budget_id):
budget_item = session.query(Budget).filter_by(id=budget_id).one()
print "Start EDIT sequence"
# Return form data from HTML initial load form
elif request.method == 'POST':
budget_amount_reallocated_total = budget_item.budget_amount_reallocated_total
#ORIGINAL BUDGET
if request.form['transaction_type'] == 'Original Budget':
#amount
if request.form['amount'] == "":
amount = 0
else:
amount = float(str(request.form['amount']))
budget_item = Budget(
#created_date = "",
budget_transaction_type = request.form['transaction_type'],
budget_line = request.form['budget_line'],
amount = amount,
description = request.form['description']
#date_received = request.form['date_received']
)
try:
count = 1
while count < 10000:
count += 1
#budget_line
setattr(budget_item,'budget_line'+str(count),request.form['budget_line'+str(count)])
#amount
setattr(budget_item,'amount'+str(count),float(request.form['amount'+str(count)]))
budget_amount_reallocated_total += float(request.form['amount'+str(count)])
setattr(budget_item, 'budget_amount_reallocated_total', budget_amount_reallocated_total)
#description
setattr(budget_item,'description'+str(count), request.form['description'+str(count)])
#date_received
setattr(budget_item,'date_received'+str(count),request.form['date_received'+str(count)])
session.commit()
except:
session.commit()
return redirect(url_for('budget_master'))
else:
print "I'm done! This is not a post request"
This block of code is setup to pass data from an HTML via a POST request an then update a corresponding object in the Postgres DB. I can confirm that the object queried from the DB "budget_item" is being updated by settattr. At the end of the passage, I use commit() to update the object; however, the database doesn't reflect the changes. Just to test to make sure things are flowing, I've tried session.add(budget_item) followed by session.commit() to make sure the connect to the DB is OK. That works. How do i update this budget_item object into the database? Any help is much appreciated.
i think that a simple
budget_item.budget_amount_reallocated_total = budget_amount_reallocated_total
session.add(budget_item)
session.commit()
is the right way to do it
To answer your question, to update the budget_item that already exists in the database you need to update the Budget instance that you retrieved from the database, i.e.
budget_item = session.query(Budget).filter_by(id=budget_id).one()
not the one that you have newly created with:
budget_item = Budget(...)
Here the first budget_item represents the row in the database, so this is the one to update. To that end you can replace the code that creates the second Budget instance with this:
budget_item.budget_transaction_type = request.form['transaction_type']
budget_item.budget_line = request.form['budget_line']
budget_item.amount = amount
budget_item.description = request.form['description']
Once you have finished updating the Budget instance you can call session.commit() to flush it to the database.
As mentioned in my comment to your question, it appears that you are trying to add a large number of additional attributes to budget_item all of which will be ignored by sqlalchemy unless they are defined in the mapping between the Budget instance and the Budget table.

How to update object with another object in get_or_create?

I have to tables wit similar fields and I want to copy objects from one table to another.
Problem that object could be absent in second table, so I have to use get_or_create() method:
#these are new products, they all are instances of NewProduct model, which is similar
#to Product model
new_products_list = [<NewProduct: EEEF0AP>, <NewProduct: XR3D-F>,<Product: XXID-F>]
#loop over them and check if they are already in database
for product in new_products_list:
product, created = Products.objects.get_or_create(article=product.article)
if created:
#here is no problem because new object saved
pass
else:
# here I need to code that will update existing Product instance
# with values from NewProduct instance fields
The case is that I don't want to list all fields for update manually, like this,, because I have about 30 of them:
update_old_product = Product(name=new_product.name,article= new_product.article)
Please advise more elegant way than above
You can loop over the field names and update them in the the other Product instance:
for new_product in new_products_list:
# use different variable names, otherwise you won't be able to access
# the item from new_product_list here
product, created = Products.objects.get_or_create(article=new_product.article)
if not created:
for field in new_product._meta.get_all_field_names():
setattr(product, field, getattr(new_product, field))
product.save()
You could try something like this.
def copy_fields(frm, to):
id = to.id
for field in frm.__class__._meta.fields:
setattr(to, field.verbose_name, field._get_val_from_obj(frm))
to.id = id
This is similar to Ashwini Chaudhary, although I think it will take care of that error that you mentioned in the comments.
new_products_list= (
# obj1, obj2, obj3 would be from [<NewProduct: EEEF0AP>, <NewProduct: XR3D-F>,<Product: XXID-F>] in your question
# NewProduct would just be the model that you import
# NewProduct._meta.fields would be all the fields
(obj1, NewProduct, NewProduct._meta.fields,),
(obj2, NewProduct, NewProduct._meta.fields,),
(obj3, NewProduct, NewProduct._meta.fields,),
)
for instance, model, fields in new_products_list:
new_fields = {}
obj, created = model.objects.get_or_create(pk=instance.article) # this is pretty much just here to ensure that it is created for filter later
for field in fields:
if field != model._meta.pk: # do not want to update the pk
new_fields[field.name] = request.POST[field.name]
model.objects.filter(pk=question_id).update(**new_fields) # you won't have to worry about updating multiple models in the db because there can only be one instance with this pk
I know this was over a month ago, but I figured I would share my solution even if you have already figured it out

Categories