Doctrine 2 multi-level inheritance - how to define the join - doctrine-orm

I have two tables:
Email:
id message
1 This is an email message
Activity:
id related_id related_type
66 1 email
72 1 booking
74 55 booking
In a query builder I want to join Email.id to Activity.related_id only if related_type is 'email'.
I therefore have Entity Activity:
/**
* Activity
*
* #ORM\Table(name="activity")
* #ORM\Entity
* #ORM\InheritanceType("JOINED")
* #ORM\DiscriminatorColumn(name="related_type", type="string")
* #ORM\DiscriminatorMap( {"email" = "Email"} )
*/
class Activity
And Entity Email:
/**
* Email
*
* #ORM\Table(name="email", indexes={#ORM\Index(name="contact_id_index", columns={"contact_id"})})
* #ORM\Entity(repositoryClass="Cinolla\ApiBundle\Entity\EmailRepository")
*/
class Email extends Activity
However, looking at the query that doctrine is generating at the moment, it's doing:
FROM email t0 INNER JOIN activity t1 ON t0.id = t1.id
Whereas it should be doing:
FROM email t0 INNER JOIN activity t1 ON t1.related_id = t0.id AND t1.related_type = 'email'
Where do I define that Email should be joined on related_id?
Why has it not included the AND t1.related_type = 'email'?

Related

Django ORM. Joining subquery on condition

I have a table TickerStatement, which contains financial statements about companies
class Statements(models.TextChoices):
"""
Supported statements
"""
capital_lease_obligations = 'capital_lease_obligations'
net_income = 'net_income'
price = 'price'
total_assets = 'total_assets'
short_term_debt = 'short_term_debt'
total_long_term_debt = 'total_long_term_debt'
total_revenue = 'total_revenue'
total_shareholder_equity = 'total_shareholder_equity'
class TickerStatement(TimeStampMixin):
"""
Model that represents ticker financial statements
"""
name = models.CharField(choices=Statements.choices, max_length=50)
fiscal_date_ending = models.DateField()
value = models.DecimalField(max_digits=MAX_DIGITS, decimal_places=DECIMAL_PLACES)
ticker = models.ForeignKey(Ticker, on_delete=models.CASCADE, null=False,
related_name='ticker_statements')
And now I'm trying to calculate a multiplier. The formula looks like:
(short_term_debt + total_long_term_debt) / total_shareholder_equity
I wrote a raw SQL query
SELECT "fin_tickerstatement"."fiscal_date_ending",
t2.equity AS "equity",
value AS "debt",
short_term_debt AS "short_term_debt",
(value + short_term_debt) / t2.equity AS "result"
FROM "fin_tickerstatement"
JOIN
(SELECT "fin_tickerstatement"."fiscal_date_ending",
fin_tickerstatement.value AS "equity"
FROM "fin_tickerstatement"
WHERE ("fin_tickerstatement"."ticker_id" = 12
AND "fin_tickerstatement"."fiscal_date_ending" >= date'2015-09-03'
AND "fin_tickerstatement"."name" = 'total_shareholder_equity')
GROUP BY "fin_tickerstatement"."fiscal_date_ending",
fin_tickerstatement.value
ORDER BY "fin_tickerstatement"."fiscal_date_ending" DESC) t2
ON fin_tickerstatement.fiscal_date_ending = t2.fiscal_date_ending
JOIN
(SELECT "fin_tickerstatement"."fiscal_date_ending",
fin_tickerstatement.value AS "short_term_debt"
FROM "fin_tickerstatement"
WHERE ("fin_tickerstatement"."ticker_id" = 12
AND "fin_tickerstatement"."fiscal_date_ending" >= date'2015-09-03'
AND "fin_tickerstatement"."name" = 'short_term_debt')
GROUP BY "fin_tickerstatement"."fiscal_date_ending",
fin_tickerstatement.value
ORDER BY "fin_tickerstatement"."fiscal_date_ending" DESC) t3
ON fin_tickerstatement.fiscal_date_ending = t3.fiscal_date_ending
WHERE ("fin_tickerstatement"."ticker_id" = 12
AND "fin_tickerstatement"."fiscal_date_ending" >= date'2015-09-03'
AND "fin_tickerstatement"."name" = 'total_long_term_debt')
GROUP BY "fin_tickerstatement"."fiscal_date_ending",
equity,
debt,
short_term_debt
ORDER BY "fin_tickerstatement"."fiscal_date_ending" DESC;
and have no idea how to translate it into Django ORM. Maybe you have some ideas or know some Django plugins that can help me.
The only way to solve this problem is to install django-query-builder.

