Thanks Mike. 

Just in case, I found some dificulties working with it, so despite the code 
is long, it could help someone in the community or open interesting 
discussions, so I leave it below. Thanks again.


import uuid
import json
import datetime
from src.common.helpers import format_date_TZ
from sqlalchemy import create_engine
from sqlalchemy.orm import relationship, create_session
from sqlalchemy import (
Column, DateTime, String, Integer,
Boolean, ForeignKey, Table
)
from src.application.kernel.engine import Base

STRING_ID = 50
STRING_JSON = 1024
STRING_NAME = 100
STRING_TYPE = 10
STRING_BIG_JSON = 2048


class Page(Base):
__tablename__ = 'page'

# Columns
page_uuid = Column(String(STRING_ID), nullable=False)
id = Column(
String(STRING_ID),
primary_key=True,
nullable=False
)
event_date = Column(DateTime)
last_update = Column(
DateTime,
default=datetime.datetime.now(),
onupdate=datetime.datetime.now(),
)
creation_date = Column(DateTime(timezone=True))
title = Column(String(STRING_NAME), nullable=False)
slug = Column(String(STRING_NAME), nullable=False)
description = Column(String(STRING_BIG_JSON))
perks = Column(String(STRING_BIG_JSON))
meta_description = Column(String(STRING_JSON))
about = Column(String(STRING_BIG_JSON))
status = Column(String(STRING_TYPE), nullable=False)
keywords = Column(String(STRING_JSON))
seo_title = Column(String(STRING_JSON))
search_field = Column(String(STRING_JSON))
marketing_type = Column(String(STRING_JSON))

images = Column(String(STRING_JSON))
cover_images = Column(String(STRING_JSON))
graph_images = Column(String(STRING_JSON))
thumbnails = Column(String(STRING_JSON))
hide_from_search = Column(Boolean)

page_type = Column(String(STRING_JSON), nullable=False)

__mapper_args__ = {
'polymorphic_identity': 'page',
'polymorphic_on': page_type,
'with_polymorphic': '*',
# This triggers the update on cascade
# 
https://docs.sqlalchemy.org/en/13/orm/mapping_api.html?highlight=passive_updates#sqlalchemy.orm.mapper.params.passive_updates
'passive_updates': False,
}

def __init__(
self,
data=None,
page_type=None,
images=None,
c_images=None,
g_images=None,
thumbnails=None,
tags=None,
ass_prod=None,
):
print('### INIT PAGE')
self.page_uuid = str(uuid.uuid4())
if ass_prod:
self.update(data, tags=tags, ass_prod=ass_prod)
self.update(data, tags=tags)

def update(
self,
data=None,
page_type=None,
images=None,
c_images=None,
g_images=None,
thumbnails=None,
):
print('**UPDATING PAGE')
if data:
self.id = data.get('id').get('__value')
if data.get('event_date'):
self.event_date = data.get('event_date').get('__value')
self.creation_date = format_date_TZ(
data.get('createdAt').get('__value')
) if data.get('createdAt').get('__value') else None
self.title = data.get('title').get('__value')
self.slug = data.get('slug').get('__value')
self.description = data.get('description').get('__value')
self.perks = json.dumps(data.get('perks').get('__value'))
self.meta_description = json.dumps(data.get('metaDescription').get('__value'
))
self.about = data.get('about').get('__value')
self.status = data.get('status').get('__value').get('status')
self.keywords = json.dumps(data.get('keywords').get('__value'))
self.seo_title = data.get('SEOTitle').get('__value')
self.marketing_type = data.get('type').get('__value')
self.search_field = ''
self.hide_from_search = True

if page_type:
self.page_type = page_type
if images:
self.images = images
if c_images:
self.cover_images = c_images
if g_images:
self.graph_images = g_images
if thumbnails:
self.thumbnails = thumbnails


product_tag_association = Table(
'product_tag_association',
Base.metadata,
Column(
'p_id',
String(STRING_ID),
ForeignKey('product.id'),
primary_key=True
),
Column(
't_id',
String(STRING_ID),
ForeignKey('pagetag.tag_id'),
primary_key=True
)
)


class Product(Page):
__tablename__ = 'product'

