I am new to programming. I am trying to create a project management site. I created a model as follows:
class Boqmodel(models.Model):
code = models.IntegerField(unique=True)
building = models.ForeignKey(building, on_delete=models.SET_NULL, null=True)
level = models.ForeignKey(level, on_delete=models.SET_NULL, null=True)
activity = models.ForeignKey(activity, on_delete=models.SET_NULL, null=True)
subactivity = models.ForeignKey(sub_activity, on_delete=models.SET_NULL, null=True)
duration = models.IntegerField()
linkactivity = models.IntegerFeild(null=True) #contains code (same as code field) which this specific code is linked to
linktype = models.CharField(max_length=300, null=True)# only two choices start or finish
linkduration = models.IntegerField(null=True)
plannedstart = models.DateField()
plannedfinish = models.DateField()
The problem is I need my planned start as a computed column. The planned column should be as follows:
if linkactivity is null, then it should take a default value 01-01-2019
if else then it should look the linkactivity in code field and then
if linktype is start, then it should specify the start date of code activity +duration
or if linktype is finish plannedfinish + duration
Example
First entry:
code=1
building=A-1
Level=L-1
Activity=Activity-1
Subactivity-Subactivity-1
duration=2
linkactivity=null
linktype=null
linkduration=null
planned start=01-01-2019(as linkactivity=null)
plannedfinish=03-01-2019(planned start+duration)
Second entry:
code=2
building=A-1
Level=L-1
Activity=Activity-2
Subactivity-Subactivity-2
duration=3
linkactivity=1
linktype=start
linkduration=1
planned start=02-01-2019(as linkactivity=1,it searches code1 ,as linktype=start,it searches startdate of code 1 it is 01-01-2019 ; finally 01-01-2019+link duration(1)=02-01-2019)
plannedfinish=05-01-2019(planned start+duration)
Any help would be really appreciated
When you call Model.objects.create() method, the django ORM implicitly calls the Model.save() method inside your model. Since, you are inheriting BoqModel from models.Model and there is no explicit BoqModel.save() method in your BoqModel, Model.objects.create() method calls the save() method from the parent class. Inside Model.save() method you can customize your model save behavior. In order to achieve your intended action, override the save() method as follows -
class Boqmodel(models.Model):
code = models.IntegerField()
building = models.ForeignKey(building, on_delete=models.SET_NULL, null=True)
level = models.ForeignKey(level, on_delete=models.SET_NULL, null=True)
activity = models.ForeignKey(activity, on_delete=models.SET_NULL, null=True)
subactivity = models.ForeignKey(sub_activity, on_delete=models.SET_NULL, null=True)
duration = models.IntegerField()
linkactivity = models.IntegerFeild(null=True) #contains code (same as code field) which this specific code is linked to
linktype = models.CharField(max_length=300, null=True)# only two choices start or finish
linkduration = models.IntegerField(null=True)
plannedstart = models.DateField()
plannedfinish = models.DateField()
def save(self, *args, **kwargs):
if self.linkactivity is None:
self.plannedstart = datetime.date(year=2019, month=1, day=1)
else:
boq = BoqModel.objects.get(code=self.linkactivity)
if self.linktype is not None:
if self.linktype == "start":
self.plannedstart = boq.plannedstart + datetime.timedelta(days=self.linkduration)
elif self.linktype == "finish":
self.plannedstart = boq.plannedfinish + datetime.timdelta(days=self.linkduration)
else:
self.plannedstart = datetime.date(year=2019, month=1, day=1)
else:
self.plannedstart = datetime.date(year=2019, month=1, day=1)
self.plannedfinish = self.plannedstart + datetime.tiemdelta(days=self.linkduration)
super(BoqModel, self).save(*args, **kwargs)
The above is not optimized. But you get the general idea of how to do it. Also learn more about overriding predefined model methdos here.
Related
I am trying to adapt the Viewflow Dynamicsplit example
The objective is to split approvals of an Order based on OrderLines and to assign them to the appropriate approver. It seems that this should be possible as there seems to be a possibility described in this answer - Assign user to tasks automatically (Viewflow, Django)
The issue is that whenever I try to grab the current order pk in the DynamicSplitActivation - the queryset comes back empty. Not sure where I am going wrong. The queryset works fine if I set the pk manually, but as soon as I try to use a dynamic variable it stops working.
I have listed the flow and models etc. at the end of the post, however, I am guessing the issue is quite basic. Any help would be appreciated!
nodes.py
...
class DynamicSplitActivation(AbstractGateActivation):
def calculate_next(self):
self._order = self.flow_task._order_callback(self.process)
order_id = self._order.pk
# order_id = 28
order_lines = models.OrderLine.objects.filter(order_id=order_id)
project_lines = project_models.ProjectLine.objects.filter(orderline__in=order_lines)
users = User.objects.filter(projectline__in=project_lines).distinct()
self._approvers = users
...
class DynamicSplit(...):
...
def __init__(self, callback):
super(DynamicSplit, self).__init__()
self._order_callback = callback
self._ifnone_next_node = None
...
flows.py
...
approval_split = (
nodes.DynamicSplit(lambda act: act.order)
.IfNone(this.end)
.Next(this.split_approval_budget)
)
models.py
...
class ProjectLine(models.Model):
project = models.ForeignKey(Project, on_delete=models.CASCADE)
description = models.CharField(max_length=50)
budget_holder = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.SET_NULL, null=True, blank=True)
class Order(models.Model):
description = models.CharField(max_length=30)
class OrderLine(models.Model):
order = models.ForeignKey(Order, on_delete=models.CASCADE)
project_line = models.ForeignKey(project_models.ProjectLine, on_delete=models.SET_NULL, null=True, blank=False)
product = models.ForeignKey(catalogue_models.Product, on_delete=models.CASCADE)
quantity = models.PositiveIntegerField()
budgetholder_approved = models.BooleanField(null=True)
class OrderProccess(Process):
order = models.ForeignKey(Order, blank=True, null=True, on_delete=models.CASCADE)
...
As I am new to Django I am practicing building a money-saving app. In the app, I want to create model attributes from my current model input. The user-created model fields look like this:
class Items(models.Model):
user = models.ForeignKey(Profile, on_delete=models.CASCADE, null=True, blank=True)
item_name = models.CharField(max_length=200, null=False, blank=False, default='Enter name')
item_category = models.ForeignKey(Categories, null=True, blank=True, on_delete=models.SET_NULL)
item_created_at = models.DateTimeField(auto_now_add=True, null=True, blank=False)
item_start_date = models.DateField(null=True, blank=False)
item_end_date = models.DateField(null=True, blank=False)
item_purchase_price = models.FloatField(null=True, blank=False)
item_rest_value = models.FloatField(null=True, blank=False)
def __str__(self):
return self.item_name
Using four of these fields (item_start_date, item_end_date, item_purchase_price, item_rest_value) I want to calculate several things.
Save goal (purchase price - rest value)
Save period in days (end date - start date)
Days passed (end_date - current_date)
I tried this doing the below:
def __init__(self, item_name, item_start_date, item_end_date, item_purchase_price, item_rest_value):
self.item_name = item_name
self.item_start_date = item_start_date
self.item_end_date = item_end_date
self.item_purchase_price = item_purchase_price
self.item_rest_value = item_rest_value
def get_saving_goal(self, item_purchase_price, item_rest_value):
return self.item_purchase_price - self.item_rest_value
def get_date_delta(self, item_end_date, item_start_date):
return self.item_end_date - self.item_start_date
def get_days_passed(self, ):
from datetime import date
today = date.today()
return today - self.item_start_date ## probably will need something like a datediff function
Question 1: However, when I add these methods below the model fields, it shows this error. How do I solve this?
init() takes 6 positional arguments but 10 were given
Question 2: Beside the error, I am wondering how I can use these methods as a field. In other words, how can I use the method's outcomes in the same way as the model fields?
In the end I solved it like this (overwriting the save() function):
def save(self, *args, **kwargs):
self.item_saving_goal = self.item_purchase_price - self.item_rest_value
self.item_date_delta = (self.item_end_date.year - self.item_start_date.year) * 12 + ( self.item_end_date.month - self.item_start_date.month )
self.item_days_passed = (date.today().year - self.item_start_date.year) * 12 + ( date.today().month - self.item_start_date.month )
self.item_currently_saved = self.item_saving_goal * (self.item_days_passed / self.item_date_delta )
self.item_percentage_saved = self.item_currently_saved / self.item_saving_goal * 100
self.item_monthly_saving = self.item_saving_goal / self.item_date_delta
super().save(*args, **kwargs)
Hi I need someone's advice.
I created a form add organizations and a form to edit organizations. These are working fine.
However, I have Last Updated By and Update Date fields on the model - These are not picking up the datetime and user information when editing the organization.
views.py
#login_required()
def organization_edit(request, pk):
org = Organization.objects.get(org_id=pk)
form = OrganizationEditForm(instance=org)
# Update Org
if request.method == 'POST':
form = OrganizationEditForm(request.POST, instance=org)
if form.is_valid():
form.organization_code = form.cleaned_data['organization_code']
form.company_name = form.cleaned_data['company_name']
form.legal_name = form.cleaned_data['legal_name']
form.business_registration_no = form.cleaned_data['business_registration_no']
form.vat_registration_no = form.cleaned_data['vat_registration_no']
form.industry_distribution = form.cleaned_data['industry_distribution']
form.industry_education = form.cleaned_data['industry_education']
form.industry_healthcare = form.cleaned_data['industry_healthcare']
form.industry_manufacturing = form.cleaned_data['industry_manufacturing']
form.industry_retail = form.cleaned_data['industry_retail']
form.industry_services = form.cleaned_data['industry_services']
form.effective_start_date = form.cleaned_data['effective_start_date']
form.effective_end_date = form.cleaned_data['effective_end_date']
org = form.save(commit=False)
org.last_updated_by = request.user
org.save()
return redirect('organizations_settings')
context = {
'form':form,
'org':org,
}
return render(request, 'settings/edit_organization.html', context)
models.py
class Organization(models.Model):
org_id = models.CharField(primary_key=True, max_length=7, default=org_id_generate, editable=False)
organization_code = models.CharField(max_length=20)
company_name = models.CharField(verbose_name="Company Name", max_length=60)
legal_name = models.CharField(verbose_name="Legal Name", max_length=100)
industry_distribution = models.BooleanField(verbose_name="Distribution", default=False)
industry_education = models.BooleanField(verbose_name="Education", default=False)
industry_healthcare = models.BooleanField(verbose_name="Healthcare", default=False)
industry_manufacturing = models.BooleanField(verbose_name="Manufacturing", default=False)
industry_retail = models.BooleanField(verbose_name="Retail", default=False)
industry_services = models.BooleanField(verbose_name="Services", default=False)
business_registration_no = models.CharField(verbose_name="Business Registration Number", max_length=15, blank=True)
vat_registration_no = models.CharField(verbose_name="VAT Registration Number", max_length=15, blank=True)
created_date = models.DateTimeField(default=datetime.now)
created_by = models.ForeignKey(User, on_delete=models.DO_NOTHING, related_name="Created_By", verbose_name="Created By")
effective_start_date = models.DateField(auto_now_add=False)
effective_end_date = models.DateField(auto_now_add=False, blank=True, null=True)
update_date = models.DateTimeField(default=datetime.now)
last_updated_by = models.ForeignKey(User, on_delete=models.DO_NOTHING, related_name="Last_Updated_By", verbose_name="Last Updated By")
def __str__(self):
return self.company_name
Any help appreciated!
You might have mistaken on how default value works in this case.
Your updated_datefield is kind of working while creating the row for the first time because of the dynamic default value datetime.now(). But it won't be automatically updated automatically later on. For this use I'd advise you to use DateTimeField with auto_now_add and auto_now set to True respectfully:
created_date = models.DateTimeField(auto_now_add=True)
modified_date = models.DateTimeField(auto_now=True)
https://docs.djangoproject.com/en/3.1/ref/models/fields/#datefield
This way you won't need to update those values manually.
Sidenote: Those values are False by default so you don't need to specify auto_now_add=False.
Sadly I don't see why updating the last_updated_by field is not working properly if the Organization editing is otherwise working as intended. Changing the modified_date to work and trying again could be a good test to see if the Organization instance at hand is actually updated properly.
I have 3 models Product, Photo, and ProductLikeDilike. I am performing left outer join on all the 3 models. First I am joining Product with Photo and then the resultant table(temp) I am joining with ProductLikeDilike. Below is the raw sql.
Note: olx is the name of django app.
data = Product.objects.raw('select * from (select
olx_product.id,olx_product.name,olx_photo.file,olx_photo.cover_photo_flag
from olx_product left outer join olx_photo on
(olx_product.id=olx_photo.reference_id_id) where
olx_photo.cover_photo_flag="yes" or olx_photo.cover_photo_flag is null) as
temp left outer join olx_productlikedislike on
(temp.id=olx_productlikedislike.product_id_id and
olx_productlikedislike.product_liked_by_id_id=2)')
for x in data:
print(x.name)
What I want to understand that when I use any of the above 3 models to run the raw sql why I am getting the same result i.e.
When I do
data = Product.objects.raw('select *.....')
for x in data:
print(x.name)
or
data = Photo.objects.raw('select *......')
for x in data:
print(x.name)
or
data = ProductLikeDislike.raw('select *.....')
for x in data:
print(x.name)
I am getting the same result. Why?
Please help me to understand this.
Below is the models.py file
from django.db import models
from django.urls import reverse
from django.dispatch import receiver
from django.contrib.auth.models import User
class Product(models.Model):
category = models.ForeignKey(Category ,on_delete=models.CASCADE)
name = models.CharField(max_length = 200, db_index = True)
slug = models.SlugField(max_length = 200, db_index = True)
description = models.TextField(blank = True)
price = models.DecimalField(max_digits = 10, decimal_places = 2 )#Not used FloatField to avoid rounding issues
created = models.DateTimeField(auto_now_add=True)
updated = models.DateTimeField(auto_now=True)
contact= models.BigIntegerField(default=None,blank=True, null=True)
created_by = models.CharField(max_length = 200, default=None,blank=True, null=True)
uploaded_by_id = models.IntegerField(default=0)
status = models.IntegerField(default=0) # 0-->Active,1-->Inactive
mark_as_sold = models.IntegerField(default=0) # 0-->not sold,1-->sold
def get_absolute_url(self):
return reverse('olx:edit_product', kwargs={'pk': self.pk})
class Meta:
ordering = ('-created',)
index_together = (('id','slug'),)# we want to query product by id and slug using together index to improve performance
def __str__(self):
return self.name
class Photo(models.Model):
reference_id = models.ForeignKey(Product, null=True,on_delete=models.CASCADE)
photo_type = models.CharField(max_length = 70, db_index = True)
file = models.FileField(upload_to='photos/',default='NoImage.jpg')
cover_photo_flag = models.CharField(default=0,max_length = 5, db_index = True)
uploaded_at = models.DateTimeField(auto_now_add=True)
uploaded_by_id = models.IntegerField(default=0)
status = models.IntegerField(default=0) # 0-->Active,1-->Inactive
class Meta:
ordering = ('-uploaded_at',)
class ProductLikeDislike(models.Model):
product_id = models.ForeignKey(Product,models.SET_DEFAULT,default=0)
product_liked_by_id = models.ForeignKey(User,models.SET_DEFAULT,default=0)
status = models.BooleanField(default=False)
And Please also show me how to write it in pure Django way if possible?
I am getting the same result. Why? Please help me to understand this.
Because .raw(..) [Django-doc] just takes a raw query and executes it. The model from which the raw is performed is irrelevant.
We can generate a query that looks like:
from django.db.models import Q
Product.objects.filter(
Q(photo__photo_flag__isnull=True) | Q(photo__photo_flag='yes'),
Q(likedislike__product_liked_by_id_id=2)
)
So here we accept all Products for which a related Photo object has a flag that is NULL (this also happens in case the JOIN does not yield any flags), or the photo_flag is 'yes'). Furthermore there should be a Likedislike object where the liked_by_id_id is 2.
Note that usually a ForeignKey [Django-doc] has no _id suffix, or id_ prefix. It is also a bit "odd" that you set a default=0 for this, especially since most databases only assign strictly positive values as primary keys, and it makes no sense to inherently prefer 0 over another object anyway.
Something like this:
user_i_care_about = User.objects.get(username='user2')
productlikedislike_set = models.Prefetch('productlikedislike_set',
ProductLikeDislike.objects.select_related('product_liked_by') \
.filter(product_liked_by=user_i_care_about) \
.order_by('id'))
photo_set = models.Prefetch('photo_set', Photo.objects.all()) # this is here incase you need to a select_related()
products = Product.objects.prefetch_related(photo_set, productlikedislike_set) \
.filter(models.Q(photo__cover_photo_flag='yes') | models.Q(photo__isnull=True)) \
.filter(productlikedislike__product_liked_by=user_i_care_about)
Then you can use:
for product in products:
for pic in product.photo_set.all():
print(x.file.name)
# every product here WILL be liked by the user
if your models look something like this:
class Product(models.Model):
# category = models.ForeignKey(Category, on_delete=models.CASCADE) # TODO: uncomment, didnt want to model this out
name = models.CharField(max_length=200, db_index=True)
slug = models.SlugField(max_length=200, db_index=True)
description = models.TextField(blank=True)
price = models.DecimalField(max_digits=10, decimal_places=2) # Not used FloatField to avoid rounding issues # this is correct, no need to explain this, anyonw that works with django, gets this.
created = models.DateTimeField(auto_now_add=True)
updated = models.DateTimeField(auto_now=True)
contact = models.BigIntegerField(default=None,blank=True, null=True)
created_by = models.CharField(max_length=200, default=None, blank=True, null=True)
uploaded_by_id = models.IntegerField(default=0) # TODO: use ForeignKey(User) here!!!
status = models.IntegerField(default=0) # 0-->Active,1-->Inactive # TODO: learn to use `choices`
mark_as_sold = models.IntegerField(default=0) # 0-->not sold,1-->sold # TODO: there is something called `BooleanField` use it!
class Meta:
ordering = ('-created',)
index_together = (('id', 'slug'),) # we want to query product by id and slug using together index to improve performance
def get_absolute_url(self):
return reverse('olx:edit_product', kwargs={'pk': self.pk})
def __str__(self):
return self.name
class Photo(models.Model):
product = models.ForeignKey(Product, null=True,on_delete=models.CASCADE, db_column='reference_id')
photo_type = models.CharField(max_length=70, db_index=True)
file = models.FileField(upload_to='photos/', default='NoImage.jpg')
cover_photo_flag = models.CharField(default=0, max_length=5, db_index=True) # TODO: learn to use `choices`, and you use "yes" / "no" -- and the default is 0 -- FIX THIS!!
uploaded_at = models.DateTimeField(auto_now_add=True)
uploaded_by_id = models.IntegerField(default=0) # TODO: use ForeignKey(User) here!!!
status = models.IntegerField(default=0) # 0-->Active,1-->Inactive # TODO: learn to use `choices` -- perhaps just call this "is_active" and make it a bool
class Meta:
ordering = ('-uploaded_at',)
class ProductLikeDislike(models.Model):
product = models.ForeignKey(Product, models.SET_DEFAULT, default=0) # TODO: default=0?? this is pretty bad. models.ForeignKey(Product, models.SET_NULL, null=True) is much better
product_liked_by = models.ForeignKey(User, models.SET_DEFAULT, default=0, db_column='product_liked_by_id') # TODO: default=0?? this is pretty bad. models.ForeignKey(ForeignKey, models.SET_NULL, null=True) is much better
status = models.BooleanField(default=False) # TODO: rename, bad name. try something like "liked" / "disliked" OR go with IntegerField(choices=((0, 'Liked'), (1, 'Disliked')) if you have more than 2 values.
A full example WITH tests can be seen here: https://gist.github.com/kingbuzzman/05ed095d8f48c3904e217e56235af54a
I am currently struggling to assign a many-to-many field to my newly created objects. Anyone knows what I am doing wrong?
Note: I have one solution in mind which is first creating the ticket, and then afterwards trying to assign it. Might that be the way to do it?
#Create ticket_tax
assign_event = Event.objects.all()
for event in assign_event:
TicketTax.objects.create(
event=event,
name=lorem,
percentage=0.19,
)
# Create tickets
price_gross = ['40.60', '30.30', '100.40', ]
name = ['Early Bird', 'Regular Ticket', 'Last Minute Ticket', ]
assign_event = Event.objects.all().first()
assign_ticket_tax = TicketTax.objects.all().first()
for i in range(len(price_gross)):
Ticket.objects.create(
event=assign_event,
ticket_tax=assign_ticket_tax.add(),
price_gross=price_gross[i],
name=name[i],
description='ABC',
start_at='2018-05-26 18:12:58.556925+02',
end_at='2018-05-29 18:12:58.556925+02',
quantity=100,
status='On sale',
)
models.py
class TicketTax(models.Model):
event = models.ForeignKey(
Event,
on_delete=models.PROTECT,
related_name='ticket_taxes'
)
name = models.CharField(max_length=100)
percentage = models.DecimalField(
max_digits=5,
decimal_places=4
)
created = models.DateTimeField(auto_now_add=True)
updated = models.DateTimeField(auto_now=True)
class Ticket(models.Model):
event = models.ForeignKey(
Event,
on_delete=models.PROTECT,
related_name='tickets'
)
ticket_tax = models.ManyToManyField(TicketTax, blank=True)
price_gross = models.DecimalField(
max_digits=25,
decimal_places=2
)
name = models.CharField(max_length=100)
description = models.TextField(blank=True, null=True)
start_at = models.DateTimeField()
end_at = models.DateTimeField()
quantity = models.PositiveIntegerField()
status = models.CharField(
max_length=8,
choices=TicketStatus.CHOICES
)
is_archived = models.BooleanField(default=False)
created = models.DateTimeField(auto_now_add=True)
updated = models.DateTimeField(auto_now=True)
def __str__(self):
return self.name
Note: I have one solution in mind which is first creating the ticket, and then afterwards trying to assign it. Might that be the way to do it?
That is exactly correct. You can't instantiate an object and assign a M2M in one create statement--since both objects need to exist in the database. This inside the for loop should (roughly) do what your code above is trying to do:
ticket = Ticket.objects.create(
event=assign_event,
price_gross=price_gross[i],
name=name[i],
description='ABC',
start_at='2018-05-26 18:12:58.556925+02',
end_at='2018-05-29 18:12:58.556925+02',
quantity=100,
status='On sale',
)
ticket.ticket_tax.add(TicketTax.objects.all().first())