Django - How to get self.id instance when creating new object - python

I am working with two classes, when i save the first one it will automatic create the other one, the field called "transaction" should be filled by self.id.
But i get this error message:
NOT NULL constraint failed: portfolios_portfoliotoken.transaction_id
this is the code that i am using:
PortfolioToken.objects.create(transaction=self.id, portfolio=self.portfolio, date=self.date, total_today_brl=self.total_cost_brl+last.total_today_brl, order_value=self.total_cost_brl)
More details is possible to see below:
class Transaction(models.Model):
id = models.AutoField(primary_key=True)
date = models.DateField(("Date"), default=date.today)
portfolio = models.ForeignKey(Portfolio, on_delete=models.CASCADE, default=1)
total_cost_brl = models.FloatField(editable=False)
...
def save(self, *args, **kwargs):
self.share_cost_brl = round(self.share_cost_brl, 2)
self.total_cost_brl = round(self.shares_amount * self.share_cost_brl, 2)
...
PortfolioToken.objects.create(transaction=self.id, portfolio=self.portfolio, date=self.date, total_today_brl=self.total_cost_brl+last.total_today_brl, order_value=self.total_cost_brl)
super(Transaction, self).save(*args, **kwargs)
class PortfolioToken(models.Model):
portfolio = models.ForeignKey(Portfolio, on_delete=models.CASCADE, default=1)
transaction = models.ForeignKey(Transaction, on_delete=models.CASCADE)
total_today_brl = models.FloatField()
order_value = models.FloatField()
date = models.DateField(("Date"), default=date.today)
...

You should first call super().save(*args, **kwargs) to save the transaction, and then you can use this to construct the PortfolioToken:
class Transaction(models.Model):
# …
def save(self, *args, **kwargs):
# …
super().save(*args, **kwargs)
PortfolioToken.objects.create(
transaction_id=self.id,
portfolio=self.portfolio,
date=self.date,
total_today_brl=self.total_cost_brl+last.total_today_brl,
order_value=self.total_cost_brl
)

Related

Django QuerySet Any

I want to get a queryset of all books that are currently in Library (the dateReturn of a currently rent is set to null).
I'm new to python and i don't know how to do subqueries in django.
In other words in want to filter every related object field on a condition, if only one related-object doesn't match to this condition the object must not be returned
models.py
class Book(models.Model):
cod = models.CharField(max_length=255, unique=True)
title = models.CharField(max_length=255)
.....
class Rent(models.Model):
dateRent = models.DateField(default=timezone.now)
dateReturn = models.DateField(null=True, blank=True)
book = models.ForeignKey(modelsBook.Book, on_delete=models.DO_NOTHING, related_name="rent")
.....
P.S:
I need this subquery for display book currently not render in a choiceField
forms.py
class RentForm(forms.ModelForm):
__pk=None
def __init__(self, *args, **kwargs):
self.__pk = kwargs.pop('pk', None)
super(RentForm, self).__init__(*args, **kwargs)
class Meta():
model = models.Rent
fields = ('book', 'student')
labels = {
'book' : _('Libro'),
'student' : _('Studente'),
}
widgets = {
'book': queryset,
.....
You can filter objects through the related_name.
class RentForm(forms.ModelForm):
__pk=None
def __init__(self, *args, **kwargs):
self.__pk = kwargs.pop('pk', None)
super(RentForm, self).__init__(*args, **kwargs)
self.fields['book'].queryset = Book.objects.exclude(rent__dateReturn__isnull=True)
...

Django Foreign Key Reverse Filtering

I am still relatively new to Django and still struggle somewhat with ForeignKey filtering and I'd appreciate any help with my problem. I have 2 models below and in my PositionUpdateForm I need the 'candidate' field choices to be only the applicants to that position.
class Position(models.Model):
title = models.CharField(max_length=128)
candidate = models.ForeignKey('careers.Applicant',
on_delete=models.SET_NULL,
related_name='candidates',
blank=True,
null=True
)
class Applicant(models.Model):
first_name = models.CharField(max_length=128)
blank=False,
)
position = models.ManyToManyField(Position,
related_name='applicants',
blank=True
)
In my form I was trying each of the following:
class PositionUpdateForm(forms.ModelForm):
candidate = forms.ModelChoiceField(queryset=Applicant.objects.filter(???))
def __init__(self, *args, **kwargs):
super(PositionUpdateForm, self).__init__(*args, **kwargs)
self.fields['candidate'].queryset = Applicant.objects.filter(???)
Thank you for any assistance.
If you want to have the Applicants that have a position to that Position, you can obtain that with:
class PositionUpdateForm(forms.ModelForm):
candidate = forms.ModelChoiceField(queryset=Applicant.objects.empty())
def __init__(self, *args, **kwargs):
super(PositionUpdateForm, self).__init__(*args, **kwargs)
self.fields['candidate'].queryset = Applicant.objects.filter(position=self.instance)
or we can use the relation in reverse:
class PositionUpdateForm(forms.ModelForm):
candidate = forms.ModelChoiceField(queryset=Applicant.objects.empty())
def __init__(self, *args, **kwargs):
super(PositionUpdateForm, self).__init__(*args, **kwargs)
self.fields['candidate'].queryset = self.instance.applicants.all()
Note that you can only use this when you update a Position model, since otherwise there are no related Applicant records of course.