# Columns
product_uuid = Column(String(STRING_ID), nullable=False)
id = Column(
String(STRING_ID),
ForeignKey('page.id'),
primary_key=True,
nullable=False
)

concessions = Column(String(STRING_BIG_JSON), nullable=False)
product_type = Column(String(STRING_TYPE), nullable=False)

tags = relationship(
"Tag",
secondary="product_tag_association",
backref="products"
)

__mapper_args__ = {
'polymorphic_identity': 'product',
# 'polymorphic_on': product_type,
}

def __init__(self, data=None, product_type=None, tags=None, ass_prod=None):
print('### INIT PRODUCT')
super().__init__(
data=data,
page_type='product',
tags=tags,
ass_prod=ass_prod,
)
self.product_uuid = str(uuid.uuid4())

def update(self, data=None, product_type=None, tags=None):
print('**UPDATING PRODUCT')
print(tags)
# Here I had my main error. I was not passing down the product_type (which 
in deed will be a page_type)
# I was passing down page_type='product' so when I generate an entity son 
of Product, its page_type
# was overwritten by product. 
super().update(data=data, page_type=product_type)
if data:
# self.id = data.get('id').get('__value')
self.concessions = json.dumps(data.get('concessions').get('__value'))
if product_type:
self.product_type = product_type
if tags:
self.tags = tags


class Tag(Page):
__tablename__ = 'pagetag'

# Columns
tag_uuid = Column(String(STRING_ID), nullable=False)
tag_id = Column(
String(STRING_ID),
ForeignKey('page.id'),
primary_key=True,
nullable=False
)
featured = Column(Integer, nullable=False)
featured_index = Column(Integer, default=0, nullable=False)
tag_type = Column(String(STRING_TYPE), nullable=False)

__mapper_args__ = {
'polymorphic_identity': 'pagetag',
}

def __init__(self, data=None):
print('### INIT TAG')
super().__init__(data, page_type='pagetag')
self.tag_uuid = str(uuid.uuid4())

def update(self, data=None, tags=None):
super().update(data=data, page_type='pagetag')
if data:
self.featured = 0
self.featured_index = 0
self.tag_type = data.get('tagType').get('__value')


travelpass_travel_association = Table(
'travelpass_travel_association',
Base.metadata,
Column(
'tp_id',
String(STRING_ID),
ForeignKey('travel_pass.id'),
primary_key=True
),
Column(
't_id',
String(STRING_ID),
ForeignKey('travel.id'),
primary_key=True
)
)


class TravelPass(Product):
__tablename__ = 'travel_pass'

# Columns
travel_pass_uuid = Column(String(STRING_ID), nullable=False)
id = Column(
String(STRING_ID),
ForeignKey('product.id'),
primary_key=True,
nullable=False
)
allow_one_way_optin = Column(Boolean, default=False)
auto_journey_optin = Column(Boolean, default=False)
allow_repurchase = Column(Boolean, default=False)
allow_edit_booking = Column(Boolean, default=False)
allow_guests_onboard = Column(Boolean, default=False)
create_own_page = Column(Boolean, default=False)
show_departure_time = Column(Boolean, default=False)
opt_out_promo = Column(String(STRING_JSON))
max_number_passenger = Column(Integer)
start_date = Column(DateTime(timezone=True))
end_when = Column(String(STRING_JSON))
end_date = Column(DateTime(timezone=True))
end_after_amount = Column(Integer)
end_after_unit = Column(String(STRING_JSON))
allow_return = Column(Boolean, default=False)

# Columns with relationships
associated_products = relationship(
'Travel',
secondary=travelpass_travel_association,
back_populates='associated_travelpass'
)

__mapper_args__ = {
'polymorphic_identity': 'travel_pass',
}

def __init__(self, data=None, ass_prod=None, tags=None):
print('### INIT TRAVELPASS')
super().__init__(data=data, tags=tags, ass_prod=ass_prod)
self.travel_pass_uuid = str(uuid.uuid4())

def update(self, data=None, travel_type=None, tags=None, ass_prod=None):
print('**UPDATING TRAVEL PASS')
super().update(data=data, product_type='travel_pass', tags=tags)