Django m2m produce Unnecessary inner join, that change SQL result

Django 2.1.4 (the like behavior exist on 2.0.4 too)
Models:
class Application(models.Model):
# many fileds
name = models.CharField(max_length=255)
seers = models.ManyToManyField('Agency', through='ApplicationAgencySeer')
parent = models.ForeignKey("self", null=True, blank=True, on_delete=SET_NULL)
class ApplicationAgencySeer(models.Model):
application = models.ForeignKey(Application, on_delete=models.CASCADE)
agency = models.ForeignKey('Agency', on_delete=models.CASCADE)
created = models.DateTimeField(auto_now_add=True)
now I wanna filter
# count 0
Application.objects.filter(seers__agency__id='c3e5ed58-a4d9-4ca6-a8f7-6793eb8e3e24').count() # 0
# but count 1
ApplicationAgencySeer.objects.filter(agency__id='c3e5ed58-a4d9-4ca6-a8f7-6793eb8e3e24').count() # 1
SELECT *
FROM "app_application"
INNER JOIN "myapp_applicationagencyseer"
ON ("app_application"."id" = "app_applicationagencyseer"."application_id")
INNER JOIN "myapp_agency"
ON ("app_applicationagencyseer"."agency_id" = "app_agency"."organization_ptr_id")
INNER JOIN "myapp_agency" T4 ON ("app_agency"."organization_ptr_id" = T4."parent_id")
WHERE T4."organization_ptr_id" = 'c3e5ed58-a4d9-4ca6-a8f7-6793eb8e3e24'
if remove INNER JOIN "myapp_agency" T4 ON ("app_agency"."organization_ptr_id" = T4."parent_id") all be right.
WHY parent_id why-why
I found the bug, maybe it some related <djangoproject> but 6 years ago. I think it already fixes before 2.1.4 release.
How to me compose right filter query, or avoid this situation. help me I am stuck.
SELECT *
FROM "myapp_application"
WHERE NOT ("myapp_application"."id" IN (SELECT U1."application_id"
FROM "myapp_applicationagencyseer" U1
INNER JOIN "myapp_agency" U2 ON (U1."agency_id" = U2."organization_ptr_id")
INNER JOIN "myapp_agency" U3 ON (U2."organization_ptr_id" = U3."parent_id")
WHERE U3."organization_ptr_id" = '9e71cff4-443d-4c60-ac2d-9dcca2a9c147'))
ORDER BY "myapp_application"."created_date" DESC;
result
application_id
7d83d056-5a7d-4095-9037-98bde29a3d78 otherfields..
7cb60afc-109d-4570-ad24-6cad6b7ddd9a otherfields.. <-- this row error
--return 0
(SELECT U1."application_id"
FROM "myapp_applicationagencyseer" U1
INNER JOIN "myapp_agency" U2 ON (U1."agency_id" = U2."organization_ptr_id")
INNER JOIN "myapp_agency" U3 ON (U2."organization_ptr_id" = U3."parent_id")
WHERE U3."organization_ptr_id" = '9e71cff4-443d-4c60-ac2d-9dcca2a9c147')
--althouth I have myapp_applicationagencyseer
id created agency_id application_id status
1 2018-12-10 17:41:14.272684 9e71cff4-443d-4c60-ac2d-9dcca2a9c147 7cb60afc-109d-4570-ad24-6cad6b7ddd9a 1
2 2018-12-11 19:25:58.818000 9e71cff4-443d-4c60-ac2d-9dcca2a9c147 7cb60afc-109d-4570-ad24-6cad6b7ddd9a 0
-- myapp_agency
organization_ptr_id accreditation parent
aff44d42-ce81-4c3e-b6e1-056ed9351adb Null Null
9e71cff4-443d-4c60-ac2d-9dcca2a9c147 10АА71 Null <-- It have Null parent

