How to use behave context.table with key value table? - python

I saw that it is possible to access data from context.table from Behave when the table described in the BDD has a header. for example:
Scenario: Add new Expense
Given the user fill out the required fields
| item | name | amount |
| Wine | Julie | 30.00 |
To access this code it's simply:
for row in context.table:
context.page.fill_item(row['item'])
context.page.fill_name(row['name'])
context.page.fill_amount(row['amount'])
That works well and it's very clean, however, I have to refactor code when I have a huge amount of lines of input data. for example:
Given I am on registration page
When I fill "test#test.com" for email address
And I fill "test" for password
And I fill "Didier" for first name
And I fill "Dubois" for last name
And I fill "946132795" for phone number
And I fill "456456456" for mobile phon
And I fill "Company name" for company name
And I fill "Avenue Victor Hugo 1" for address
And I fill "97123" for postal code
And I fill "Lyon" for city
And I select "France" country
...
15 more lines for filling the form
How could I use the following table in behave:
|first name | didier |
|last name | Dubois |
|phone| 4564564564 |
So on ...
How would my step definition look like?

To use a vertical table rather than a horizontal table, you need to process each row as its own field. The table still needs a header row:
When I fill in the registration form with:
| Field | Value |
| first name | Didier |
| last name | Dubois |
| country | France |
| ... | ... |
In your step definition, loop over the table rows and call a method on your selenium page model:
for row in context.table
context.page.fill_field(row['Field'], row['Value'])
The Selenium page model method needs to do something based on the field name:
def fill_field(self, field, value)
if field == 'first name':
self.first_name.send_keys(value)
elif field == 'last name':
self.last_name.send_keys(value)
elif field == 'country':
# should be instance of SelectElement
self.country.select_by_text(value)
elif
...
else:
raise NameError(f'Field {field} is not valid')

Related

add prefix to id in template if flag is set in django

My database was something like this :
| id | customer_account | -few more fields - | is_renewed |
| 25 | asd111 | - some values - | 0 |
| 26 | asd222 | - some values - | 1 |
| 27 | asd333 | - some values - | 1 |
| 28 | asd444 | - some values - | 0 |
in my models, I have :
class Policy(models.Model):
customer_account = models.ForeignKey(CustomerAccount, on_delete=models.CASCADE)
--few more fields--
is_renewed = models.BooleanField(default = False)
def use_updated_id(self):
if self.is_renewed:
new_id = str("R") + str(self.id)
else:
new_id = self.id
return new_id
in my template, I have :
{% for policy in policy_list % }
<p> Policy Number : {{policy.id}} </p>
{% endfor %}
which gives me output as
Policy Number : 25
Policy Number : 26
Policy Number : 27
Policy Number : 28
I understand that I can define a method in model and use that instead of id as below to meet my requirement
{% for policy in policy_list % }
<p> Policy Number : {{policy.use_updated_id}} </p>
{% endfor %}
Policy Number : 25
Policy Number : R26
Policy Number : R27
Policy Number : 28
My only challenge is that if use model method as above, i will have to replace updated multiple templates.
I'm looking for a better solution where in i only have to make changes in models file instead of updating multiple templates to achieve the desired result.
So you have {{ policy.id }} in multiple templates and want to change its behavior by making changes to models.py?
AFAIK you cannot achieve that, since you haven't correctly encapsulated the display beforehand. That's a pain, but you'll have to change it everywhere, since you're accessing a particular attribute on your models. Adding your use_updated_id is a great idea, since it encapsulates the display logic in one function and, in the future, if you need to change the display all you have to do is to change your new function.
So go on, make those hundreds of file edits but be sure that now you've made a great progress and facilitated your project maintainability.

How to do not select duplicated values from db?