if data:
# super().__init__(data=data, product_type='travel_pass')
self.id = data.get('id').get('__value')
self.allow_one_way_optin = (
data
.get('allowOneWayOptin')
.get('__value')
)
self.auto_journey_optin = (
data
.get('autoJourneyOptin')
.get('__value')
)
self.allow_repurchase = data.get('allowRepurchase').get('__value')
self.allow_edit_booking = (
data
.get('allowEditBooking')
.get('__value')
)
self.allow_guests_onboard = (
data
.get('allowGuestsOnBoard')
.get('__value')
)
self.create_own_page = data.get('createOwnPage').get('__value')
self.show_departure_time = (
data
.get('showDepartureTime')
.get('__value')
)
self.opt_out_promo = json.dumps(
data.get('optOutPromo').get('__value')
)
self.max_number_passengers = (
data
.get('maxNumberPassengers')
.get('__value')
)
self.start_date = format_date_TZ(
data.get('startDate').get('__value')
)
self.end_when = (
data
.get('endWhen')
.get('__value')
.get('end_when')
) if data.get('endWhen').get('__value') else None
self.end_date = format_date_TZ(
data.get('endDate').get('__value')
) if data.get('endDate').get('__value') else None
self.end_after_amount = data.get('endAfterAmount').get('__value')
self.end_after_unit = (
data
.get('endAfterUnit')
.get('__value')
.get('end_after_unit')
) if data.get('endAfterUnit').get('__value') else None
self.allow_return = data.get('allowReturn').get('__value')

if ass_prod:
self.associated_products = ass_prod


class Travel(Product):
__tablename__ = 'travel'

# Columns
travel_uuid = Column(String(STRING_ID), nullable=False)
id = Column(
String(STRING_ID),
ForeignKey('product.id'),
primary_key=True,
nullable=False
)
outbound_seats_on_sale = Column(Integer, default=0)
return_seats_on_sale = Column(Integer, default=0)
travel_type = Column(String(STRING_TYPE), nullable=False)

# Columns with relationships
associated_travelpass = relationship(
'TravelPass',
secondary=travelpass_travel_association,
back_populates='associated_products'
)

__mapper_args__ = {
'polymorphic_identity': 'travel',
# 'polymorphic_on': travel_type
}

def __init__(self, data=None, travel_type=None, tags=None):
print('### INIT TRAVEL')
super().__init__(data=data, product_type='travel', tags=tags)
self.travel_uuid = str(uuid.uuid4())

def update(self, data=None, travel_type=None, tags=None, ass_prod=None):
print('**UPDATING TRAVEL')
super().update(data=data, product_type='travel', tags=tags)
if data:
# self.id = data.get('id').get('__value')
self.outbound_seats_on_sale = (
data
.get('outboundSeatsOnSale')
.get('__value')
)
self.return_seats_on_sale = (
data
.get('returnSeatsOnSale')
.get('__value')
)
if travel_type:
self.travel_type = travel_type


class Event(Travel):
__tablename__ = 'event'

# Columns
event_uuid = Column(String(STRING_ID), nullable=False)
id = Column(
String(STRING_ID),
ForeignKey('travel.id'),
primary_key=True,
nullable=False
)
from_date = Column(DateTime(timezone=True), nullable=False)
to_date = Column(DateTime(timezone=True), nullable=False)

__mapper_args__ = {
'polymorphic_identity': 'event',
}

def __init__(self, data=None, tags=None):
print('### INIT EVENT')
super().__init__(data=data, travel_type='event', tags=tags)
self.event_uuid = str(uuid.uuid4())
# self.update(data)

def update(self, data=None, tags=None, ass_prod=None):
super().update(data=data, travel_type='event', tags=tags)
if data:
# self.id = data.get('id').get('__value')
self.from_date = format_date_TZ(
data.get('eventFromDate').get('__value')
) if data.get('eventFromDate').get('__value') else None
self.to_date = format_date_TZ(
data.get('eventToDate').get('__value')
) if data.get('eventToDate').get('__value') else None


e = create_engine("sqlite:///test.db", echo=True)
Base.metadata.drop_all(e)
Base.metadata.create_all(e)

