Невозможно связать правильные идентификаторы с помощью обратного отношения 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()".
Заранее большое, большое спасибо. Надеюсь, я был достаточно понятен