Django DateTimeField() casuing TypeError ('datetime.timedelta' object is not callable)

I am trying to get differenc of two Datetiemfield in Djago. I have tried overriding the default save() but still getting error.
models.py
class Sample(models.Model):
ad_start = models.DateTimeField()
ad_end = models.DateTimeField()
ad_duration = models.IntegerField()
#property
def get_time_diff(self):
timediff = self.ad_end - self.ad_start
return timediff
#return relativedelta(self.ad_end, self.ad_start)
def save(self, *args, **kwargs):
self.ad_duration = self.get_time_diff()
super(Sample, self).save(*args, **kwargs)
forms.py
class SampleForm(forms.ModelForm):
class Meta:
model = Sample
exclude = ("submitted", 'ad_duration', "list_date" )
widgets = {
'ad_start': DatePickerInput(),
'ad_end': DatePickerInput(),
}
Error
Django Version: 2.1.7
Exception Type: TypeError
Exception Value:'datetime.timedelta' object is not callable
There are two changes required in your code.
First, you need to remove #property from method get_time_diff. Because you can't call a property method via (). Or, you can still keep the property method ,but don't call it in save function, for example like this: self.ad_duration = self.get_time_diff
Second, you need to update the model field to DurationField to store the time delta object created in get_time_diff. Like this:
class Sample(models.Model):
ad_start = models.DateTimeField()
ad_end = models.DateTimeField()
ad_duration = models.DurationField()
def get_time_diff(self):
timediff = self.ad_end - self.ad_start
return timediff
def save(self, *args, **kwargs):
self.ad_duration = self.get_time_diff()
super(Sample, self).save(*args, **kwargs)
Or you can get the total seconds from get_time_diff and store it in ad_duration field(which will be a float field).
class Sample(models.Model):
ad_start = models.DateTimeField()
ad_end = models.DateTimeField()
ad_duration = models.FloatField()
def get_time_diff(self):
timediff = self.ad_end - self.ad_start
return timediff.total_seconds() # returns value in seconds

Circular Import with app models

I have an app in two different models, The error is 'cannot import name sku', which i believe is because of a circular import. How can I still reference this app.model without referencing the model import the way I am currently.
Model PurchaseOrderDetail
App Purchase_order
from product.models import InventoryTransaction
class PurchaseOrderDetail(AuditMixin, models.Model):
purchase_order = models.ForeignKey(PurchaseOrder,
on_delete=models.PROTECT)
sku = models.ForeignKey(Sku, on_delete=models.PROTECT)
qty_received = models.IntegerField(default=0, null=True, blank=True)
reason_code = models.IntegerField(default=0, null=True, blank=True)
def _get_sku_code(self):
return self.sku.sku_code
def _set_sku_code(self, value):
tenant = self.purchase_order.tenant
sku = Sku.objects.get(tenant=tenant, sku_code=value)
self.sku = sku
sku_code = property(_get_sku_code, _set_sku_code)
def calc_received(self):
# calculate sum of qty_received from inventory_transactions
sum_quantity = InventoryTransaction.objects.filter(
sku=self.sku,
po_number=self.purchase_order,
transaction_type='100'
).aggregate(
quantity_sum=Sum(F('quantity'))
)
return sum_quantity
Model Inventorytransaction
app Product
from purchase_order.models import PurchaseOrderDetail
class InventoryTransaction(models.Model):
tenant = models.ForeignKey(Tenant)
po_number = models.CharField(max_length=100)
inventory_transaction = models.ForeignKey(PurchaseOrderInventoryTransaction)
def save(self, *args, **kwargs):
super().save(*args, **kwargs)
# update the PO detail with the qty_received
obj = PurchaseOrderDetail.objects.get(
purchase_order=self.po_number,
sku=self.inventory_transaction.sku
)
obj.qty_received = obj.calc_received()
obj.save()
If you don't want this problem to appear, simply import your PurchaseOrderDetails inside your def save function.
def save(self, *args, **kwargs):
from purchase_order.models import PurchaseOrderDetail
...

how django 'auto_now' ignore the update of specified field

i have a model, like this:
name = models.CharField(max_length=255)
modify_time = models.DateTimeField(auto_now=True)
chasha = models.CharField(max_length=255)
stat = models.CharField(max_length=255)
Usually, 'modify_time' will be updated when i update 'name', 'chasha', 'stat' field. But, I just did not want the 'modify_time' been updated when i update 'stat'. how can i do that?
thanks.
Use a custom save method to update the field by looking at a previous instance.
from django.db import models
from django.utils import timezone as tz
class MyModel(models.Model):
name = models.CharField(max_length=255)
modify_time = models.DateTimeField(null=True, blank=True)
chasha = models.CharField(max_length=255)
stat = models.CharField(max_length=255)
def save(self, *args, **kwargs):
if self.pk: # object already exists in db
old_model = MyModel.objects.get(pk=self.pk)
for i in ('name', 'chasha'): # check for name or chasha changes
if getattr(old_model, i, None) != getattr(self, i, None):
self.modify_time = tz.now() # assign modify_time
else:
self.modify_time = tz.now() # if new save, write modify_time
super(MyModel, self).save(*args, **kwargs) # call the inherited save method
Edit: remove auto_now from modify_time like above, otherwise it will be set at the save method.

Categories