travelpass_data = {
'old_entity': None,
'new_entity': {
'__type': 'array',
'__encrypted': False,
'__class': None,
'__value': {
'id': {
'__value': '4753fa6a-9b9f-47b9-975c-dacb7634f093'
},
'createdAt': {
'__value': None
},
'title': {
'__value': 'Travel pass test title'
},
'slug': {
'__value': 'rides%2Fsporting-en-primera%2Ftravel-pass-test-title'
},
'description': {
'__value': 'Travel pass test description'
},
'perks': {
'__value': []
},
'images': {
'__value': []
},
'coverImages': {
'__value': []
},
'metaDescription': {
'__value': 'Travel pass test description SEO BODY'
},
'about': {
'__value': '<p><strong>Travel pass about information</strong></p>\n'
},
'status': {
'__value': {'status': 'UNPUBLISHED'}
},
'keywords': {
'__value': 'travel'
},
'graphImages': {
'__value': []
},
'SEOTitle': {
'__value': 'Travel pass test title SEO TITLE'
},
'thumbnails': {
'__value': []
},
'type': {
'__value': 'sport'
},
'tags': {
'__value': [
{
'__value': '27422bce-dd24-45fa-9096-f402c1f2c9a5'
},
{
'__value': '2fc57cf6-3022-4926-b597-5798d259d693'
}
]
},
'concessions': {
'__value': []
},
'allowOneWayOptin': {
'__value': True
},
'autoJourneyOptin': {
'__value': True
},
'allowRepurchase': {
'__value': True
},
'allowEditBooking': {
'__value': True
},
'allowGuestsOnBoard': {
'__value': True
},
'createOwnPage': {
'__value': False
},
'showDepartureTime': {
'__value': True
},
'optOutPromo': {
'__value': None
},
'maxNumberPassengers': {
'__value': 100
},
'associateProducts': {
'__value': [
{
'__value': '21bd039b-465b-4de3-bf40-fc1b4a41843e'
},
{
'__value': '553acea9-22d1-4118-954a-7bc699166fcc'
}
]
},
'startDate': {
'__value': '20190514140000 Europe/London'
},
'endWhen': {
'__value': {
'end_when': 'ON_SPECIFIC_DATE'
}
},
'endDate': {
'__value': '20190530005700 Europe/London'
},
'endAfterAmount': {
'__value': None
},
'endAfterUnit': {
'__value': None
},
'allowReturn': {
'__value': True
}
},
'__entity_version': 1
}
}

session = create_session(bind=e, autoflush=True, autocommit=False)
data = travelpass_data.get('new_entity').get('__value')
print(data)

ass_prod = []
for prod in data.get('associateProducts').get('__value'):
temp = (
session
.query(Travel)
.filter(Travel.id == prod.get('__value'))
.all()
)
if temp:
ass_prod.append(temp)

ass_tags = []
for tag_id in data.get('tags').get('__value'):
ass_tags.append(
session.query(Tag)
.filter(
Tag.id == tag_id.get('__value')
)
.one_or_none()
)

print(ass_tags)

new_entity = TravelPass(
data=data,
ass_prod=ass_prod,
tags=None
)

session.add(new_entity)
session.commit()


new_entry_id = data.get('id').get('__value')
print(TravelPass)
print('REQUIRED ID: {}'.format(new_entry_id))

entry_exist = (
session
.query(TravelPass)
.filter(TravelPass.id == new_entry_id)
.one_or_none()
)

print('****ENTITY TYPE: {}'.format(entry_exist.__class__))
print(dict(entry_exist.__dict__))



