In OpenERP I have 3 models, A, B and C. If you start on the form for A, there is a tree list of children B. when you click on one of those B children that form has a tree list of children C. I need the C children to be associated to both parents A and B but they will only associate themselves with B despite having many2one fields for both A and B. How can I force this association?
I have looked at solutions using active_id and default_get without success. The context object seems useful for this but I see no way of dynamically setting it with ids for both parent objects as I drill down from A to C navigating through the forms. I don't understand why context is not normally used for holding the context in this manner like in various web frameworks.
To clarify, when I edit object A and from it's edit form create an instance of B and from B's edit form create an instance of C how do I make the C associated to A and B?
Should I just execute a simple update with subselect query in C's create method to make this happen or will that break the ORM?
Looking at the transaction data when I save a new C instance (document) I see that everything I need in terms of ids is within the transaction but I don't know how to access and manipulate the values as I need to e.g.
{
"jsonrpc":"2.0",
"method":"call",
"params":{
"model":"dbe.vendor",
"method":"write",
"args":[
[
3
],
{
"application":[
[
4,
2,
false
],
[
1,
21,
{
"documents":[
[
4,
37,
false
],
[
4,
35,
false
],
[
4,
46,
false
],
[
4,
36,
false
],
[
0,
false,
{
"state":"new",
"name":"order of precendence test",
"description":"TESTING",
"type_of":7,
"locked":false,
"note":false,
"datas":false,
"datas_fname":false,
"type":"binary",
"application_id":false,
"certification_id":false,
"vendor_id":3,
"message_follower_ids":false,
"message_ids":false
}
]
]
}
]
]
}
],
"kwargs":{
"context":{
"lang":"en_US",
"tz":"EST",
"uid":7
}
},
"session_id":"303ae4c1bd9d49079c4efc9e06e0184f",
"context":{
"lang":"en_US",
"tz":"EST",
"uid":7
}
},
"id":"r138"
}
NOTE: I manually inserted vendor_id because it is a required field but it is the field I want to automatically populated.
Perhaps I am not literate enough with OpenERP to make this association happen properly or there isn't enough relevant documentation or the ORM isn't designed for this use (or any combinations of these) but I need this to work as per my requirements and now it does. I apologize if it is offensive in any manner. Criticisms and advice always welcome.
def create(self, cr, uid, vals, context=None):
"""Creates a new dbe.document instance. Called by both internal app and client.
documents are associated to dbe.vendor, dbe.application and dbe.certification.
#param vals: All dbe.document field values as a dictionary.
#return ID of new dbe.document instance.
"""
if context is None:
context={}
doc_id = None
association_id = None
# vendor_id is passed with vals when documents are created from the client side.
new_vendor_id = vals.get('vendor_id',False)
if new_vendor_id:
doc_id = super(dbe_document,self).create(cr, uid, vals, context=context)
_logger.debug("<CREATE> DBE Document (%d) created for vendor #%d by user %d", doc_id, new_vendor_id, uid)
else: # within OpenERP we cannot get vendor_id from context so we do it caveman style.
doc_id = super(dbe_document,self).create(cr, uid, vals, context=context)
association_id = self.read(cr, uid, doc_id, ['application_id', 'certification_id'], context=context)
if association_id['application_id']:
application_id = association_id['application_id']
application_obj = self.pool.get('dbe.application')
application = application_obj.browse(cr, uid, application_id)
new_vendor_id = application.vendor_id.id
elif association_id['certification_id']: # since there is no application maybe its a certification related doc....
certification_id = association_id['certification_id'][0]
certification_obj = self.pool.get('dbe.certification')
certification = certification_obj.browse(cr, uid, certification_id)
new_vendor_id = certification.vendor_id.id
else:
raise osv.except_osv(_('ValidateError'), _('<CREATE> A DBE Document cannot be created without an application or certification - Association Missing!'))
if new_vendor_id: # brute-force association to dbe.vendor.
vals.update({'vendor_id': new_vendor_id})
self.write(cr, uid, doc_id, vals, context)
_logger.debug("<CREATE> DBE Document (%d) created for vendor #%d by user %d", doc_id, new_vendor_id, uid)
else: # too bad - no vendor, no doc.
_logger.debug("<CREATE> DBE Document (%d) removed because vendor_id missing for user %d", doc_id, uid)
raise osv.except_osv(_('ValidateError'), _('<CREATE> A DBE Document cannot be created without selecting a Vendor - Vendor Id Missing!'))
return doc_id
better to use fields.related to make such association where you can do refer "A" from "B" in form of "C".
Related
I have a list of users with characteristics like this and I want to create a local variable that includes the names of the users in the "maker" group.
variable "users" {
type = map(object({
groups = list(string)
}))
default = {
"kevin.mccallister" = {
groups = ["kids", "maker"],
},
"biff" = {
groups = ["kids", "teens", "bully"],
},
}
}
I want to write the local like this, but it complains
Error: Invalid 'for' expression ... Key expression is required when
building an object.
locals {
makers_list = flatten({
for user, attr in var.users: user
if contains(attr.groups, "makers")
})
}
How can I take that map of objects and get out a list of names based on group affiliation?
flatten() is not required for this. Also, the {} is pushing this to build an object. You can instead build a list using [] and then it will create a list of the users filtered by their group association.
makers_list = [
for user, attr in var.users: user
if contains(attr.groups, "makers")
]
I am trying to set the description of a Google Calendar event to have a different selected presenter that is chosen in a rotatory manner (it is a slide deck that needs to be presented by a different person each week). The Python script specifying the rationale would work as the following
import datetime
people = ['Person 1', 'Person 2', 'Person 3']
year, week, day = datetime.date.today().isocalendar()
print(people[week_of_year % len(people)])
the resulting person from this calculation would show up in the calendar event description. Is there any tool to do that?
I was not able to find a way to create a recurrent event with different descriptions for each event.
However, I found a workaround for you using Events: patch. You first create an event using Events: insert, get the ID of the event you created with Events: list, and after that, then get the ID of the recurrences using Events: instances. Lastly, you use Events: patch to add the new description.
It might sound long, but I'm adding a sample with explanations on how to use it.
# impor the libraries that you will use for the calendar API
from __future__ import print_function
import os.path
from google.auth.transport.requests import Request
from google.oauth2.credentials import Credentials
from google_auth_oauthlib.flow import InstalledAppFlow
from googleapiclient.discovery import build
from googleapiclient.errors import HttpError
# The scopes that we need to use based on the Google documentation
# I added the information in the reference at the end of the answer
SCOPES = ['https://www.googleapis.com/auth/calendar',
'https://www.googleapis.com/auth/calendar.events']
# creation of the credential, I use as a base the Google Documentation "Python quickstart"
def main():
creds = None
if os.path.exists('token.json'):
creds = Credentials.from_authorized_user_file('token.json', SCOPES)
if not creds or not creds.valid:
if creds and creds.expired and creds.refresh_token:
creds.refresh(Request())
else:
flow = InstalledAppFlow.from_client_secrets_file(
'credentials.json', SCOPES)
creds = flow.run_local_server(port=0)
with open('token.json', 'w') as token:
token.write(creds.to_json())
try:
service = build('calendar', 'v3', credentials=creds)
# The list of people that will be use in each event
peoples = ['Person 1', 'Person 2', 'Person 3', 'Person 4']
number_week = 0
event = {
# Event title
'summary': 'Testing create description',
# A test description will be replaced later, so you can add anything you want to it.
'description': 'test',
# The start and end dates need to be in ISO-8601 date format
# and the time zone needs to be formatted as an IANA Time Zone Database name, e.g. "Europe/Zurich
'start': {
'dateTime': '2022-10-28T09:00:00-07:00',
'timeZone': 'America/Los_Angeles',
},
'end': {
'dateTime': '2022-10-28T17:00:00-07:00',
'timeZone': 'America/Los_Angeles',
},
'recurrence': [
# You can change the recurrence of the event
# for this example is a weekly event, and it has 4 recurrences
'RRULE:FREQ=WEEKLY;COUNT=4'
],
# The list of attendees
'attendees': [
{'email': 'test#email.xyz'},
{'email': 'test2#email.xyz'},
],
'reminders': {
'useDefault': False,
'overrides': [
{'method': 'email', 'minutes': 24 * 60},
{'method': 'popup', 'minutes': 10},
],
},
}
# We use insert to create the event
event = service.events().insert(calendarId='primary', body=event).execute()
# You can use the print in the next line to see the information about the event while you are testing
# print('Event created: %s' % (event.get('htmlLink')))
page_token = None
# Search for the event, using the method list and the event title q='Testing create description'
# you can use any other search key to get the event ID
events = service.events().list(calendarId='primary', pageToken=page_token, q='Testing create description').execute()
# get the ID of the event
for event in events['items']:
# print(event['id'])
id_event = event['id']
# Will search the ID of the recurrences of the event using the method instances
# e.g. xxxxxxxxxxxxxxxxx_20221028T160000Z
while True:
recurrences_for_events = service.events().instances(calendarId='primary', eventId=id_event,
pageToken=page_token).execute()
# run the dictionary of each iteration
for recurrence_instance in recurrences_for_events['items']:
id_to_update = recurrence_instance['id']
# I used the next print just to review the IDs of each event
# print(id_to_update)
# Create the new body of the event with the name of the people in the list of peoples
# instead of using year, week, day = datetime.date.today().isocalendar(). I use a simple counter to iterate on the list
body = {
'description': peoples[number_week],
}
# update the event description with patch
updated_event = service.events().patch(calendarId='primary', eventId=id_to_update, body=body).execute()
# print(updated_event['description'])
# next patch in case you have a large recurrence of the event
page_token = events.get('nextPageToken')
number_week += 1
# This will reset the counter, in case the number of people is less than the recurrences of the event
if number_week >= len(peoples):
number_week = 0
if not page_token:
break
except HttpError as error:
print('An error occurred: %s' % error)
if __name__ == '__main__':
main()
If the recurrent event has already been created, you only need to use the imports until the number_week = 0, and the part from:
events = service.events().list(calendarId='primary', pageToken=page_token, q='Testing create description').execute()
To the end, you might need to modify the for loop to only run once per recurrence.
Reference:
Python quickstart
Events: insert
Events: list
Events: instances
Events: patch
ISO 8601
I am unable to find a node via a key and then add a new node and an edge between them. with the movie nodes already in graph, i use:
case class GraphBuilder(movieId: Int, personId: Int)
//
val Ident = Key[String]("personId")
val ItemId = Key[String]("movieId")
//
def applyToGraph(it: GraphBuilder): Unit = {
val thisPerson = graph + ("Person", Ident -> it.personId.asInstanceOf[String])
val movies = graph.V.hasLabel("Movie").has(ItemId, it.movieId)
movies.headOption match {
case Some(v) =>
v --- "likedBy" --> thisPerson // tested with println("yay" + v)
case None => println("youre a failure")
}
graph.tx.commit()
}
But each time I run this programmatically, it correctly adds the person to the graph via thisPerson val, correctly finds the movie vertex based on the movieId, but does not create the "likedBy" edge. I have also tried without pattern matching on the option but that does not work either.
What method is best to find node, add node, add edge between added and found?
I'm a bit confused by the syntax in your snippet, but since you have to have the identifiers for both vertices, the following query should do the trick:
g.V().has("Movie", "movieId", movieId).as("m").
V().has("Person", "personId", personId).
addE("likedBy").to("m").iterate()
If the person vertex doesn't exist yet:
g.V().has("Movie", "movieId", movieId).as("m").
addV("Person").property("personId", personId).
addE("likedBy").to("m").iterate()
And if you don't know whether the person vertex already exists or not:
g.V().has("Movie", "movieId", movieId).as("m").
coalesce(
V().has("Person", "personId", personId)
addV("Person").property("personId", personId)).
addE("likedBy").to("m").iterate()
What is the Groovy way to get collection items without items in subcollection. For example:
collection:
[1,2,3,4,5,6]
subcollection:
[1,5,6]
the result should be:
[2,3,4]
EDIT:
It looks I'm doing something wrong. This is part of my code:
def report = Report.get(params.report.id)
def user = User.get(params.user.id)
List<User> availableUsers = []
availableUsers = User.findAllByCompany(company))
List<User> addedUsers = []
addedUsers = (List<User>) session["addedUsers"] ?: []
addedUsers << user
session["addedUsers"] = null
session["addedUsers"] = addedUsers
availableUsers = availableUsers - addedUsers
This code is only removing last user in addedUsers list.
availableUsers: [John, Jack, Jim]
addedUsers: [John, Jack]
availableUsers - addedUsers: [John, Jim]
Every time only the last item in addedUsers gets removed. I'm guessing I'm missing something obvious but I cant find it.
Did you try the obvious:
result = [ 1, 2, 3, 4, 5, 6 ] - [ 1, 5, 6 ]
Because that is what works...
Edit
Storing domain object in the session will result in the object being different between hibernate transactions, better to store the id in the session and get the Users fresh each time (or write this functionality into the domain if it needs persisting), something like:
addedUsers = session["addedUsers"].collect { User.get( it.id ) } ?: []
Does Scala support something like dynamic properties? Example:
val dog = new Dynamic // Dynamic does not define 'name' nor 'speak'.
dog.name = "Rex" // New property.
dog.speak = { "woof" } // New method.
val cat = new Dynamic
cat.name = "Fluffy"
cat.speak = { "meow" }
val rock = new Dynamic
rock.name = "Topaz"
// rock doesn't speak.
def test(val animal: Any) = {
animal.name + " is telling " + animal.speak()
}
test(dog) // "Rex is telling woof"
test(cat) // "Fluffy is telling meow"
test(rock) // "Topaz is telling null"
What is the closest thing from it we can get in Scala? If there's something like "addProperty" which allows using the added property like an ordinary field, it would be sufficient.
I'm not interested in structural type declarations ("type safe duck typing"). What I really need is to add new properties and methods at runtime, so that the object can be used by a method/code that expects the added elements to exist.
Scala 2.9 will have a specially handled Dynamic trait that may be what you are looking for.
This blog has a big about it: http://squirrelsewer.blogspot.com/2011/02/scalas-upcoming-dynamic-capabilities.html
I would guess that in the invokeDynamic method you will need to check for "name_=", "speak_=", "name" and "speak", and you could store values in a private map.
I can not think of a reason to really need to add/create methods/properties dynamically at run-time unless dynamic identifiers are also allowed -and/or- a magical binding to an external dynamic source (JRuby or JSON are two good examples).
Otherwise the example posted can be implemented entirely using the existing static typing in Scala via "anonymous" types and structural typing. Anyway, not saying that "dynamic" wouldn't be convenient (and as 0__ pointed out, is coming -- feel free to "go edge" ;-).
Consider:
val dog = new {
val name = "Rex"
def speak = { "woof" }
}
val cat = new {
val name = "Fluffy"
def speak = { "meow" }
}
// Rock not shown here -- because it doesn't speak it won't compile
// with the following unless it stubs in. In both cases it's an error:
// the issue is when/where the error occurs.
def test(animal: { val name: String; def speak: String }) = {
animal.name + " is telling " + animal.speak
}
// However, we can take in the more general type { val name: String } and try to
// invoke the possibly non-existent property, albeit in a hackish sort of way.
// Unfortunately pattern matching does not work with structural types AFAIK :(
val rock = new {
val name = "Topaz"
}
def test2(animal: { val name: String }) = {
animal.name + " is telling " + (try {
animal.asInstanceOf[{ def speak: String }).speak
} catch { case _ => "{very silently}" })
}
test(dog)
test(cat)
// test(rock) -- no! will not compile (a good thing)
test2(dog)
test2(cat)
test2(rock)
However, this method can quickly get cumbersome (to "add" a new attribute one would need to create a new type and copy over the current data into it) and is partially exploiting the simplicity of the example code. That is, it's not practically possible to create true "open" objects this way; in the case for "open" data a Map of sorts is likely a better/feasible approach in the current Scala (2.8) implementation.
Happy coding.
First off, as #pst pointed out, your example can be entirely implemented using static typing, it doesn't require dynamic typing.
Secondly, if you want to program in a dynamically typed language, program in a dynamically typed language.
That being said, you can actually do something like that in Scala. Here is a simplistic example:
class Dict[V](args: (String, V)*) extends Dynamic {
import scala.collection.mutable.Map
private val backingStore = Map[String, V](args:_*)
def typed[T] = throw new UnsupportedOperationException()
def applyDynamic(name: String)(args: Any*) = {
val k = if (name.endsWith("_=")) name.dropRight(2) else name
if (name.endsWith("_=")) backingStore(k) = args.first.asInstanceOf[V]
backingStore.get(k)
}
override def toString() = "Dict(" + backingStore.mkString(", ") + ")"
}
object Dict {
def apply[V](args: (String, V)*) = new Dict(args:_*)
}
val t1 = Dict[Any]()
t1.bar_=("quux")
val t2 = new Dict("foo" -> "bar", "baz" -> "quux")
val t3 = Dict("foo" -> "bar", "baz" -> "quux")
t1.bar // => Some(quux)
t2.baz // => Some(quux)
t3.baz // => Some(quux)
As you can see, you were pretty close, actually. Your main mistake was that Dynamic is a trait, not a class, so you can't instantiate it, you have to mix it in. And you obviously have to actually define what you want it to do, i.e. implement typed and applyDynamic.
If you want your example to work, there are a couple of complications. In particular, you need something like a type-safe heterogenous map as a backing store. Also, there are some syntactic considerations. For example, foo.bar = baz is only translated into foo.bar_=(baz) if foo.bar_= exists, which it doesn't, because foo is a Dynamic object.