Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Many-to-many relation, adding property from association table #787

Unanswered
kast3t asked this question in Q&A
Discussion options

Greetings,

I've 3 tables: "tasks", "services" and "assoc_tasks_services".
They contain data like this:

tasks:

task_id user_id price
... ... ...
84 1 174.25
85 1 250.25
86 1 300.00
87 1 1050.49
88 1 600.00

services:

service_id name
... ...
4 Service_1
5 Service_2
19 Service_3

assoc_tasks_services:

task_id service_id count
... ... ...
84 4 0
85 5 0
86 19 3
87 19 6
88 19 1
88 4 0

So, in "tasks" I keep tasks, which may include several services, in "services" I keep names of services, their prices, etc., and in "assoc_tasks_services" I keep associations: which task, which services and count of service (for each service it might be 0, 1, or more).

There are 2 problems:

1.) I can't use .limit() correctly. For example, I need only last 5 tasks (84-88), but when I make query, it returns 85, 86, 87, 88 and 88 (it doesn't count 2 entries of task No88 as one).

2.) How can I attach property "count" of table "assoc_tasks_services" in every service in every task?

Please, help me. I'm not good at programming, but I'm trying to understand how can I realize it. Thank you!

Code of initialisation of tables:

class Service(db.Model):
 __tablename__ = 'services'
 service_id = db.Column(db.Integer, autoincrement=True, primary_key=True, nullable=False)
 name = db.Column(db.String, nullable=False)
 price = db.Column(db.Numeric(7, 2))
 def __init__(self, **kw):
 super().__init__(**kw)
 self._tasks = set()
 self._count = set()
 @property
 def tasks(self):
 return self._tasks
 @property
 def count(self):
 return self._count
 def add_count(self, count):
 self._count.add(count)
class Task(db.Model):
 __tablename__ = 'tasks'
 task_id = db.Column(db.Integer, autoincrement=True, primary_key=True)
 user_id = db.Column(db.BigInteger, db.ForeignKey('clients.user_id', ondelete='CASCADE'), nullable=False)
 price = db.Column(db.Numeric(7, 2))
 def __init__(self, **kw):
 super().__init__(**kw)
 self._services = set()
 self._count = set()
 @property
 def services(self):
 return self._services
 def add_service(self, service):
 self._services.add(service)
 service._tasks.add(self)
 @property
 def count(self):
 return self._count
 def add_count(self, count):
 self._count.add(count)
class AssocTasksServices(db.Model):
 __tablename__ = 'assoc_tasks_services'
 task_id = db.Column(db.Integer, db.ForeignKey('tasks.task_id', ondelete='CASCADE'), nullable=False)
 service_id = db.Column(db.Integer, db.ForeignKey('services.service_id', ondelete='CASCADE'), nullable=False)
 count = db.Column(db.Integer, nullable=False)

Attempt No1 (added property "count" to task. It's the most successful attempt):

async def get_users_tasks(user_id: int) -> List[Task]:
 query = Task.outerjoin(AssocTasksServices, Task.task_id == AssocTasksServices.task_id). \
 outerjoin(Service, AssocTasksServices.service_id == Service.service_id). \
 select().where(Task.user_id == user_id).order_by(Task.task_id.desc()).limit(5)
 tasks_loader = Task.distinct(Task.task_id).load(add_service=Service.distinct(Service.service_id),
 add_count=AssocTasksServices.count))
 tasks = await query.gino.load(tasks_loader).all()
 return tasks

Printing result No1:

tasks = await get_users_tasks(1)
for task in tasks:
 for service in task.services:
 print(f'Task No{task.task_id} - {service.name}. Count: {task.count}')

It returns:

Task No88 - Service_3. Count: {0, 1} # But I need Count: {1}, not {0, 1}, because count of Service_3 is 1 for Task No88 according to the table
Task No88 - Service_1. Count: {0, 1} # But I need Count: {0}, not {0, 1}, because count of Service_1 is 0 for Task No88 according to the table
Task No87 - Service_3. Count: {6} # Correct
Task No86 - Service_3. Count: {3} # Correct
Task No85 - Service_2. Count: {0} # Correct

Attempt No2 (added property "count" to service):

async def get_users_tasks(user_id: int) -> List[Task]:
 query = Task.outerjoin(AssocTasksServices, Task.task_id == AssocTasksServices.task_id). \
 outerjoin(Service, AssocTasksServices.service_id == Service.service_id). \
 select().where(Task.user_id == user_id).order_by(Task.task_id.desc()).limit(5)
 tasks_loader = Task.distinct(Task.task_id).load(add_service=Service.distinct(Service.service_id).load(
 add_count=AssocTasksServices.count))
 tasks = await query.gino.load(tasks_loader).all()
 return tasks

Printing result No2:

tasks = await get_users_tasks(1)
for task in tasks:
 for service in task.services:
 print(f'Task No{task.task_id} - {service.name}. Count: {service.count}')

It returns:

Task No88 - Service_3. Count: {1, 3, 6} # But I need Count: {1}, not {1, 3, 6}, because count of Service_3 is 1 for Task No88 according to the table
Task No88 - Service_1. Count: {0} # Correct
Task No87 - Service_3. Count: {1, 3, 6} # Incorrect
Task No86 - Service_3. Count: {1, 3, 6} # Incorrect
Task No85 - Service_2. Count: {0} # Correct
You must be logged in to vote

Replies: 0 comments

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Category
Q&A
Labels
None yet
1 participant

AltStyle によって変換されたページ (->オリジナル) /