Невозможно связать правильные идентификаторы с помощью обратного отношения ManyToMany

Я пытаюсь объединить две модели, которые связаны через поле ManyToMany. В основном я хочу установить обратную связь между моделью "Должность" и моделью "Продажа".

Каждая продажа может иметь несколько позиций, но каждая позиция должна быть специфична для своей продажи.

Вот что происходит. Я фильтрую по датам, по которым я знаю, что есть данные (продажи), и получаю:

sales_df | | sales_id | transaction_id | total_price | customer |

|0| 11 | 3B6374D5ED85 | 300.0 | Test |

|1| 12 | D52E5123EDBE | 900.0 | Test |

(я намеренно удалил "created" и "updated" из этого примера, потому что они не очень хорошо вписываются сюда)

positions_df | | sales_id | quantity | price | sales_id |

|0| 10 | 3 | 300.0 | 11 |

|1| 10 | 3 | 300.0 | 11 |

|2| 11 | 1 | 600.0 | 12 |

WHEN positions_df sales_id should be =>

| | sales_id | quantity | price | sales_id |

|0| 10 | 3 | 300.0 | 11 |

|1| 10 | 3 | 300.0 | 12 |

|2| 11 | 1 | 600.0 | 12 |

Похоже, что когда я получаю sale_id в обратном порядке через метод "get_sales_id()", он ассоциирует его с первым экземпляром позиции, вместо того чтобы установить приоритет sale_id

Вот код:

models.py

from django.db import models
from products.models import Product
from customers.models import Customer
from profiles.models import Profile
from django.utils import timezone
from .utils import generate_code
from django.shortcuts import reverse

# Create your models here.

class Position(models.Model):
    product = models.ForeignKey(Product, on_delete=models.CASCADE)
    quantity = models.PositiveIntegerField()
    price = models.FloatField(blank=True)
    created = models.DateTimeField(blank=True)

    def save(self, *args, **kwargs):
        self.price = self.product.price * self.quantity
        return super().save(*args, **kwargs)

    def get_sales_id(self):
        sale_obj = self.sale_set.first()
        return sale_obj.id

    def __str__(self):
        return f"id: {self.id}, product: {self.product.name}, quantity: {self.quantity}"


class Sale(models.Model):
    transaction_id = models.CharField(max_length=12, blank=True)
    positions = models.ManyToManyField(Position)
    total_price = models.FloatField(blank=True, null=True)
    customer = models.ForeignKey(Customer, on_delete=models.CASCADE)
    salesman = models.ForeignKey(Profile, on_delete=models.CASCADE)
    created = models.DateTimeField(blank=True)
    updated = models.DateTimeField(auto_now=True)


    def __str__(self):
        return f"Total sales price: ${self.total_price}"

    def get_absolute_url(self):
        return reverse('sales:detail', kwargs={'pk': self.pk})

    def save(self, *args, **kwargs):
        if self.transaction_id == '':
            self.transaction_id = generate_code()
        if self.created is None:
            self.created = timezone.now()
        return super().save(*args, **kwargs)
    
    def get_position(self):
        return self.positions.all()

views.py

from .models import Sale
from .forms import SalesSearchForm
import pandas as pd
from .utils import get_customer_from_id, get_salesman_from_id

# Create your views here.

def home_view(request):
    sales_df = None
    form = SalesSearchForm(request.POST or None)
    positions_df = None
    merged_df = None
    df = None

    if request.method == 'POST':
        date_from = request.POST.get('date_from')
        date_to = request.POST.get('date_to')
        chart_type = request.POST.get('chart_type')

        sale_qs = Sale.objects.filter(created__date__lte=date_to, created__date__gte=date_from)
        if len(sale_qs) > 0:
            sales_df = pd.DataFrame(sale_qs.values())
            sales_df['customer_id'] = sales_df['customer_id'].apply(get_customer_from_id)
            sales_df['salesman_id'] = sales_df['salesman_id'].apply(get_salesman_from_id)
            sales_df['created'] = sales_df['created'].apply(lambda x: x.strftime('%Y-%m-%d'))
            sales_df.rename({'customer_id':'customer', 'salesman_id':'salesman', 'id':'sales_id'}, axis=1, inplace=True)

            positions_data = []

            for sale in sale_qs:
                for pos in sale.get_position():
                    obj = {
                        'position_id': pos.id,
                        'product': pos.product.name,
                        'quantity': pos.quantity,
                        'price': pos.price,
                        'sales_id': pos.get_sales_id(),
                    }
                    positions_data.append(obj)

            positions_df = pd.DataFrame(positions_data)
            merged_df = pd.merge(sales_df, positions_df, on='sales_id')

            df = merged_df.groupby('transaction_id', as_index=False)['price'].agg('sum')

            sales_df = sales_df.to_html()
            positions_df = positions_df.to_html()
            merged_df = merged_df.to_html()
            df = df.to_html()
        else:
            print('no data')

        
    context = {
        'form': form,
        'sales_df': sales_df,
        'positions_df': positions_df,
        'merged_df': merged_df,
        'df': df,
    }

    return render(request, 'sales/home.html', context)

Я пытался возиться с функцией "get_sales_id()" внутри класса Position, но я не могу понять, как отфильтровать ID различных объектов, если я получу их все, вместо того чтобы использовать метод "first()".

Заранее большое, большое спасибо. Надеюсь, я был достаточно понятен

Вернуться на верх