I created a custom module where you can link multiple contacts in a many2many field and I want to automatically add them all as a follower. I've read this article:
Automated Action to Add Users as Followers Odoo 12
Adding followers works fine, but only when the fields have ONE user or partner in it. In my installation these are many2many fields. When I add more then one user or partner in one of the fields, the code crashes.
Do I need to change something in this code when I want to add more then 1 contact or user in one of the fields?
I have this python code in my automated action:
record.message_subscribe(partner_ids=[record.field1.id, record.field2.partner_id.id, record.field3.partner_id.id])
field1 = partner
field2 & field3 = user
Thanks for your help!
You can not use .id to get id of records when there is multiple record, you have to use .ids which returns a list of record ids. So you code will have to changed into:
field1_ids = record.field1.ids
field2_ids = record.field2.mapped('partner_id').ids
field3_ids = record.field3.mapped('partner_id').ids
record.message_subscribe(partner_ids=field1_ids+field2_ids+field3_ids)
So the main issue with your code was, you were trying to access field where the record could be multiple (as many2many), but in Odoo ORM you can not do that, it will always give Expected Singletone error for multiple records.
Related
Take a record from the customers database as an example:
id, company, first_name, last_name, email, phone
'3', 'ABC Company', 'Kevins', 'kevinboy#gmail.com', 667-545-9502
And a sample record from the user permissions table:
user_id table column add delete view
1 customers company 1 1 1
1 customers first_name 1 1 1
1 customers last_name 1 1 1
1 customers email 0 0 0
1 customers phone 0 0 0
On our frontend, user 1 might be logged in, and the permissions table basically says that for any customer record, which fields do they have access to see. So from the customer record (id 3), on the front-end they would only see company, first and last name.
Normally, before permissions were implemented, on the frontend anyone could click a delete button, and a delete query was made DELETE FROM customers WHERE id = 3.
Now with permissions implemented, values for a record will only be returned where the user has view = 1 for a given table + column combo.
The question is, this works great for adding and editing a record. I was able to create logic on our API that checks specifically what the user is allowed to see. My challenge though is with DELETE. I have 2 ideas, and wanted to get some advice on the best approach, or if there is an easier way to achieve this directly in MySQL.
option 1) when a user sends a DELETE request to the API, I can take the customer id given and get the record from the db using a SELECT. Then, I can evaluate which fields have data, and which fields the user is permissioned to delete. Basically, if a record contains what they are permissioned to, then yes they can delete it, but if it contains values in other fields they are not permissioned to, then no they cant delete the record.
option 2) when the user sends a DELETE request to the API they can include the full record from the frontend. So I'd expect them to send all values for id 3 as shown above. In this case, i can also evaluate what they are sending me and what fields they have access to delete.
This query runs at the API level before ever adding, deleting a record.
SELECT column FROM permissions WHERE table = ? and delete = ? and user_id = ?
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
How do you determine the name of a custom field in jira-python?
When I retrieve an issue, my custom fields show up as customfield_xxx
The names on my screen are 'project', 'name', 'due date', etc.
Short of putting a value in each field, then seeing where it appears
when I re-read the issue.
That is I can put 'a' in one of my fields, then read the issue, and find that
customfield_10801 (or whatever) has the value 'a'. But is there a general
way to find, for example, if my custom field is 'due date', which customfield_xxx
does it get mapped to?
Or, in the JIRA GUI, how would I look up these customfield #'s.
From the GUI you can see the custom field id in the html code or url:
On the admin page where all the custom fields are listed on the row of the custom field you are interested to the right click the gear and click/hover over "Configure". You should see the custom field ID in the URL.
Another way is via the REST API:
{jira-base-url}/rest/api/2/field
It's a GET request so just put that url in your browser.
Update:
Based on the comments it can be done something like this:
# Fetch all fields
allfields=jira.fields()
# Make a map from field name -> field id
nameMap = {field['name']:field['id'] for field in allfields}
# Fetch an issue
issue = jira.issue('ABC-1')
# You can now look up custom fields by name using the map
getattr(issue.fields, nameMap[custom_name])
i am trying to use SQLFORM.factory in web2py and in one of the tables i have field where i want to use requires 2 times but it gives an error i know there is some way how you are supposed to do it but i dont know how.
i am new to web2py
form = SQLFORM.factory(
Field('email', requires=IS_NOT_EMPTY(), requires = IS_EMAIL(error_message='invalid email'))
)
here i want to put both conditions that field email is of type email and should not be empty which are 2 different require fields but how to join them or somthing???
I'm new to web2py as well but I believe you need to put them in a python list. Like this:
form = SQLFORM.factory(
Field('email', requires=[IS_NOT_EMPTY(), IS_EMAIL(error_message='invalid email')])
)
See the documentation where they talk about Multiple validators: http://www.web2py.com/book/default/chapter/07#Validators
MongoDB is using string(hash) _id field instead of integer; so, how to get classic id primary key? Increment some variable each time I create my class instance?
class Post(Document):
authors_id = ListField(IntField(required=True), required=True)
content = StringField(max_length=100000, required=True)
id = IntField(required=True, primary_key=True)
def __init__(self):
//what next?
Trying to create new user raises exception:
mongoengine.queryset.OperationError: Tried to save duplicate unique keys
(E11000 duplicate key error index: test.user.$_types_1_username_1
dup key: { : "User", : "admin" })
Code:
user = User.create_user(username='admin', email='example#mail.com',
password='pass')
user.is_superuser = True
user.save()
Why?
There is the SequenceField which you could use to provide this. But as stated incrementing id's dont scale well and are they really needed? Can't you use ObjectId or a slug instead?
If you want to use an incrementing integer ID, the method to do it is described here:
http://www.mongodb.org/display/DOCS/How+to+Make+an+Auto+Incrementing+Field
This won't scale for a vary large DB/app but it works well for small or moderate application.
1) If you really want to do it you have to override the mongoengine method saving your documents, to make it look for one document with the highest value for your id and save the document using that id+1. This will create overhead (and one additional read every write), therefore I discourage you to follow this path. You could also have issues of duplicated IDs (if you save two records at the exactly same time, you'll read twice the last id - say 1 and save twice the id 1+1 = 2 => that's really bad - to avoid this issue you'd need to lock the entire collection at every insert, by losing performances).
2) Simply you can't save more than one user with the same username (as the error message is telling you) - and you already have a user called "admin".