我有这个模型,我可以节省应该在稍后阶段计费的费用。由于几个模型可以产生费用,我建立了一个通用关系。
class Fee(models.Model):
content_type = models.ForeignKey(ContentType, blank=True, null=True,
related_name='fees', on_delete=models.CASCADE)
object_id = models.PositiveIntegerField(null=True, blank=True, db_index=True)
content_object = GenericForeignKey()
class FeeType(models.IntegerChoices):
SALES_CREDIT = 1, 'Sales Credit'
MANAGEMENT = 2, 'Management Fee'
BROKERAGE = 3, 'Brokerage Fee'
PLATFORM = 4, 'Platform Fee'
MARKETING = 5, 'Marketing Fee'
DISCOUNT = 6, 'Discount'
NOFEE = 99, 'No Fee'
fee_type = models.IntegerField(choices=FeeType.choices)
fee_date = models.DateField(auto_now_add=True)
due_date = models.DateField(editable=False)
creditor = models.ForeignKey('users.Company', on_delete=models.CASCADE, related_name='fee_credit')
debitor = models.ForeignKey('users.Company', on_delete=models.CASCADE, related_name='fee_debit')
quantity = models.PositiveBigIntegerField()
rate = models.DecimalField(max_digits=10, decimal_places=4)
class RateType(models.IntegerChoices):
PERCENTAGE = 1, 'Percentage'
NOMINAL = 2, 'Nominal'
rate_type = models.IntegerField(choices=RateType.choices, default=1)
taxes_due = models.BooleanField(default=True)
including_taxes = models.BooleanField(default=True)
tax_rate = models.DecimalField(max_digits=4, decimal_places=2)
total_amount = models.DecimalField(max_digits=12, decimal_places=2, editable=False)
total_taxes = models.DecimalField(max_digits=12, decimal_places=2, editable=False)
total_amount_incl_taxes = models.DecimalField(max_digits=12, decimal_places=2, editable=False)
billed = models.BooleanField(default=False)
paid = models.BooleanField(default=False)
我有一个生活在芹菜任务中的函数,它准备将数据保存到所述模型中:
@shared_task
def log_fee(model, fee_type, creditor_pk, debitor_pk, quantity, rate_type, rate=None,
taxes_due=True, including_taxes=True, tax_rate=None, fee_date=None):
from fees.models import Fee
from users.models import Company
logger.info(f'{model} {fee_type} {creditor_pk} {debitor_pk} {quantity} {rate_type} {rate} {taxes_due} {including_taxes} {tax_rate}')
# Get Model Details to link to
app_label = model.get('app')
model_name = model.get('object')
model_pk = model.get('model_pk')
# Catch fee types that are strings (most likely product related)
logger.info(type(fee_type))
if type(fee_type) == str:
mapping = {'SC': 1, 'DC': 6, 'MF': 2, 'NP': 99}
fee_type = mapping.get(fee_type)
if fee_type == 99:
rate = 0.0
rate_type = 2
logger.info(f'{fee_type} {rate} {rate_type}')
# Get Object
Object = apps.get_model(app_label=app_label, model_name=model_name)
# Get Object instance
try:
target = Object.objects.get(pk=model_pk)
except Object.DoesNotExist:
target = None
logger.info(target)
# Get Involved Parties
debitor = Company.objects.get(pk=debitor_pk)
creditor = Company.objects.get(pk=creditor_pk)
logger.info(debitor)
logger.info(creditor)
# Clean Fields when fee type == 1
if fee_type == 1:
# CALCULATE AMOUNTS AND TAXES
total_amt = quantity * decimal.Decimal(rate)
logger.info(total_amt)
# Total Amount
if rate_type == 1:
total_amt = total_amt / 100
# Set Tax Rate to Companies VAT if not already set.
if not tax_rate:
tax_rate = decimal.Decimal(creditor.vat)
logger.info(tax_rate)
if taxes_due:
if including_taxes:
total_taxes = total_amt - (total_amt / (1 + (tax_rate / 100)))
total_amt = total_amt - total_taxes
else:
total_taxes = total_amt * (tax_rate / 100)
else:
total_taxes = 0.0
total_amount = round(total_amt, 2)
total_taxes = round(total_taxes, 2)
total_amount_incl_taxes = total_amount + total_taxes
# SET DUE DATE
if not fee_date:
fee_date = timezone.now().date()
due_date = utils.get_valid_shifted_date(fee_date, days=creditor.payment_term)
# Save Fee
fee = Fee(content_object=target, fee_type=fee_type, creditor=creditor, debitor=debitor,
quantity=quantity, rate=rate, rate_type=rate_type, taxes_due=taxes_due,
including_taxes=including_taxes, tax_rate=tax_rate, due_date=due_date,
total_amount=total_amount, total_taxes=total_taxes, total_amount_incl_taxes=total_amount_incl_taxes)
try:
with transaction.atomic():
fee.save()
except Exception as e:
logger.info(e)
如果我尝试使用 transaction.atomic() 保存模型,我会收到一条错误消息,说明'NoneType' object has no attribute 'pk'
. 如果我省略 transaction.atomic() 语句,一切都会按预期保存。我几乎尝试了一切,但到目前为止没有成功。所有输入参数都采用模型期望的格式,正如我所说,没有 transaction.atomic() 保存工作。尽管如此,忽略错误消息,我还是觉得很不舒服。
知道这里发生了什么吗?
PS:我没有在目标模型(我正在测试的模型)上设置 GenericRelation,并且在运行 makemigrations 时,GenericRelation 无论如何都没有列出(这也让我感到困惑)。
我使用 Django 3.2 版和 PostgreSQL 作为数据库。