I'm starting to learn Odoo and I'm developing an application in Odoo 12. I want to represent a database with intermediate table, in this case I have 2 tables ( products and actions ) and the relationship is 1...n and I must have an intermediate table that joins two tables.
Product (id, name, price...)
Action (id, name)
Product_action (id, id_product, id_action, date_from, date_to)
How I can do this? How can i represent this in the Odoo's model?
Thanks in advance.
Just create a model for the intermediate. You can also represent the entries of this intermediate model (rows in table) as 1:n relation on both the other models:
class ProductAction(models.Model):
_name = "product.action"
date_from = fields.Date()
date_to = fields.Date()
product_id = fields.Many2one(comodel_name="product.product")
action_id = fields.Many2one(comodel_name="action.model.name")
class ProductProduct(models.Model):
_inherit = "product.product"
intermediate_ids = fields.One2many(
comodel_name="product.action", inverse_name="product_id")
class ActionClassName(models.Model):
_inherit = "action.model.name"
intermediate_ids = fields.One2many(
comodel_name="product.action", inverse_name="action_id")
I assumed you are using Odoo's product class product.product but don't know what class/model is used for "actions" so i used a wildcard name for it in my example code.
Related
Problem Statement:
Extract all parents, grandparents, child, and grandchild from Snomed CT database
Description:
I am trying to set up the snomed database on my local box to extract relationships (all parents and child) for a particular concept (using concept_id).
I have downloaded snomed data from https://download.nlm.nih.gov/umls/kss/IHTSDO20190131/SnomedCT_InternationalRF2_PRODUCTION_20190131T120000Z.zip
Then I imported data into Postgres SQL DB using a script which I found here https://github.com/IHTSDO/snomed-database-loader/tree/master/PostgreSQL
But I didn't find any relationship between these tables so that I can fetch parents, grandparents, children and grandchildren for a particular concept id (I tried with lung cancer 93880001)
Following image contains table structure:
I really appreciate any help or suggestions.
According to the NHS CT Browser, which may not be accessible from everywhere, 93880001 has three parents:
Malignant tumor of lung (disorder)
Primary malignant neoplasm of intrathoracic organs (disorder)
Primary malignant neoplasm of respiratory tract (disorder)
and 31 children:
Carcinoma of lung parenchyma (disorder)
Epithelioid hemangioendothelioma of lung (disorder)
Non-Hodgkin's lymphoma of lung (disorder)
Non-small cell lung cancer (disorder)
and so on...
The way to find higher and lower levels of the hierarchy is to use relationship_f.sourceid and relationship_f.destinationid. However, the raw tables are not user friendly so I would suggest making some views. I have taken the code from the Oracle .sql files in this GitHub repo.
First, we make a view with concept IDs and preferred names:
create view conceptpreferredname as
SELECT distinct c.id conceptId, d.term preferredName, d.id descriptionId
FROM postgres.snomedct.concept_f c
inner JOIN postgres.snomedct.description_f d
ON c.id = d.conceptId
AND d.active = '1'
AND d.typeId = '900000000000013009'
inner JOIN postgres.snomedct.langrefset_f l
ON d.id = l.referencedComponentId
AND l.active = '1'
AND l.refSetId = '900000000000508004' -- GB English
AND l.acceptabilityId = '900000000000548007';
Then we make a view of relationships:
CREATE VIEW relationshipwithnames AS
SELECT id, effectiveTime, active,
moduleId, cpn1.preferredName moduleIdName,
sourceId, cpn2.preferredName sourceIdName,
destinationId, cpn3.preferredName destinationIdName,
relationshipGroup,
typeId, cpn4.preferredName typeIdName,
characteristicTypeId, cpn5.preferredName characteristicTypeIdName,
modifierId, cpn6.preferredName modifierIdName
from postgres.snomedct.relationship_f relationship,
conceptpreferredname cpn1,
conceptpreferredname cpn2,
conceptpreferredname cpn3,
conceptpreferredname cpn4,
conceptpreferredname cpn5,
conceptpreferredname cpn6
WHERE moduleId = cpn1.conceptId
AND sourceId = cpn2.conceptId
AND destinationId = cpn3.conceptId
AND typeId = cpn4.conceptId
AND characteristicTypeId = cpn5.conceptId
AND modifierId = cpn6.conceptId;
So a query to print out the names and ids of the three parent concepts would be:
select *
from relationshipwithnames r
where r.sourceId = '93880001'
and r.active = '1'
and r.typeIdName = 'Is a';
Note that this actually returns three extra concepts, which the online SNOMED browser thinks are obsolete. I am not sure why.
To print out the names and ids of child concepts, replace destinationId with sourceId:
select *
from relationshipwithnames r
where r.destinationId = '93880001'
and r.active = '1'
and r.typeIdName = 'Is a';
Note that this actually returns sixteen extra concepts, which the online SNOMED browser thinks are obsolete. Again, I cannot find a reliable way to exclude only these sixteen from the results.
From here, queries to get grandparents and grandchildren are straightforward.
I have recently started using Entity Framework and have run into a problem.
I have 2 simple tables mapped with Entity Framework in my solution:
Employees:
emp_id INT
first_name VARCHAR
last_name VARCHAR
department INT ( FOREIGN KEY MAPPED TO departments.dept_id )
and
Departments:
dept_id INT
department_name VARCHAR
Using the code below, I want to write to the database.
var record = db.employees.Create();
string test = "test";
record.first_name = test;
record.last_name = test;
record.department = 1;
db.employees.Add(record);
db.SaveChanges();
I get an error the error:
Entities in "'DBContextContainer.employees' participate in the 'employeedepartment' relationship. 0 related 'department' were found. 1 'department' is expected."
at the db.SaveChanges() method. Can someone please explain to me how I could resolve or troubleshoot this?
Update: There is a record in the departments table with a dept_id of 1 and I am still getting the error.
You'll need to add a field to the Departments table first since Departments is the parent table (Employees depend on Departments as per your table structure). You cant add an employee with department that doesn't have a corresponding entry in the Departments table.
I'm using Flask-SQLAlchemy with PostgreSQL. I have the following two models:
class Course(db.Model):
id = db.Column(db.Integer, primary_key = True )
course_name =db.Column(db.String(120))
course_description = db.Column(db.Text)
course_reviews = db.relationship('Review', backref ='course', lazy ='dynamic')
class Review(db.Model):
__table_args__ = ( db.UniqueConstraint('course_id', 'user_id'), { } )
id = db.Column(db.Integer, primary_key = True )
review_date = db.Column(db.DateTime)#default=db.func.now()
review_comment = db.Column(db.Text)
rating = db.Column(db.SmallInteger)
course_id = db.Column(db.Integer, db.ForeignKey('course.id') )
user_id = db.Column(db.Integer, db.ForeignKey('user.id') )
I want to select the courses that are most reviewed starting with at least two reviews. The following SQLAlchemy query worked fine with SQlite:
most_rated_courses = db.session.query(models.Review, func.count(models.Review.course_id)).group_by(models.Review.course_id).\
having(func.count(models.Review.course_id) >1) \ .order_by(func.count(models.Review.course_id).desc()).all()
But when I switched to PostgreSQL in production it gives me the following error:
ProgrammingError: (ProgrammingError) column "review.id" must appear in the GROUP BY clause or be used in an aggregate function
LINE 1: SELECT review.id AS review_id, review.review_date AS review_...
^
'SELECT review.id AS review_id, review.review_date AS review_review_date, review.review_comment AS review_review_comment, review.rating AS review_rating, review.course_id AS review_course_id, review.user_id AS review_user_id, count(review.course_id) AS count_1 \nFROM review GROUP BY review.course_id \nHAVING count(review.course_id) > %(count_2)s ORDER BY count(review.course_id) DESC' {'count_2': 1}
I tried to fix the query by adding models.Review in the GROUP BY clause but it did not work:
most_rated_courses = db.session.query(models.Review, func.count(models.Review.course_id)).group_by(models.Review.course_id).\
having(func.count(models.Review.course_id) >1) \.order_by(func.count(models.Review.course_id).desc()).all()
Can anyone please help me with this issue. Thanks a lot
SQLite and MySQL both have the behavior that they allow a query that has aggregates (like count()) without applying GROUP BY to all other columns - which in terms of standard SQL is invalid, because if more than one row is present in that aggregated group, it has to pick the first one it sees for return, which is essentially random.
So your query for Review basically returns to you the first "Review" row for each distinct course id - like for course id 3, if you had seven "Review" rows, it's just choosing an essentially random "Review" row within the group of "course_id=3". I gather the answer you really want, "Course", is available here because you can take that semi-randomly selected Review object and just call ".course" on it, giving you the correct Course, but this is a backwards way to go.
But once you get on a proper database like Postgresql you need to use correct SQL. The data you need from the "review" table is just the course_id and the count, nothing else, so query just for that (first assume we don't actually need to display the counts, that's in a minute):
most_rated_course_ids = session.query(
Review.course_id,
).\
group_by(Review.course_id).\
having(func.count(Review.course_id) > 1).\
order_by(func.count(Review.course_id).desc()).\
all()
but that's not your Course object - you want to take that list of ids and apply it to the course table. We first need to keep our list of course ids as a SQL construct, instead of loading the data - that is, turn it into a derived table by converting the query into a subquery (change the word .all() to .subquery()):
most_rated_course_id_subquery = session.query(
Review.course_id,
).\
group_by(Review.course_id).\
having(func.count(Review.course_id) > 1).\
order_by(func.count(Review.course_id).desc()).\
subquery()
one simple way to link that to Course is to use an IN:
courses = session.query(Course).filter(
Course.id.in_(most_rated_course_id_subquery)).all()
but that's essentially going to throw away the "ORDER BY" you're looking for and also doesn't give us any nice way of actually reporting on those counts along with the course results. We need to have that count along with our Course so that we can report it and also order by it. For this we use a JOIN from the "course" table to our derived table. SQLAlchemy is smart enough to know to join on the "course_id" foreign key if we just call join():
courses = session.query(Course).join(most_rated_course_id_subquery).all()
then to get at the count, we need to add that to the columns returned by our subquery along with a label so we can refer to it:
most_rated_course_id_subquery = session.query(
Review.course_id,
func.count(Review.course_id).label("count")
).\
group_by(Review.course_id).\
having(func.count(Review.course_id) > 1).\
subquery()
courses = session.query(
Course, most_rated_course_id_subquery.c.count
).join(
most_rated_course_id_subquery
).order_by(
most_rated_course_id_subquery.c.count.desc()
).all()
A great article I like to point out to people about GROUP BY and this kind of query is SQL GROUP BY techniques which points out the common need for the "select from A join to (subquery of B with aggregate/GROUP BY)" pattern.
I have trouble with pulling data from two different tables. I'm attempting to first grab all the addresses with a given name (select all the addresses with the name tom in table). Then with the addresses, look through another table (table2) for those addresses and pull a all the data from col number. Is there a better way than my code:
CONTROLLER:
this->table = new Address();
$getaddress = $this->table->getAddress($name); //grabbing all address associated with a given name
$address = $getaddress->toArray();
foreach ($addy as $address)
{
this->table2 = new Number();
$numbers = $this->table2->getNumber($address['numberColumn']);
$this->view->numbers = $numbers->toArray();
}
I will advice you to define relationship between table and table2. Of course you need foreign key in table2 which will be the relation to the first table.
Please study this document:
http://framework.zend.com/manual/1.12/en/zend.db.table.relationships.html
Consider two tables Bill and Product with a many to many relationship. How do you get all the bills for a particular product using Entity Sql?
Something like this
SELECT B FROM [Container].Products as P
OUTER APPLY P.Bills AS B
WHERE P.ProductID == 1
will produce a row for each Bill
Another option is something like this:
SELECT P, (SELECT B FROM P.Bills)
FROM [Container].Products AS P
WHERE P.ProductID == 1
Which will produce a row for each matching Product (in this case just one)
and the second column in the row will include a nested result set containing the bills for that product.
Hope this helps
Alex
You need to use some linq like this;
...
using (YourEntities ye = new YourEntities())
{
Product myProduct = ye.Product.First(p => p.ProductId = idParameter);
var bills = myProduct.Bill.Load();
}
...
This assumes that you have used the entitiy framework to build a model for you data.
The bills variable will hold a collection of Bill objects that are related to your product object.
Hope it helps.