I have the following comment table(comment and corresponding info including photo_id)
comment_id | photo_id | ...
com_1 | pho_1 | ...
com_2 | pho_2 | ...
com_3 | pho_1 | ...
com_4 | pho_2 | ...
Frontend sends a request: "Hey, backend, give me info about first 2 items and I will display it"
Backend setup token to the third item:
comment_id | photo_id | ...
com_1 | pho_1 | ...
com_2 | pho_2 | ...
-->com_3 | pho_1 | ...
com_4 | pho_2 | ...
and select all info up to the third comment like this:
pho_1 com_1
pho_2 com_2
and then add all other comments to corresponding photo_id's and send it to front, so the final info that user will see, will be:
pho_1 com_1, com_3
pho_2 com_2, com_4
I have the following problem: if front sends another request "Hey, backend, give me info about next 2 items and I will display it". Then backend again setup token to the fifth item and send exactly the same info to front, so the user will see exactly the same info, because
1) it select
pho_1 com_3
pho_2 com_4
2) and append other comments to the photos id's, it will be:
pho_1 com_1, com_3
pho_2 com_2, com_4
How to avoid this and do not send duplicated info?
From the way i see it, you have 2 options.
You DO have a Foreign Key on the Photo id:
select * comment as c
right join (
select * from photo
limit 2 offset 0
) as p
on c.photo_id = p.photo_id
You DO NOT have a Foreign Key on the Photo id:
select * comment
where photo_id in (
select photo_id from comment
limit 2 offset 0
)
In both, you need to page from the photo_id perspective.

How to call a wizard from other wizard in Odoo8?

I have a wizard in which there is a one2many field. I made a button in each line of the one2many which calls another wizard made by me. This wizard is for modifying some values of the selected line.
My purpose is to return the first wizard, with the new changes, when you click on the Apply button of my wizard.
Example:
The first wizard has a one2many field with three records:
Product A | 1 ud | Source location X | Dest location Y | Lot A1
Product B | 2 ud | Source location X | Dest location Y | Lot B1
Product C | 3 ud | Source location X | Dest location Y | Lot C1
Now, I click on the first line button I made (each line has one), and
my wizard is opened. Here I can modify the lot of the first line (the
one with the Product A). Imagine I set Lot A0 and click on Apply.
I should return to the parent wizard, and see the same data except for
the changes made. So the result will be:
Product A | 1 ud | Source location X | Dest location Y | Lot A0
Product B | 2 ud | Source location X | Dest location Y | Lot B1
Product C | 3 ud | Source location X | Dest location Y | Lot C1
Does anyone know how to achieve this? How could I preserve the first wizard data?
First you need to browse current record of Wizard and it's line. Afterward write value as you want.
Return that current id with wizard object.
Try with following trick:
#apply button method logic
def apply_data(self, cr, uid, ids, context=None):
if not context:
context = {}
ctx = context.copy()
for wizard in self.browse(cr, uid, ids[0], context=context):
for line in wizard.one2many_field:
line.write({
'field_name': field_value
})
dummy, view_id = self.pool.get('ir.model.data').get_object_reference(cr, uid, 'module_name', 'wizard_form_view_name')
return {
'name':_("Name of your Wizard"),
'view_mode': 'form',
'view_id': view_id,
'view_type': 'form',
'res_id': ids and ids[0] or False,
'res_model': 'wizard.object.name',
'type': 'ir.actions.act_window',
'nodestroy': True,
'target': 'new',
'context': ctx
}
NOTE:
You can also update context value as well.
Apply button type must be object to execute method logic.

Pygal - Click bar and post data?