convert sql query form to django orm

I Have a models like this :
class Person(models.Model):
person_id=models.AutoField(primary_key=True)
person_name=models.CharField(max_length=100)
person_family=models.CharField(max_length=100)
person_father=models.ForeignKey('Person', related_name='child_from_father',null=True)
person_mother=models.ForeignKey('Person', related_name='child_from_mother',null=True)
def __str__(self):
return self.person_family
class Car(models.Model):
car_id=models.AutoField(primary_key=True)
car_name=models.CharField(max_length=100)
car_owner=models.ForeignKey(Person)
def __str__(self):
return self.car_name
there is some query that i want the orm form :
1: select person_name from Person
2: select *
from Person,Car
where car_owner=person_id
3: select *
from Person,Car
group_by(person_name)
4: select *
from Person,Car
where name like %x%
group_by(person_name)
having car_id >= 2
and at last do u know any good refrence for orm
thx for help
I'm assuming the group by is for ordering. If you really want group_by look at aggregates and annotate in django. My guess of what you are looking for is:
1: Get the person record - select person_name from Person
person = Person.objects.get(<WHERE clause>).values('person_name')
2: select *
from Person,Car
where car_owner=person_id
Get the cars belonging to the person
cars = Car.objects.filter(car_owner = person)
3: select *
from Person,Car
group_by(person_name)
Get list of cars sorted by owner
car_list = Car.objects.all().order_by('car_owner__person_name')
4: select *
from Person,Car
where name like %x%
group_by(person_name)
having car_id >= 2
List of cars with search criteria
car_list = Car.objects.filter(id__gte = 2, car_name__contains = "<search>").order_by('car_owner__person_name',)
Cars and their Owners
car_list = Car.objects.all().values('car_name','car_owner__person_name')

Django Validate M2M Form Save

I am trying to creating cron application my model look like :
class Crontab(models.Model):
#Some filelds
...
...
#m2m fields From here prob starts
minute = models.ManyToManyField(Mst_Cron_Minute, db_table="crontab_minute_map")
hour = models.ManyToManyField(Mst_Cron_Hour, db_table = "crontab_hour_map")
day_of_month = models.ManyToManyField(Mst_Cron_Day_Of_Month, db_table="crontab_day_of_month_map")
month = models.ManyToManyField(Mst_Cron_Month, db_table="crontab_month_map")
day_of_week = models.ManyToManyField(Mst_Cron_Day_Of_Week, db_table="crontab_day_of_week_map")
description = models.CharField(max_length=250, blank=True)
is_active = models.IntegerField(choices=YES_NO_CHOICES)
reason_for_deactivate = models.CharField(max_length=250, blank=True)
I need to validate the cron before it saves it into database.
Should not have duplicate cron data saved on this model.
if already a data in db say 5 1 * * * then for new record in the position of * none of the value allowed.
Example 5 1 * * 1 or 5 1 * 1 * or 5 1 1 1 1 not allowed.
if i have a data data 5 1 * 1 * is in DB the new data * 1 * 1 * or 5 * * 1 * ... not allowed, it mean if there is a digit in the position the * not allowed.
How can i validate this ? where my code should go ? Please help me .

Doctrine2 OneToMany count

I have two entities: User and Comment.
In User have:
/**
* #ORM\OneToMany(targetEntity="Comment", mappedBy="User", cascade={"persist", "remove"})
* #ORM\OrderBy({"sort_priority" = "ASC"})
*/
private $Comments;
In my custom class I have query:
$query = 'SELECT u from BackendUserBundle:User u WHERE u.status != 0';
This query return all users but I want return user with count(Comments) >0. I cant use Join because I using iterate().
OK I found in Doctrine docs:
http://docs.doctrine-project.org/en/2.1/reference/dql-doctrine-query-language.html
createQuery('SELECT u FROM CmsUser u WHERE
SIZE(u.phonenumbers) > 1'); $users = $query->getResult();