on my edit/add page for SQLFORM.grid I would like to get the values of some fields on process. In case this value in combination with another field (userid) already exists user has to be notified about it.
any suggestions?
You can simply define the validator for one of the fields so it doesn't allow duplicates when the other field is also a duplicate, and then let the standard form validation process handle everything:
db.define_table('mytable',
Field('userid', 'reference auth_user'),
Field('otherfield',
requires=IS_NOT_IN_DB(db(db.mytable.userid == request.vars.userid),
'mytable.otherfield')))
Whenever a form is submitted, the IS_NOT_IN_DB validator will return an error if the value of "otherfield" is duplicated among the set of records where "userid" is also duplicated.
Related
I have a list in sharepoint online.
And in this list, i have a person field.
When i call the API endpoint to get all the items in the list, i get an LookupId value for the person field.
I tried to get the user by using the value of the lookupid, but it don't work because the id is not recognized.
The lookupid is a int (eg: 21) instead of a guid.
Is there something missing in the configuration of the person field or in my calls to Microsoft Graph API ?
When a user signs into a SharePoint site collection for the first time, a ListItem is created in a hidden User Information List. The LookupId in a PersonOrGroup field refers to the ListItem in this list. The URL for the User Information List for SharePoint Online should be:
https://{yourTenant}.sharepoint.com/{yourSiteCollection}/_catalogs/users/detail.aspx
Since the User Information List is a generic SharePoint list, you can query the list via Graph. First, get the list id for the User Information List. An easy way to get the list id is to view the source for the User Information Site via Chrome and search for 'listId'. You should find a result like this:
"listId":"{yourListIdIsHere}"
Copy the id. By using the copied id, the id of your root site and the LookupId, you can get the ListItem in the User Information List:
https://graph.microsoft.com/v1.0/sites/{siteId}/lists/{pasteCopiedListId}/items/{lookUpId}?$expand=Fields
The ListItem contains information about the user, such as the email, which can be used to identify the Azure user:
https://graph.microsoft.com/v1.0/users/{eMail}
Question: How could i get the hidden User Information List from Microsoft Graph?
If you do not want to use the 'trick' with Google Chrome to get the id, there is another way to get the site. Typically, if you want to get the id for any site, you would call:
https://graph.microsoft.com/v1.0/sites/{siteId}/lists
However, you will not find the id of the User Information List, even if you include hidden sites. I do not know why. An additional problem seems to be, that you cannot filter lists by their name:
https://graph.microsoft.com/v1.0/sites/{siteId}/lists?$filter=name eq 'users'
The query returns an error, that the provided filter statement is not supported. The only way to get the list without knowing the id seems to by using the property displayName of the list. However, the displayName is based on your localization. So, since I am from Germany, I can get the site by using the query:
https://graph.microsoft.com/v1.0/sites/{siteId}/lists?$filter=displayName eq 'Benutzerinformationsliste'
You will need to replace Benutzerinformationsliste with your localized name. For EN replace it with 'User Information List'.
This returns the expected result:
{
"#odata.context": "https://graph.microsoft.com/v1.0/$metadata#sites('xxx')/lists(id,name,displayName)",
"value": [
{
"#odata.etag": "\"xxx\"",
"id": "xxx",
"name": "users",
"displayName": "Benutzerinformationsliste"
}
]
}
As you can see, the name of the list is 'users', so why the first filter statement does not work is a little mystery to me. Maybe someone here knows and can help out.
Some of the queries above don't work at the moment.
What I finally found as a good solution - after trying many many queries - is that you can do this by following the few steps below:
1- Get the GUID of the user information list.
Using the title of the list "User Information List" or the name "users" in the parameter "$filter" does not work.
Don't forget 'system' among the properties you select if you want to retrieve the hidden system-lists.
GET https://graph.microsoft.com/v1.0/sites('{site_id}')/lists?select=id,name,system
2- Filter the previous result in order to pick up the ID of the targeted list named 'users'.
By the way, applying this restriction "$filter=name eq 'users'" does not work.
You will get an exception. So you must do the filtering part by writing a few lines of code.
3- Once you've got the list identifier, then select all the items you want. And voilà! The word 'Fields' must be in pascal case (uppercase the first letter ).
GET https://graph.microsoft.com/v1.0/sites('{site_id}')/lists('users_list_id')/items?$select=Fields&$expand=Fields
As #QuestionsPS1991 mentioned, the people field in fact refers to the hidden user list. With the lookupid, we can get the user via below methods:
Get user by id
Get user property by expanding lookup field
//////////// updated
By default, MS Graph does not return this user list. You may hard code the list id or follow ##QuestionsPS1991 suggestion. Below is my test:
I am attempting to set a field in one data model to equal to a field in a related data model. I've considered setting up an event to set the field equal to the other but do not know what the best trigger for this event would be and do not know the code that would be required.
Additionally, perhaps an event is not needed and there is some more fundamental/basic way to establish this field connection between related models.
Example: People Model has Companies Model as a related model. When adding a new People record, selecting the related Companies record would mean that the "Industry" field in the People record would be equal to the "Industry" field in the related Companies record.
Thank you!
You can execute a callback function after the People record is created. The callback function would change the Industry field value of the related Companies record to match the same value of the People record. Something like this (GIF). Notice that I am updating the Companies Industry value while creating a People record.
Here's the code on a Client Script:
var pgPeople = app.pages.PeopleCompanies;
var pgPeopleDesc = pgPeople.descendants;
function updateRelatedRecordField(){
var peopleDatasource = app.datasources.People;
peopleDatasource.createItem(function(record){
var industry = record.Industry;
record.Companies.Industry = industry;
});
}
You need to replace the default onClick function on the Form widget button with your function updateRelatedRecordField();
Read more here.
.py file:
….
namex=fields.Text()
moifier=fields.Many2one(‘res.users’, string=”Modifier”)
…
When some user modify “namex”, his/her name should be recorded on field “modifier” automatically; what code should I make? I try “onchange/depends”, but failed; maybe modifier could be a “text field/ char field”?
in addition, shall I set "access_rule" to set users just see the records created by the members in his/her own group?
Odoo already has that for you. Every model has those fields, which are automatically created and updated each time you create, or write:
create_date (datetime): when record is created
create_uid (many2one): user who created this record
write_date (datetime): last time record is updated
write_uid (many2one): last user updated this record
Go to Settings > Technical > Database Structure > Models for more details.
While Odoo will keep for you a track of the last user which has modified a record, a modifier per field is not kept. I can see the interest of such a functionality in many cases.
To do that for a particular model one possibility is to redefine the write method of this model. In your .py file you may want to add something like this:
#api.model
def write(self):
if self.namex in values:
values.update({'modifier': uid})
super().write(cr, uid, ids, values, context)
Another way to do that in a more flexible way is to use the #onchange decorator:
#onchange('your_sensible_field_name'):
def set_modifier(self):
self.modifer = self.env.user
You may also want to take a look at the #depends decorator.
I am currently automating my tests with Specflow and Selenium. I have created simple functions which I would like to re-use with Specflow. The problem I am encountering is, once I have defined a step as When, later on I cannot re-use this step with Then.
So for example:
Scenario: 1
Given user navigates to 'http://www.anyURL.com/'
When user inserts 'data' into field with ID 'id'
And user clicks on button with ID 'id'
Then user sees 'x' amount of search results
So this is scenario 1. Now in scenario 2 I want to use
"When user inserts 'data' into field with ID 'id'"
as:
"Then user inserts 'data' into field with ID 'id'"
But as in my code, my function starts with [When(#"user inserts '(.*)'.... Sepcflow doesn't match this.
I remember that Cucumber used to do this automatically.
Any help much appreciated!
In specflow you just have to add another attribute to the method you want to bind:
[When(#"user inserts '(.*)'"]
[Given(#"user inserts '(.*)'"]
public void UserInertsData(string data)
{
....
}
I know that in Rails you can call model.update_attribute :foo, 'bar' and it will update just that one attribute in the db without validating the rest of the model. This causes one SQL transaction.
You can also set multiple attributes with .update_attributes, but this cannot skip validations.
Or, you can call .save( :validate=>false ) and update the model without validation. However, this saves all the attributes on the model in their current state, rather than being able to limit this to certain columns.
My question is, is there any way to set more than one value on a model, but not all of them, without triggering validations, in a single SQL transaction?
Why don't you just set attributes and then call save with :validate => false?
#record.attributes = your_hash # won't nil non-mentioned attributes, as you expect it to
#record.save :validate => false
There are a number of ways to consider going depending on what you want. You can set your attributes and then call save with validate: false
model.attribute = value
model.other_attribute = other_value
model.save(validate: false)
You can also use update_columns. It is the fastest way to write to your db, but keep in mind that this will not only skip validations, it also skips callbacks, and it will even skip updating updated_at.
model.update_columns(attribute: value, other_attribute: other_value)
https://apidock.com/rails/ActiveRecord/Persistence/update_columns
Based on some of your comments it sounds like assign_attributes might actually be what you want. This won't save to the database at all, but sets the attributes so that you can save after your form is complete. Again, there are a number of ways to go depending on your specific need.
https://api.rubyonrails.org/v6.0/classes/ActiveModel/AttributeAssignment.html#method-i-assign_attributes