In customer invoice in the account module there is a one2many field,
invoice_line = fields.One2many('account.invoice.line', 'invoice_id', string='Invoice Lines')
Using this field we can add multiple products in the invoice. After adding multiple products how to segregate those products from this field, so that i will get product ids.
Suppose if we save two products, we will have two entries. From these two entry i need to separate each product's product id
For your question i can only give you a general answer. I hope, you can start with it.
In a odoo model (osv.osv, ...) you can use self.pool.get("model name") to get the object pool for any model. With this pool you can use the method read() to read the data.
A Odoo model is stored mostly in one table on the database.
Firstly you need to understand the relationship of the objects in Odoo. In your case it's so:
account.invoice --(invoice_line_ids:one2many)--> account.invoice.line --(product:many2one)-> product
Reading of one2many field returns a list of IDs of the destination objects.
Reading of Many2one field returns an int value of ID of the destination object.
Here is an example to get product ids from the lines of a invoice:
# call object pool for account.invoice
invoice_pool = self.pool.get("account.invoice")
# here you need the invoice_id to get the data.
# you can get it by parsing the parameter context
found_invoices = invoice_pool.read(cr, uid, [invoice_id,], ["invoice_line_ids"], context)
# It returns a list, but i gave only one invoice_id.
# the list has maximun one element. we need the frist element
found_invoice = found_invoices[0] if found_invoices else None
invoice_line_ids = found_invoice["invoice_line_ids"]
# the same with "account.invoice.line"
invoice_line_pool = self.pool.get("account.invoice.line")
invoice_lines = invoice_line_pool.read(cr, uid, invoice_line_ids, ["product_id"], context)
# Here you have the product ids
# I don't need to get the first element, because it returns a int
product_ids = [line["product_id"] for line in invoice_lines]
cr, uid, context are parameters, which you get from a request. You can get it by overwriting the method read, write, ....
Important: you need the invoice_id to start. You can get this value by parsing the variable context.
You can use logging to show the content of context in log file:
import logging
_logger = logging.getLogger(__name__)
_logger.info("context type: " + type(context))
_logger.info("context content: " + str(context))
P/S: You will need to customize my code to fit with yours, because i don't know many about your idea. I'm working with Odoo 9. But it's mostly the same core with Odoo 8
Related
I'm designing a database in which I'll be importing a large amount of data from XML daily to create or update existing rows.
Item data spans dozens of tables all related to the item_id in the main item table
For every item in the XML file, I need to check if it already exists in the database and update or create if it's not there.
Every XML belongs to a source_id and every item in the XML contains a unique alphanumeric ID up to 50 chars (but those IDs are not unique across all XMLs), so source_id:xml_item_id would be unique here
What I need is a way of finding if the item already exists in the database. Ideally, I will search by pk and use the same pk to join other tables
Attempt 1
I've tried encoding source_id:xml_item_id into a bigint for the pk as well as decode the bigint back to the original source_id:xml_item_id, but most of the times this is overflowing
So this is not going to work
Attempt 2
Use a UUID for the pk and source_id:xml_item_id as unique_id (string) for which to search by, but join related tables to UUID
While I don't see anything wrong here (IMO), JOINs might be affected, and I would prefer numeric pk for use in URLs
Attempt 3
Use source_id:xml_item_id as pk (string)
Same worries as with Attempt 2
The reason I've avoided AI PKs in all attempts is that there is a high possibility to shard this data in the future and I'd like this to have a relatively low impact on how PKs are being generated when this happens
What would be the best approach to handle this?
To identify if items already exist in the database
Have a user-friendly pk for URLs
Try not to impact JOIN performance too much
You can use unique together
class Data(models.Model):
source_id = models.CharField()
xml_item_id = models.CharField()
# ... other fields
class Meta:
unique_together = ("source_id", "xml_item_id")
Then in your import function just:
scid = your_xml_source_id
xmlid = your_xml_id
obj, created = Data.objects.get_or_create(source_id=scid, xml_item_id=xmlid)
if created:
# it's the new object, populate obj with the rest of the data
obj.other_field = your_xml_other_field
else:
# it's existing object, update object with a new value
obj.other_field = new_value
obj.save()
I have to store an existing computed field in Odoo 8 (only because it should be sortable for the users). The field is debit, which you can find in the module analytic, file analytic.py, model account.analytic.account.
The problem is, unfortunately, the field is declared in old API, and I am trying to store it using that one. By the way, adding only store=True to the field does not work (every record debit is 0 after that, even if I remove the column debit from the database once is stored and update my module to regenerate it), so I have to use the "old" #api.depends.
The model account.analytic.account, has a One2many field named line_ids which points to account.analytic.line. The field debit depends on this field, line_ids, and the fields account_id, date and amount of the account.analytic.line model. So in new API, the compute method should have this decorator above:
#api.depends('line_ids', 'line_ids.account_id', 'line_ids.date', 'line_ids.amount')
But I have to tell that in old API, so I did what I knew about that.
My code:
def _get_analytic_account_to_update_from_analytic_line(self, cr, uid, line_ids,
context=None):
if context is None:
context = {}
lines = self.browse(cr, uid, line_ids, context=context)
analytic_ids = []
for line in lines:
if line.account_id and line.account_id.id not in analytic_ids:
analytic_ids.append(line.account_id.id)
return analytic_ids
_columns = {
'debit': osv_fields.function(
_debit_credit_bal_qtty,
type='float',
string='Debit',
multi='debit_credit_bal_qtty',
digits_compute=dp.get_precision('Account'),
store={
'account.analytic.line': (
_get_analytic_account_to_update_from_analytic_line,
['account_id', 'date', 'amount'],
10
)
},
),
}
But there must be a mistake because every record debit is 0 (like if I put store=True). However, if I put store=False, every record debit is rightly computed.
The workflow is not even going into my method _get_analytic_account_to_update_from_analytic_line when the values should be computed.
Does anyone remember anything about this old API store dictionary? Any advice?
Would you migrate the whole compute method to new API only to make it being stored in the database?
I have the following (simplified) data model, see visual representation below the post:
Articles, which have Attributes
Attributes refer by PK to a Type, which have a field code
Attributes have a field value
The value refers to the field uuid in another model called Record, which also has a field sorting_code
I now want to return a list of articles in a certain ordering, using pagination. I am using a default ViewSet for it. The pagination forces me to do the ordering in database, instead of later in Python. However, I cannot seem to find the correct ordering clause that orders these articles. What I need to do is:
Fetch the Attribute with a specific type
Look up the values in those Attributes in the Record table
Order the articles based by sorting_code
The following SQL query does the job (for all articles):
SELECT art.order_id, art.uuid, att.value, mdr.code, mdr.name, mdr.sorting_code
FROM ow_order_article art
INNER JOIN ow_order_attribute att ON att.article_id = art.uuid
INNER JOIN ow_masterdata_type mdt ON att.masterdata_type_id = mdt.uuid
INNER JOIN ow_masterdata_record mdr ON att.value = mdr.uuid
WHERE mdt.code = 'article_structure'
ORDER BY mdr.sorting_code, mdr.code
What would be the correct way to get this ordering in a queryset in Django?
I've got 2 questions, but they are related to the same topic.
I know how to retrieve data from a for loop using template tags
{% for status in status %}
<tr>
<td>{{ status.status}}</td>
</tr>
{% endfor %}
However when I want to retrieve a single object i get an error even when i use:
po = Status.objects.latest('id')
and remove the for loop.
I get:
'Status' object is not iterable
My questions are:
How can I get the latest entry from the database for a given model?
How can I setup my templates tags to allow for just a single record?
You have two different questions here:
How do I retrieve the latest object from the database.
You can do this using the latest() queryset operator. By reading the docs you will note that this operator works on date fields, not integers.
Status.objects.latest('date_added') # or date_updated
If you want to do this off the ID you will need to order by ID and select the first result. (this will only work if you are using incrementing primary keys, it will not work with UUID's or randomly generated hashes).
Status.objects.order_by('id')[0]
Side note: I would personally use the date_added / date_updated way of doing this.
Iterating over a single object
A single object cannot be iterated over. For this you will need to use a different template. Or, you will need to add the single object into a list.
# note the [] around the query
result = [Status.object.latest('date_added')]
Personally I have a different views for listing single / multiple result. I have a ListView for many result objects and a DetailView for single objects.
TableName.objects.filter(key=value).order_by('-date_filed').first()
The "-date_filed'" field will reverse the order and the first will give you the latest element.
Let us assume I have a Model named "OneOfTheModelsUsed"
and there is a field called "car_name" and "date" within this model.
The following code worked for me while I was using Django FormWizard. After going through all the steps in the form and it gets saved. I used
last_entry = OneOfTheModelsUsed.objects.latest("date")
This gives all the entries in that model
last_car_name = last_entry.car_name
This gives the specific field entry you want in the given form.
return render(request, 'reference.html', {'last_car_name':last_car_name,}
passed the data to a template.
for the display in the template I used
{{last_car_model}}
and if you need the id for that entry.. use this {{last_car_model.id}} in the template.
PS:I'm fairly new to Django and Web development as a whole so I don't know much of the technical terms for all this
This is because latest returns a single instance rather than a queryset (which is iterable). So:
1) Latest is not working because it works with Date Fields. Read more at: https://docs.djangoproject.com/en/1.8/ref/models/querysets/#latest. 'id' is not a valid field to use with the latest filter.
2) You can't use for template tag with a single instance because it is not iterable.
To solve your situation, I would specify the ordering = ('id',) field in the Meta class of the model and then do a po = Status.objects.all()[:1] so you will obtain a queryset (which is iterable) with a single object in it. Then you will be able to use the for template tag with your po variable.
Hope it helps.
comments = usercomment.objects.order_by('-id')[:100]
I Did By This Method
First "comment" Is The Variable Name, "usercomment" Is Model Name, "id" is generated by django when make a model, [:100] is from 0 to 100 you can increase the number to x
I've got 2 questions, but they are related to the same topic.
I know how to retrieve data from a for loop using template tags
{% for status in status %}
<tr>
<td>{{ status.status}}</td>
</tr>
{% endfor %}
However when I want to retrieve a single object i get an error even when i use:
po = Status.objects.latest('id')
and remove the for loop.
I get:
'Status' object is not iterable
My questions are:
How can I get the latest entry from the database for a given model?
How can I setup my templates tags to allow for just a single record?
You have two different questions here:
How do I retrieve the latest object from the database.
You can do this using the latest() queryset operator. By reading the docs you will note that this operator works on date fields, not integers.
Status.objects.latest('date_added') # or date_updated
If you want to do this off the ID you will need to order by ID and select the first result. (this will only work if you are using incrementing primary keys, it will not work with UUID's or randomly generated hashes).
Status.objects.order_by('id')[0]
Side note: I would personally use the date_added / date_updated way of doing this.
Iterating over a single object
A single object cannot be iterated over. For this you will need to use a different template. Or, you will need to add the single object into a list.
# note the [] around the query
result = [Status.object.latest('date_added')]
Personally I have a different views for listing single / multiple result. I have a ListView for many result objects and a DetailView for single objects.
TableName.objects.filter(key=value).order_by('-date_filed').first()
The "-date_filed'" field will reverse the order and the first will give you the latest element.
Let us assume I have a Model named "OneOfTheModelsUsed"
and there is a field called "car_name" and "date" within this model.
The following code worked for me while I was using Django FormWizard. After going through all the steps in the form and it gets saved. I used
last_entry = OneOfTheModelsUsed.objects.latest("date")
This gives all the entries in that model
last_car_name = last_entry.car_name
This gives the specific field entry you want in the given form.
return render(request, 'reference.html', {'last_car_name':last_car_name,}
passed the data to a template.
for the display in the template I used
{{last_car_model}}
and if you need the id for that entry.. use this {{last_car_model.id}} in the template.
PS:I'm fairly new to Django and Web development as a whole so I don't know much of the technical terms for all this
This is because latest returns a single instance rather than a queryset (which is iterable). So:
1) Latest is not working because it works with Date Fields. Read more at: https://docs.djangoproject.com/en/1.8/ref/models/querysets/#latest. 'id' is not a valid field to use with the latest filter.
2) You can't use for template tag with a single instance because it is not iterable.
To solve your situation, I would specify the ordering = ('id',) field in the Meta class of the model and then do a po = Status.objects.all()[:1] so you will obtain a queryset (which is iterable) with a single object in it. Then you will be able to use the for template tag with your po variable.
Hope it helps.
comments = usercomment.objects.order_by('-id')[:100]
I Did By This Method
First "comment" Is The Variable Name, "usercomment" Is Model Name, "id" is generated by django when make a model, [:100] is from 0 to 100 you can increase the number to x