Django Count() multiple fields and sort by their sum - python

I have a model named Topiccenter. and there are many entries in each Topiccenter.
class Topiccenter(models.Model):
name = models.TextField()
class Book(models.Model):
tc = models.ForeignKey(Topiccenter,related_name="tc_book_entries")
name = models.TextField()
class Journal(models.Model):
tc = models.ForeignKey(Topiccenter,related_name="tc_journal_entries")
name = models.TextField()
I want to get topiccenters and sort them by max entries and min entries.
I tried
Topiccenter.objects.annotate(sum_entries=Sum('tc_book_entries','tc_journal_entries')).order_by('-sum_entries')
but this is not working

Try this -
Topiccenter.objects.annotate(
sum_books=Sum('tc_book_entries'),
sum_journals=Sum('tc_journal_entries')
).extra({
'select': {
'sum_entries': 'sum_books + sum_journals'
}
}).order_by('-sum_entries')
This should work.

Related

Django model function implementation to auto initialize a particular field's value

I need to write a Django model function to calculate the value of an existing field.
my models.py:
class questionNumeric(models.Model):
question = models.TextField()
marks = models.IntegerField()
correctAns = models.FloatField()
class questionTureFalse(models.Model):
question = models.TextField()
marks = models.IntegerField()
correctAns = models.BooleanField()
class questionSet(models.Model):
examName = models.CharField(max_length=200)
questionNumeric = models.ManyToManyField(questionNumeric)
questionTureFalse = models.ManyToManyField(questionTureFalse)
totalMarks = models.IntegerField(default=0)
As you can see here, each questionNumeric or questionTureFalse object has specific marks. Now I want to set my questionSet object's totalMarks field with- the summation of marks carried by all questionNumeric or questionTureFalse under this questionSet object.
How can I write a Django Model function under questionSet to auto initialize totalMarks?
You can declare a function in questionSet and return count of relations. For example sth like:
class QuestionSet(models.Model):
...
def get_question_numeric_count(self):
return self.questionNumeric.count()

Extract data from ORM and group by Date

I have a function which data like this :
my_workouts = Workouts.objects.groupby('my_date').filter(
my_date__year=year, my_date__month=month)
I want to do the same with another model where I want to group the weight by date:
Models.py
class Quiz(models.Model):
owner = models.ForeignKey(User, on_delete=models.CASCADE, related_name='quizzes')
scheduled_date = models.DateTimeField(max_length=255, default=0)
weight = models.IntegerField(default=0)
What I tried:
data = Quiz.objects.orderby('scheduled_date').
filter(owner_id=request.user.pk,my_date__year=year, my_date__month=month).
annotate(c=Sum('weight')).values('c')
But this is not working, Please Help!
check your syntax
orderby must be order_by
data = Quiz.objects.order_by('scheduled_date').
filter(owner_id=request.user.pk,my_date__year=year, my_date__month=month).
annotate(c=Sum('weight')).values('c')
refer this

Django order by primary key does not work

I have a model as below:
class Photos(models.Model):
id = models.IntegerField(primary_key=True, default=1)
name = models.CharField(max_length=500)
size = models.IntegerField()
path = models.CharField(max_length=500)
date = models.DateField(default=datetime.now)
def __str__(self):
return self.date.strftime('%Y-%m-%d')
class Meta:
verbose_name_plural = "Photos"
I want to retrieve the last primary key from the database (postgresql) as below:
try:
last_inserted = Photos.objects.order_by('-id')[0]
print(last_inserted)
except IndexError:
print("No data in the database")
but instead of a primary key I always get a date from the date column which is really strange! printing the last_inserted gives me '2018-09-04'.
As a test I change the 'id' column to lang (does not exists in table) gives below error message:
Cannot resolve keyword 'lang' into field. Choices are: date, id, name, path, size
in the above message why date is coming first then id and so on ..!
please help!
print(last_inserted) will show you result of model's __str__ method. To see id you can change model:
class Photos(models.Model):
id = models.IntegerField(primary_key=True, default=1)
name = models.CharField(max_length=500)
size = models.IntegerField()
path = models.CharField(max_length=500)
date = models.DateField(default=datetime.now)
def __str__(self):
return str(self.id)
class Meta:
verbose_name_plural = "Photos"
Or just change query to select only id field using values_list:
last_inserted = Photos.objects.order_by('-id').values_list('id', flat=True)[0]
print(last_inserted)
As for
in the above message why date is coming first then id and so on ..!
I suppose it because of alphabetical order.
You can also try it like this. A bit shorter
Photos.objects.order_by('-id').first().id
There is also a last()

