django: Count objects with the same value - django

Lets say I have following models:
class Book(models.Model):
name = models.CharField(max_length=70)
lang = models.CharField(max_length=70)
author = models.FK(Author)
class Author(models.Model):
name = models.CharField(max_length=70)
And I want to write something to get a list of authors with annotated field which shows amount of books in each language. Can't imagine an annotation for it :(, e.g. {'en': 10, 'ru': 1...etc}
e.g. just counts all, Author.objects.annotate(languages=Count(book__lang))

Simple annotation should help you:
Book.objects.values('lang').annotate(lang=Count('author')).order_by('lang')

Related

Django - annotate on multiple fields and load relevant objects

Let's say I have the following models
class Author(models.Model):
name = models.CharField(max_length=25)
...
class Publisher(models.Model):
name = models.CharField(max_length=25)
...
class Book(models.Model):
author = models.ForeignKey(Author)
publisher = models.ForeignKey(Publisher)
...
For some reason, I want to query books and group results by the author and publisher, so:
books = Book.objects.values('author', 'publisher').annotate('sth'=Avg('sth_else'))
with the results looking like:
<BookQuerySet [{'author': 2, 'publisher': 1, 'sth': 1.0}]>
Is it possible to load the whole Author and Publisher objects and not just their related ids?
I am afraid it isn't. In order to get the respective author and publisher objects. you might have to just use the ids you got here from the query and make another query.
authors = Author.objects.filter(id__in = authors)
publishers = Publisher.objects.filter(id__in = publishers)
where authors,publishers is the list of ids you got above

Where and how put my business logic in django

A friend recommended that I read the book two scoops Django and I was amazed at the recommendations he makes for a robust and well-designed Django project. This reading created a doubt in me and it is where I put the business logic, I give an example. Suppose I have two models:
models.py
class Sparks(models.Model):
flavor = models.CharField(max_length=100)
quantity = models.IntegerField(default=0)
class Frozen(models.Model):
flavor = models.CharField(max_length=100)
has_cone = models.BooleanField()
quantity_sparks = models.IntegerField(default=0)
Let's suppose that every time I add a frozen, if it has sparks, I have to subtract it from the Sparks model and check that there is an available quantity. In the book they recommend putting this logic in models.py or forms.py. If create some model required modify data from another model where should I do it?
Your data model is lacking, that's the likely source of uneasiness.
class Flavor(models.Model):
name = models.CharField(max_length=100)
class Sparks(model.Model):
flavor = models.ForeignKeyField(Flavor, on_delete=models.CASCADE)
quantity = models.IntegerField(default=0)
class Frozen(model.Model):
# This maybe should be a OneToOne, can't tell from your description.
sparks = models.ForeignKeyField(Sparks)
has_cone = models.BooleanField()
Then you'd do
frozen_instance = Frozen.objects.get()
frozen.sparks.quantity # This has replaced frozen_instance.quantity_sparks

django conditional max for each with foreign key

consider these models:
class Author(models.Model):
name = models.CharField(max_length=200)
class Book(models.Model):
author = models.ForigenKey(Author)
name = models.CharField(max_length=200)
created_at = models.DateTimeField(auto_now_add=True)
active = models.BooleanField(default=True)
I want to query all the Authors, with the latest(e.g Max('created_at') ) book of them in the same row, but only when the book is active=True.
I need to whole related book object - not just the max date.
If there is no such a book - all are active=False, or they simply do not exist - the query should output NULL where needed instead of the a book .
I've tried to write something like this:
Author.objects.annotate(max_book_date=Max('book'))
which does work, but it's missing additional fields on the book, and I'm not sure how it works in case of null (i.e no books), and the active=True condition is not there..
First of all, you should define a related_name param in the author fk field on the Book model:
author = models.ForeignKey(Author, related_name='libro')
Then, you should be able to do something like:
Author.objects.filter(libro__active=True).annotate(max_book_date=Max('libro__created_at')).all()

Django-views Custom filter

If having different books stored in django database, each book has a date in which it was added to the database. Is their a way of filtering books written by a certain author that was within a date range only using django views?
Not sure what you mean by only django views, I assume you want to use querysets. Your question is poorly written - read this.
class Book(models.Model):
title = models.CharField(max_length=200)
date = models.DateTimeField()
author = models.ForeignKey(Author)
class Author(models.Model):
name = models.CharField(max_length=200)
And Queryset would be something like this.
books = Book.objects.filter(author__name=authors_name,
date__range=["2011-01-01", "2011-01-31"])

django custom model field

If I have 2 interlinked models:
class Person(models.Model)
name = models.CharField()
class Project(models.Model):
person = models.ForeignKey(Person)
title = models.CharField()
I frequently find myself trying to find the number of Projects associated with each Person:
person = Person.objects.get(id=1)
no_projects = Project.objects.filter(person=person).count()
Is there a way of adding this as a custom field to the Person model, such that I may just call person.no_projects?
This can be done by adding a property to the Person class.
class Person(models.Model)
name = models.CharField()
#property
def no_projects(self):
return Project.objects.filter(person=self).count()
This can be called now like this
person = Person.objects.get(id=1)
person.no_projects
In fact, that functionality is (almost) built-in. Instead of querying Projects, you can just do person.project_set.count() to get that person's count of projects (and .all() to get the actual list).
You can use the property() to generate the dynamical field.
class Project(models.Model):
person = models.ForeignKey(Person)
title = models.CharField()
def _get_no_projects(self):
return Projects.objects.filter(person=self).count()
no_projects = property(_get_no_projects)
But the dynamical fields can not be used in querying, because the they don't really store data into the database.
FYI: http://www.b-list.org/weblog/2006/aug/18/django-tips-using-properties-models-and-managers/