I am new to Django. My query is
I store some quantity of components in a table. I want to sum the quantity sorting it by components and then use the summed quantity in some other table to do further calculations. How can I achieve this..
#views.py
class PurchaseCreateView(CreateView):
model = Purchase
fields = '__all__'
success_url = reverse_lazy("purchase_form")
def get_context_data(self,**kwargs):
context = super().get_context_data(**kwargs)
context['purchases'] = Purchase.objects.all()
return context
#models.py
class Purchase(models.Model):
purchase_date = models.DateField()
invoice_no = models.CharField(max_length=200,unique=True)
supplier =models.ForeignKey(Supplier,on_delete=models.CASCADE)
components = models.ForeignKey(Components,on_delete=models.CASCADE)
quantity = models.PositiveIntegerField()
remarks = models.TextField(max_length=500,blank=True,null=True)
def __str__(self):
return str(self.pk)
# Below is the Model where I want to use the summed quantity for further calc
class IntermediateStage(models.Model):
producttype = models.ForeignKey(ProductType,on_delete=models.CASCADE)
components = models.ForeignKey(Components,on_delete=models.CASCADE)
processingstage = models.ForeignKey(ProcessingStage,on_delete=models.CASCADE)
unitsrequired = models.PositiveIntegerField()
quantity = models.PositiveIntegerField(blank = True)**#want to store summed qty here**
total_quantity = models.IntegerField(blank= True)
class Meta:
unique_together = [['producttype','components','processingstage']]
def __str__(self):
return str(self.id)
#Components Model
class Components(models.Model):
name = models.CharField(max_length=100,unique=True)
producttype = models.ManyToManyField(ProductType, through='IntermediateStage')
def __str__(self):
return self.name
Related
I have manytomanyfield inside my model.The manytomanyfield field lists the products in the products table.
I want to enter the amount for each product I choose. How can I relate manytomanyfield to floatfield field?
That's my model:
`
class TaskSources(models.Model):
id = models.AutoField(primary_key=True)
user_task_id = models.ForeignKey(UserTask,on_delete=models.CASCADE)
product_id = models.ManyToManyField(Product, verbose_name="Product",default=None)
product_amount = models.FloatField(max_length=255,verbose_name="Product Amount")
`
The form:
`
class TaskSourcesForm(forms.ModelForm):
class Meta:
model = TaskSources
fields = ['product_id', 'product_amount']
`
The views:
`
#login_required(login_url="login")
def addUserTask(request):
user_task_form = UserTaskForm(request.POST or None,initial={'user_id': request.user})
task_sources_form = TaskSourcesForm(request.POST or None)
if request.method == 'POST':
if user_task_form.is_valid():
user_task = user_task_form.save(commit=False)
user_task.author = request.user
user_task.save()
print(user_task.id)
if task_sources_form.is_valid():
task_sources = task_sources_form.save(commit=False)
task_sources.user_task_id = UserTask(id = user_task.id)
task_sources.save()
task_sources_form.save_m2m()
messages.success(request,"Task added successfully!")
return redirect(".")
context = {
"user_task_form" : user_task_form,
"task_sources_form" : task_sources_form,
}
return render(request,"user/addtask.html",context)
`
Thanks for care.
I tried associating the two fields with each other, but I could not succeed.
If I got it right I think that what you need is an intermediate table between your models. That way you can link an amount of a product to a TaskSource, something similar to this:
class Product(models.Model):
name = models.CharField(max_length=128)
def __str__(self):
return self.name
class ProductAmount(models.Model):
amount = models.FloatField(max_length=255,verbose_name="Product Amount")
product = models.ManyToManyField(Product, through='TaskSources')
def __str__(self):
return self.name
class UserTask(models.Model):
name = models.CharField(max_length=128)
def __str__(self):
return self.name
class TaskSources(models.Model):
id = models.AutoField(primary_key=True) # this is not really necessary
task = models.ForeignKey(UserTask,on_delete=models.CASCADE)
product_amount = models.ForeignKey(ProductAmount, on_delete=models.CASCADE)
This is my model:
class Car(models.Model):
make = models.CharField(max_length=30)
model = models.CharField(max_length=30)
rating = models.PositiveIntegerField(validators=[MinValueValidator(1), MaxValueValidator(5)], default=0, blank=True)
avg_rating = models.FloatField(default=0, blank=True)
rates_number = models.IntegerField(default=0, blank=True)
def __str__(self):
return self.make + ' ' + self.model
What's the best way to move the logic from the following perform_create function (in views.py) to my models?
class CarRate(generics.CreateAPIView):
serializer_class = CarRatingSerializer
queryset = Car.objects.all()
def perform_create(self, serializer):
pk = serializer.validated_data['car_id']
rating = serializer.validated_data['rating']
queryset = Car.objects.all()
car_queryset = get_object_or_404(queryset, pk=pk)
if car_queryset.rates_number == 0:
car_queryset.avg_rating = rating
else:
car_queryset.avg_rating = (car_queryset.avg_rating + rating)/2
car_queryset.avg_rating = round(car_queryset.avg_rating, 1)
car_queryset.rates_number = car_queryset.rates_number + 1
car_queryset.save()
It would be much better to create two models. Think about how you are counting average rating. This would be some better idea for now:
class Car(models.Model):
make = models.CharField(max_length=30)
model = models.CharField(max_length=30)
def rates_number(self):
return self.rates.all().count()
def avg_rating(self):
# count average_rating from relation to Rate objects and return it
return average_rating
class CarRate(models.Model):
value = models.PositiveIntegerField(validators=[MinValueValidator(1), MaxValueValidator(5)], default=0, blank=True)
car = models.ForeignKey(Car, on_delete=models.CASCADE, related_name='rates')
I am working on Django where I have two models Gigs and Orders and I am calculating average Completion time of order of every gig.
in order model I have two fields order start time (which I'm sending whenever seller accepts the order) and order completed time (which I'm sending when seller delivered) the order.
but I want to calculate average of only those orders where isCompleted = True
Models.py
class Orders(models.Model):
buyer = models.ForeignKey(User,default=None, on_delete=models.CASCADE,related_name='buyer_id')
seller = models.ForeignKey(User,default=None, on_delete=models.CASCADE,related_name='seller_id')
item = models.ForeignKey(Gigs,default=None, on_delete=models.CASCADE,related_name='gig')
payment_method= models.CharField(max_length=10)
address = models.CharField(max_length=255)
mobile = models.CharField(max_length=13,default=None)
quantity = models.SmallIntegerField(default=1)
status = models.CharField(max_length=13,default='new order')
orderStartTime = models.DateTimeField(default=timezone.now)
orderCompletedTime = models.DateTimeField(default=timezone.now)
isCompleted = models.BooleanField(default=False)
created_at = models.DateTimeField(auto_now_add=True)
class Gigs(models.Model):
title = models.CharField(max_length=255)
category = models.ForeignKey(Categories , on_delete=models.CASCADE)
images = models.ImageField(blank=True, null = True, upload_to= upload_path)
price = models.DecimalField(max_digits=6, decimal_places=2)
details = models.TextField()
seller = models.ForeignKey(User,default=None, on_delete=models.CASCADE)
#property
def average_completionTime(self):
if getattr(self, '_average_completionTime', None):
return self._average_completionTime
return self.gig.aggregate(Avg(F('orderCompletedTime') - F('orderStartTime')))
Views.py
class RetrieveGigsAPI(GenericAPIView, RetrieveModelMixin):
def get_queryset(self):
return Gigs.objects.annotate(
_average_completionTime=Avg(
ExpressionWrapper(F('gig__orderCompletedTime') - F('gig__orderStartTime'), output_field=DurationField())
)
)
serializer_class = GigsSerializerWithAvgTime
permission_classes = (AllowAny,)
def get(self, request , *args, **kwargs):
return self.retrieve(request, *args, **kwargs)
Serializers.py
class GigsSerializerWithAvgTime(serializers.ModelSerializer):
average_completionTime = serializers.SerializerMethodField()
def get_average_completionTime(self, obj):
return obj.average_completionTime
class Meta:
model = Gigs
fields = ['id','title','category','price','details','seller','images','average_completionTime']
please tell me how can I get the average of only those orders completion time where iscompleted is True
You can specify a filter to Avg to just aggregate on completed orders based on isCompleted like this:
class RetrieveGigsAPI(GenericAPIView, RetrieveModelMixin):
def get_queryset(self):
return Gigs.objects.annotate(
_average_completionTime=Avg(
ExpressionWrapper(F('gig__orderCompletedTime') - F('gig__orderStartTime'), output_field=DurationField()),
filter=Q(gig__isCompleted=True),
# ^^^ Add this
)
)
if isCompleted:
foo = Gigs.objects.annotate(_average_completionTime=Avg(
ExpressionWrapper(F('gig__orderCompletedTime') F('gig__orderStartTime'), output_field=DurationField())
)
)
return foo
I have created two models with two fields which are quantity and quantity_given, so I want to change the value of quantity field by adding the value of quantity + quantity given. For example
if quantity = 4 and quantity_given = 8
therefore the new value of quantity field will be 12.
Here are the source code for my models
class Stock(models.Model):
`name = models.CharField(max_length=30)`
def __str__(self):
return self.name
class Medicine(models.Model):
stock = models.ForeignKey(Stock, on_delete=models.CASCADE)
name = models.CharField(max_length=30)
quantity = models.IntegerField()
def __str__(self):
return self.name
class MedicineGiven(models.Model):
medicine = models.ForeignKey(Medicine, on_delete=models.CASCADE)
quantity_given = models.IntegerField()
You can have a method in MedicineGiven, like:
class MedicineGiven(models.Model):
medicine = models.ForeignKey(Medicine, on_delete=models.CASCADE)
quantity_given = models.IntegerField()
#property
def quantity(self):
return self.quantity_given + int(self.medicine.quantity)
In your views, you can get quantity of MedicineGiven like:
medicine_given = MedicineGiven.objects.get(pk=id) # Just a example code
medicine_given.quantity
EDIT
If you want to save the quantity in database, then you can override save() method:
class MedicineGiven(models.Model):
medicine = models.ForeignKey(Medicine, on_delete=models.CASCADE)
quantity_given = models.IntegerField()
def save(self, *args, **kwargs):
quantity = self.quantity_given + int(self.medicine.quantity)
self.medicine.quantity = quantity
self.medicine.save()
super().save(*args, **kwargs)
I am trying to count the number of the student according to CourseMasterModel.
I did it in MySQL, but I want to in Django.
select cn.course_name,count(st.id) from course_master
cn,semister_master sem,division_master di,student_profile st where
st.division_id = di.id and di.semister_id = sem.id and sem.course_id =
cn.id GROUP BY cn.course_name;
class CourseMasterModel(models.Model):
course_name = models.CharField(max_length=20,unique=True)
total_semister = mod`enter code here`els.SmallIntegerField()
class Meta:
db_table = "course_master"
verbose_name_plural = 'Course (Department)'
verbose_name = "Course"
def __str__(self):
return self.course_name
class SemisterMasterModel(models.Model):
semister = models.SmallIntegerField()
total_div = models.SmallIntegerField()
course = models.ForeignKey(CourseMasterModel,on_delete=models.PROTECT)
class Meta:
db_table = "Semister_master"
verbose_name_plural = 'Semister'
verbose_name = "semister"
def __str__(self):
return "%s - %d" %(self.course.course_name,self.semister)
class DevisionMasterModel(models.Model):
div_name = models.CharField(max_length=2)
semister = models.ForeignKey(SemisterMasterModel,on_delete=models.CASCADE)
class Meta:
db_table = "division_master"
verbose_name_plural = 'Division'
verbose_name = "Division"
def __str__(self):
return "%s - %s - %s"%(self.semister.course.course_name,self.semister.semister,self.div_name)
class StudentProfileModel(models.Model):
user = models.OneToOneField(User,on_delete=models.CASCADE,related_name="profile")
division = models.ForeignKey('core.DevisionMasterModel',on_delete=models.CASCADE,verbose_name="Course / Semister / Division")
roll_no = models.IntegerField()
enrollment_no = models.IntegerField(unique=True, error_messages={'unique':"This enrollment number has already been registered."})
def __str__(self):
return self.user.username
class Meta:
db_table = "Student_Profile"
You can annotate your CourseMasterModel, like:
from django.db.models import Count
CourseMasterModel.objects.annotate(
nstudents=Count('semistermastermodel__devisionmastermodel__studentprofilemodel')
)
The CourseMasterModels that arise from this QuerySet have an extra attribute .nstudents that contains the number of related StudentProfileModels.
Note: usually the names of Django models have no Model suffix, so CourseMaster instead of CourseMasterModel.
In case you rename the models, the query is:
from django.db.models import Count
CourseMasterModel.objects.annotate(
nstudents=Count('semistermaster__devisionmaster__studentprofile')
)