anyone know how to reference a field value in a model when it's described with the 'property' decorator?
I have an 'order' model with a property decorator which totals a number of values in fields related to my 'order' class via a foreign key.
#property
def total_price(self):
"""
The total value of all items in the order, minus any discounts.
"""
total = sum([item.total_price
for item in self.order_orderitem_set.all()])
discounts = sum([item.discount
for item in self.order_orderitem_set.all()])
return total - discountsenter code here
When I reference this type it's quite simple. I do:
myOrders = Orders.objects.all()
for key in myOrders:
print "My total is: ", key.total_price
However if I use the source attribute as: Orders.objects.all and try and reference this value 'total_orders' Chartit provides me with an error that it can't find this field value.
My chartit datapool looks like:
orderdata = \
DataPool(
series=
[{'options': {
'source': Order.objects.all()},
'terms': [
'order_date',
'total_price']}
])
#Step 2: Create the Chart object
cht = Chart(
datasource = orderdata,
series_options =
[{'options':{
'type': 'line',
'stacking': False},
'terms':{
'order_date': [
'total_price']
}}],
chart_options =
{'title': {
'text': 'Total Orders Over Time'},
'xAxis': {
'title': {
'text': 'Order Date'}}})
I get the error:
Field u'total_price' does not exist. Valid lookups are promo_code, enduser_address, etc....
It looks like to me it is not able to reference my 'property' within the model. Is this just a limitation of the framework?
Does anyone know of a neat way of getting round this - it seems my options are:
1) Create my own json object and iterate around my 'orders' and create my own data list. Then pass this to highcharts directly; or
2) Create another table say 'OrderSaleHistory' and populate for each month via a management function that django will update periodically or from manual action. This new table will then be passed to chartit.
Or does anyone have better ideas? :-)
This is my first 'post' so quite a newbie in posting but not reading!!!!
Kind regards, Nicholas.
Related
I am using Django to generate a generic.ListView of objects. I am also using Elastic Search for search results. My question is how can I combine my queryset with an ordered list of JSON objects? get_queryset only allows me to return one variable (the queryset) but I need get_context_data to be able to access both the queryset and the associated metadata for the search results.
I created a below hack that works but looking for a better solution.
def get_queryset(self):
# just get 2 documents, in my actual code the queryset is generated by a list of IDs
# from the Elastic Search query
qs = Document.objects.all()[:2]
# create some fake search results, in my actual code I get a similar looking JSON
# objects with metadata like result score or highlighted snippets from the search corpus
fake_results = [
{ 'meta': {
'highlight': {
'title': ['ABC'],
'content': ['123', '456'],
}
}
},
{ 'meta': {
'highlight': {
'content': ['789'],
}
}
}
]
# this is a hack (i think) but need to merge the metadata from search results into the queryset object
for doc, result in zip(qs, fake_results):
if 'highlight' in result['meta']:
doc.snippet = result['meta']['highlight']
return qs
def get_context_data(self, **kwargs):
""" do stuff with the modified queryset """
You can return any iterable from the get_queryset. You can return zip(qs, fake_results), but you should just unpack it properly.
I'm trying to retrieve the field 'biddingStrategyConfiguration' via Adwords API for Python (3) using CampaignService(), but I always get an weird error. It's weird because the field does exist, as mentioned in the documentation found here.
account_id = 'any_id'
adwords = Adwords(account_id) # classes and objects already created, etc.
def get_bidding_strategy():
service = adwords.client.GetService('CampaignService', version = 'v201806')
selector = {
'fields': ['Id', 'Name', 'Status', 'biddingStrategyConfiguration']
}
results = service.get(selector)
data = []
if 'entries' in results:
for item in results['entries']:
if item['status'] == 'ENABLED':
data.append({
'id': item['id'],
'name': item['name'],
'status': item['status'] # i have to retrieve biddingStrategyConfiguration.biddingStrategyName (next line)
})
return results
This is the error:
Error summary:
{'faultMessage': "[SelectorError.INVALID_FIELD_NAME # serviceSelector; trigger:'biddingStrategyConfiguration']",
'requestId': '000581286e61247e0a376ac776062df4',
'serviceName': 'CampaignService',
'methodName': 'get',
'operations': '1',
'responseTime': '315'}
Notice that fields like "id" or "name" are easily retrievable, but the bidding configuration is not. In fact, I'm looking for the id/name of the biddingStrategies using .biddingStrategyID or .biddingStrategyName.
Can anyone help me? Thanks in advance.
How I solved it: biddingStrategyConfiguration is not a retrievable field, but biddingStrategyName is (part of the JSON).
account_id = 'any_id'
adwords = Adwords(account_id) # classes and objects already created, etc.
def get_bidding_strategy():
service = adwords.client.GetService('CampaignService', version = 'v201806')
selector = {
'fields': ['Id', 'Name', 'Status', 'biddingStrategyName']
}
results = service.get(selector)
I have two models skills and res_users.
I want that each user can have many skills and also each skill can have many users on it. I tried to do that but without success.
This is my skills:
class technicians_skills(osv.osv):
_name = 'skills'
_description = 'Technicians Skills'
_columns = {
'name': fields.char(string='name', size=50),
'description': fields.text(string="description"),
'member_ids': fields.many2many('res.users', 'skill', string='Technicians')
}
and this is the users :
class res_users(osv.osv):
_inherit = 'res.users'
_columns = {
'skill': fields.many2many('skills', relation='skills.rel', column1='name', column2='skill', string='Skill'),
}
and I want to know the skills of each user, but when I call this :
test = http.request.env['skills.rel'].search([])
It shows me this error
KeyError: 'skills.rel'
You need to specify all key words in your declaration to create the same relation tables
fields.many2many(
comodel_name='model.name',
relation='valid_postgres_name',
colum1='current_model_m2o_field_name',
column2='comodel_m2o_name',
string='Label')
And in the other definition keep the same name of the relation but inverse the other keyword.
In skills
user_ids = fields.many2many('re.users', 'user_skill_rel','user_id','skill_id', 'Users')
In users
skill_ids = fields.many2many('skills', 'user_skill_rel', 'skill_id', 'user_id', 'Skills')
See how i inversed the definition only the relation is the same.
Keep the same names of columns
EDITS:
don't execute search on relation because they are not models. you need to execute the search on the model then access the many2many fields.
Let say you want to get skill of the current user.
self.env.user.skill_ids # this will return the list of the skills for the current user
if you want to get the skills of more than one user.
result = self.env['res.users'].search([your_domain]])
# if you need to show user information then it's skill
for rec in result:
# use loop
rec.name # user name
rec.skill_ids
# but if you want to get the list of skill and you don't need users
skills = result.mapped('skills_ids') # mapped will return all the skills without duplication
I am building a module (Odoo 8) , my target is create offers in sale order, this offer can set a fix price for a determinate product or set a gift to zero cost.
I am adding my custom model offer_line, in new tab inside sale order.
Is defined like this:
class OfferSaleOrderLine(models.Model):
_name = 'offer.sale.order.line'
sale_order_ref = fields.Many2one('sale.order',ondelete='set null', string="Sale Order", index=True)
offer_ref = fields.Many2one('offer',ondelete='set null', string="Oferta", index=True)
is_active = fields.Boolean(default=True,string='Activo')
accumulations = fields.Float(digits=(6, 2), help="Acumulaciones")
class SaleOrder(models.Model):
_inherit = 'sale.order'
offers_lines = fields.One2many('offer.sale.order.line','sale_order_ref', string="Lineas de Ofertas")
I have a new api onchange method inside sale order:
#api.onchange('offers_lines')
def _onchange_offers_lines(self):
I check is offer need apply, and i add to offers_line new lines from this onchange function, like this:
self.offers_lines += self.env['offer.sale.order.line'].new({'is_active': True, 'offer_ref': offer, 'accumulations' : is_offer})
This is working perfect, lines is created, added to tab in form and onchange methods is trigger.
But the problem is next, if i try the same with sale order line, no working:
val = {
'name': gift_line.free_product.name,
'order_id': self.id,
'product_id': gift_line.free_product.id,
'product_uom_qty': gift_line.qty,
'product_uom': self.order_line[0].product_uom.id,
'price_unit': 0.0,
'state': 'draft',
}
self.order_line += self.env['sale.order.line'].new(val)
In log, this lines is created, i can see the newid id is created when i foreach self.order_line
****ORDER LINES : ID : ; Product: product.product(5152,) ; Qty: 6.0 ; Price: 0.0 ;****
but the item is no created in sale order line tab, i dont know why, my custom lines(One2many) is created, but, the sale_order_lines, with same code and one2many field too, is not created. I have the same problem if i try set the price_unit to this sale_order_lines. Log says changes is added, but is not updated in form. In next onchange trigger, the changes is dissapear.
Thanks to all!
#api.onchange('Put Your Onchange Field Here')
def _onchange_offers_lines(self):
vals = {
'name': gift_line.free_product.name,
'order_id': self.id,
'product_id': gift_line.free_product.id,
'product_uom_qty': gift_line.qty,
'product_uom': self.order_line[0].product_uom.id,
'price_unit': 0.0,
'state': 'draft'
}
self.order_line = [(0, 0, vals)]
Hope it will help you.
Odoo doesn't natively support onchange on *2many fields, anymore.
You can see that in openerp.models here https://github.com/odoo/odoo/blob/9.0/openerp/models.py#L6050
And furthermore a discussion on that topic here: https://github.com/odoo/odoo/issues/2693
I'm not sure to have properly understand your problem, but I see two things about it.
First you need to check that the field you want to set onchange is not already set in the base module that you are extending. If so, you had to disable the old-style onchange in the view by setting the attribute to 1 in the field (keep in mind that by disabling the api-v7 onchange on the field will not call the old onchange function you will probably want to call it in your new onchange function).
The second problem is that you can't add an item to a one2many field, you probably can to a many2one instead. You also can't use var += value to add an item to a relation field, you must use the special tupple (as described here).
So I have a session variable that has a rough structure like this:
request.session['selected_courses'] = {
'2': {'num_spots_available': 3,
attendees = [ {'first_name': 'Jon', 'last_name': 'Kan'}, ... ]}
...
}
Each key under 'selected_courses' is a course id.
I need to remove an attendee i.e {'first_name': 'Jon', 'last_name': 'Kan'} from a selected course. When I try to do this, the session does not actually delete the attendee. As I try to delete another attendee, the previous attendee pops right back into the session even though my code deleted it before! However, after rerunning this code, it finally deletes the attendee from session.
My code in views.py (i pull data out of POST because I am doing an AJAX request and know the data is not inputted by the user):
course_id = str(request.POST['course_id'])
first_name = str(request.POST['first_name'])
last_name = str(request.POST['last_name'])
request.session['selected_courses'][str(course_id)]['attendees'] = [a for a in request.session['selected_courses'][str(course_id)]['attendees']
if a['first_name'] != first_name or a['last_name'] != last_name]
request.session.modified =True
So I have tried the request.session.modified attribute (as shown above) along with the SESSION_SAVE_EVERY_REQUEST = True and neither worked. (Please note: I am still quite new to Django).
This code is much too complex, and has at least one serious bug. remove does not return the modified list, but None, so if you do attendees = attendees.remove(...) then the attendees will now be None.
A very much simpler way to write this code will be with loops:
for course in request.session['selected_courses']:
if course['course_id'] == course_id:
course['attendees'] = [
a for a in course['attendees']
if a['first_name'] != first_name and a['last_name'] != last_name
]
break
Note, this is not any less efficient, since your calls to map and remove are really loops themselves.
Alternatively, you might consider a different data structure; if you regularly need to search selected_courses for a particular course ID, it would be better to store it as a dict keyed by that ID, rather than a list of dicts containing the ID as a value.
request.session['selected_courses'] = {
'2': [ {'first_name': 'Jon', 'last_name': 'Kan'}, ... ]
}