Group Django model objects to a distinct column

I have the following Django model
class TestModel(models.Model):
company_name = models.CharField(max_length=100)
nick_name = models.CharField(max_length=100)
created_at = models.DateTimeField()
Now I want to create a query/multiple queries which will group all the TestModel objects to the particular company_name. In a nutshell it will have the following structure.
out - {
"company_name_test_1": [TestModel1, TestModel2, TestModel3],
"company_name_test_2": [TestModel4, TestModel5, TestModel6],
}
companyNames = ["a", "b", "c"]
result = {}
for name in companyNames:
result[name] = list(TestModel.objects.filter(company_name = name))
If you want to save the dictionary as JSON or something similar, the filtered models will need to be serialised first.
Also, depending on the logic of your program, it might be worth having a 'company' model, and having the TestModels as a foreign key to their respective companies.
class Company(models.Model):
name = models.CharField(max_length = 100)
# other fields and functions
class TestModel(models.Model):
company = models.ForeignKey(Company)
nick_name = models.CharField(max_length=100)
created_at = models.DateTimeField()
Then you can just filter by foreign key to get the company's testmodels:
results = {}
for company in Company.objects.all():
results[company.name] = list(company.testmodel_set.all())

Cleaning inline instances

Consider these pseudo models:
class Category(models.Model):
name = models.CharField()
class Product(models.Model):
name = models.CharField()
code = models.CharField()
category = models.ForeignKey(Category)
price = models.DecimalField()
stock = models.IntegerField()
class AlternativeProduct(Product):
original_product = models.ForeignKey(Product, related_name="alternative", editable=False)
I want to use inlines to be able to quickly add a product and its alternative option without typing duplicate data (ONLY code, stock and price differentiate).
admin.py
class AlternativeProductInline(admin.TabularInline):
model = AlternativeProduct
formset = AlternativeProductInlineFormset
fk_name = "original_product"
fields = ["code", "price", "in_stock"]
max_num = 1
extra = 0
class ProductAdmin(admin.ModelAdmin):
form = ProductAdminForm
inlines = [AlternativeProductInline]
Ofcourse this will raise ValidationError, because AlternativeProduct is missing a category.
Now I could setup a default value to fix that:
class Product(models.Model):
name = models.CharField()
code = models.CharField()
category = models.ForeignKey(Category, default=1)
price = models.DecimalField()
stock = models.IntegerField()
But besides the fact this id might not exist it still needs to be corrected. Is there any other way (besides Javascript) to copy the category value of the genuine product to the alternative inline product 'under the hood'
I have tried to change the admin_view, but it gets hackish, perhaps a custom view would be a nice solution although javascript is a less time consuming approach.
Javascript does seem to be the easy approach to achieve this.
$(document).ready(function(){
$('#alternative-group thead th:nth-child(2)').hide();
$('#alternative-group tbody td:nth-child(1) p').hide();
$('#alternative-group tbody td:nth-child(3)').hide();
$('#id_alternative-0-category').hide();
var product_category = $('#id_category option:selected').val();
$('#id_alternative-0-category').val(product_category);
$("#id_category").change(function() {
product_category = $('#id_category option:selected').val();
$('#id_alternative-0-category').val(product_category);
});
});

Categories