I am trying to create a simple charting web app using pygal and flask to chart some financial data I have stored in a mysql database. The data in the DB is hierarchical, and I want the app to start at the top of the hierarchy and allow the user to drill down by simply clicking on the relevant parts of the chart.
I am using flask to display the dynamically generated pygal charts.
Sample DB data:
guid | name | value | parentGuid | Description
------------------------------------------------
1234 | cat1 | 1 | null | Blah, blah
4567 | cat2 | 55 | null | asfdsa
8901 | cat3 | 22 | 1234 | asfdsa
5435 | cat4 | 3 | 8901 | afdsa
etc...
I have no problem drilling down the hierarchy using python + sql, but where I'm stumped is how I drill down using links in my pygal chart.
#app.route('/', methods=['GET', 'POST'])
def index():
if request.method == 'POST':
chart = graph_sub(request.form['guid'])
return render_template('Graph3.html', chart=chart)
else:
chart = graph_main()
return render_template('Graph3.html', chart=chart)
def graph_main():
""" render svg graph """
line_chart = pygal.HorizontalBar()
line_chart.title = 'Root Accounts'
RootAccts = GetRootAccounts() # Returns a list of lists containing accounts and account data.
for Acct in RootAccts:
line_chart.add({
'title': Acct[1], # Acct Name
'tooltip': Acct[4], # Acct description
'xlink': {'href': '/'} # Hyperlink that I want to pass POST data back to the form.
}, [{
'value': Acct[2]), # Acct Value
'label': Acct[4], # Acct Description
'xlink': {'href': '/'} # Hyperlink that I want to pass POST data back to the form.
}])
return line_chart.render()
def graph_sub(parentGuid):
### This works fine if I pass a parent GUID to it
### Now the question is how do I pass the guid to it from my pygal chart?
return line_chart.render()
So when I click on the links embedded in the pygal chart
'xlink': {'href': '/'}
How can I make it redirect back to the same page and pass the GUID of the selected account as POST data? Or is there another way to do this that doesn't involve POST?
The page reloading every time they click something so I'm hoping to keep this as simple as possible without having to involve ajax/java/etc... though if there are no other options I am open to it.
I don't have it coded yet, but there will also be some additional form controls added to the page that will allow the user to set date ranges to control how much data is displayed. I was planning to use POST to pass user input around, but before I get too far down that road, I need to figure out how I can manage this base functionality.
Thoughts?

Django - Saving one form multiple times

I have a Django view that uses one form multiple times. The form is saving relationship Subgroup id as a foreign key and Student id as a foreign key .
The problem I'm having is when I try to save information to database it only saves the last record.
For example (database model):
1 858 | Pump | Iron
2 78 | Madagaskar| Thomas
And if Im trying to split them into seperate groups, only Madagaskar his data is saved:
id | timestamp | student_Id_id | subgroup_Id_id |
+----+----------------------------+---------------+----------------+
| 62 | 2016-05-06 10:54:49.022000 | 2 | 91 |
The form looks like this:
class ApplicationFormaFull1(MultiModelForm):
form_classes = {
'sub1': FormSubgroup,
'sub2': FormSubgroup,
'stud_sub': FormStudent_in_Subgroup
}
and my view :
sub = form['sub1'].save(commit=False)
sub.student_group = StudentGroup.objects.get(id=element)
sub.number = 1
sub.type = 'Other'
sub.student_count = firstSubgroup
sub.save()
sub1 = form['sub2'].save(commit=False)
sub1.student_group = StudentGroup.objects.get(id=element)
sub1.number = 2
sub1.type = 'Others'
sub1.student_count = secondSubgroup
sub1.save()
if (counter%2==1):
stud_sub = form['stud_sub'].save(commit=True)
stud_sub.subgroup_Id = sub
stud_sub.student_Id = Student.objects.get(id=student)
stud_sub.save()
else:
stud_sub = form['stud_sub'].save(commit=True)
stud_sub.subgroup_Id = sub1
stud_sub.student_Id = Student.objects.get(id=student)
stud_sub.save()
So to sum up, I want that every form would save its information multiple times (dynamically)
Maybe the solution is that I should store information in the list and after all forms are added, save them one by one ?
stud_sub = form['stud_sub'].save(commit=False)
stud_sub.subgroup_Id = sub
stud_sub.student_Id = Student.objects.get(id=student)
list.add(stud_sub)
...
for i in list:
i.save()
Other solution use formset:
ArticleFormSet = formset_factory(ArticleForm, extra=2)
formset = ArticleFormSet(initial=[
{'title': 'Django is now open source',
'pub_date': datetime.date.today(),}
])
However i dont know how to change title, pub_date and to add everyting to formset dynimically.

Categories