On Thursday, August 22, 2019 at 8:16:36 PM UTC+2, Mike Bayer wrote:
>
>
>
> On Thu, Aug 22, 2019, at 2:06 PM, Javier Martínez wrote:
>
> Thanks for the answer Mike. 
> If I understand right, what you mean is to have at the base-most level 
> (Page in this case) the polymorphic on, and each child, grandchild class 
> having a specific value for that discriminator?
>
>
> yes that's the normal way to do it.   It would be nice if you could have 
> two levels of discriminator for schema / code organization purposes but you 
> never need it to make the basic structure work.
>
>
>
>
> So let say the discriminator is page_type, each class can put the string 
> there with its name, for instance, Event will put 'event', travel will put 
> 'travel' and so on?
>
>
> yup
>
>
>
>
>
>
> On Thursday, August 22, 2019 at 5:00:15 PM UTC+2, Mike Bayer wrote:
>
> That particular idea is a convenience but is never necessary to get a 
> multiple-level inheritance model to work.  You simply have the 
> polymorphic_on in the base-most table be the place where the discriminator 
> is stored, and each descendant class defines its discriminator value fully.
>
>
>
> On Thu, Aug 22, 2019, at 10:39 AM, Javier Martínez wrote:
>
> In deed I am trying to follow this idea:
> https://groups.google.com/d/msg/sqlalchemy/ij10zJ4hOv8/5YQDDkwJ2wUJ
>
> On Thursday, August 22, 2019 at 3:28:34 PM UTC+2, Javier Martínez wrote:
>
> Hi everyone, 
>
> here again to look for some advice and wise suggestions. 
>
> I am facing a situation that I thought I have already covered, but during 
> the testing phase (with real data) was not the case. So I have the 
> relationship between entities that you can see in the diagram below. I have 
> started using the next hierarchy:
>
> Base ->Page->(Tag and Product)-> (TravelPass and Travel) -> (Event, 
> Privatebooking)
>
> In each one of this extends I have used the 'polymorphic_on' to work with 
> a Joined Inheritance format. So reading more carefully the docs I realized 
> that this is not possible and in deed I had problems when querying the 
> TravelPass entity getting the results of
> the Travel entity. So right now I am looking for alternatives to implement 
> this but I am a bit lost. I think the single table format will not solve 
> it. I am thinking about using regular relationships for making it works, 
> but so far no great
> ideas come to my mind. I would like to ask for your advice in this topic. 
> Thanks in advance. 
>
>
> [image: Screenshot 2019-08-22 at 15.16.39.png]
>
>
> --
> SQLAlchemy - 
> The Python SQL Toolkit and Object Relational Mapper
>  
> http://www.sqlalchemy.org/
>  
> To post example code, please provide an MCVE: Minimal, Complete, and 
> Verifiable Example. See http://stackoverflow.com/help/mcve for a full 
> description.
> --- 
> You received this message because you are subscribed to the Google Groups 
> "sqlalchemy" group.
> To unsubscribe from this group and stop receiving emails from it, send an 
> email to sqlal...@googlegroups.com.
> To view this discussion on the web visit 
> https://groups.google.com/d/msgid/sqlalchemy/143c780c-2e3a-4634-84fb-537363f95051%40googlegroups.com
>  
> <https://groups.google.com/d/msgid/sqlalchemy/143c780c-2e3a-4634-84fb-537363f95051%40googlegroups.com?utm_medium=email&utm_source=footer>
> .
>
>
>
> --
> SQLAlchemy - 
> The Python SQL Toolkit and Object Relational Mapper
>  
> http://www.sqlalchemy.org/
>  
> To post example code, please provide an MCVE: Minimal, Complete, and 
> Verifiable Example. See http://stackoverflow.com/help/mcve for a full 
> description.
> --- 
> You received this message because you are subscribed to the Google Groups 
> "sqlalchemy" group.
> To unsubscribe from this group and stop receiving emails from it, send an 
> email to sqlal...@googlegroups.com <javascript:>.
> To view this discussion on the web visit 
> https://groups.google.com/d/msgid/sqlalchemy/928134ab-5711-468d-87b4-606fd6e942b3%40googlegroups.com
>  
> <https://groups.google.com/d/msgid/sqlalchemy/928134ab-5711-468d-87b4-606fd6e942b3%40googlegroups.com?utm_medium=email&utm_source=footer>
> .
>
>
>

-- 
SQLAlchemy - 
The Python SQL Toolkit and Object Relational Mapper

http://www.sqlalchemy.org/

To post example code, please provide an MCVE: Minimal, Complete, and Verifiable 
Example.  See  http://stackoverflow.com/help/mcve for a full description.
--- 
You received this message because you are subscribed to the Google Groups 
"sqlalchemy" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to sqlalchemy+unsubscr...@googlegroups.com.
To view this discussion on the web visit 
https://groups.google.com/d/msgid/sqlalchemy/7871e581-75fc-41fe-95c1-43c2e53e6c28%40googlegroups.com.

Reply via email to