I am writing one method in Django Manager model.
I want to write method that finds out number of all sold copies (books) per author.
I have two models and method written in Manager.
My problem is that method should also be chainable from any Author queryset, for example something like
Author.objects.filter(...).exlucde(...).total_copies_sold()
should also work.
Example:
author = Author.objects.create(...)
Book.objects.create(..., author=author, copies_sold=10)
Book.objects.create(..., author=author, copies_sold=20)
author_total_books = Author.objects.total_copies_sold().first()
>>> author_total_books.copies
30
Below my code. It works like in example above, but then I try something like:
author_books = Author.objects.filter(id=2).total_copies_sold()
I got
'QuerySet' object has no attribute 'annotate'
class AuthorManager(models.Manager):
def total_copies_sold(self):
return self.get_queryset().annotate(copies=Sum('book__copies_sold')
class Author(models.Model):
first_name = models.CharField(max_length=120)
last_name = models.CharField(max_length=120)
objects = AuthorManager()
class Book(models.Model):
title = models.CharField(max_length=120)
copies_sold = models.PositiveIntegerField()
author = models.ForeignKey(Author, on_delete=models.CASCADE, related_name='books')
[Edited]
Thank you schillingt for reply. I added:
class AuthorQueryset(models.QuerySet):
def total_copies_sold(self):
return self.annotate(copies=Sum('books__copies_sold'))
I tried something like:
author_books = Author.objects.filter(id=2).total_copies_sold()
>>> author_books.copies
I got
'AuthorQueryset' object has no attribute 'copies'
What you are lookig for is :
from django.db import models
from django.db.models import Sum
from django.db.models.functions import Coalesce
class AuthorManager(models.Manager):
def get_queryset(self):
return AuthorQuerySet(self.model, using=self._db)
def annotate_with_copies_sold(self):
return self.get_queryset().annotate_with_copies_sold()
class AuthorQuerySet(models.QuerySet):
def annotate_with_copies_sold(self):
return self.annotate(copies_sold=Sum('books__copies_sold'))
class Author(models.Model):
objects = AuthorManager()
first_name = models.CharField(max_length=30)
last_name = models.CharField(max_length=30)
class Book(models.Model):
title = models.CharField(max_length=30)
copies_sold = models.PositiveIntegerField()
author = models.ForeignKey(Author, on_delete=models.CASCADE, related_name='books')
Now it is possible to chain queries e.g.:
author_total_books = Author.objects.total_copies_sold().first()
However you will no be able to use it on QuerySet object like:
author_books = Author.objects.filter(id=2).total_copies_sold()
That is because you are annotating Author object, not a QuerySet. To obtain that result you should execute:
Author.objects.annotate_with_copies_sold().get(id=2)
author.copies_sold
15
You need to use Manager.from_queryset to set your manager. Here are the docs.
class AuthorQueryset(models.QuerySet):
def total_copies_sold(self):
...
class Author(models.Model):
objects = models.Manager.from_queryset(AuthorQueryset)()
from django.db import models
from django.db.models import Sum
from django.db.models.functions import Coalesce
class AuthorManager(models.Manager):
def get_queryset(self):
return AuthorQuerySet(self.model, using=self._db)
def annotate_with_copies_sold(self):
return self.get_queryset().annotate_with_copies_sold()
class AuthorQuerySet(models.QuerySet):
def annotate_with_copies_sold(self):
# Write your solution here
return self.annotate(copies_sold=Coalesce(Sum('books__copies_sold'), 0))
class Author(models.Model):
# Make sure this manager is available.
objects = AuthorManager()
# objects = models.Manager.from_queryset(AuthorQuerySet)()
first_name = models.CharField(max_length=30)
last_name = models.CharField(max_length=30)
class Book(models.Model):
title = models.CharField(max_length=30)
copies_sold = models.PositiveIntegerField()
author = models.ForeignKey(Author, on_delete=models.CASCADE, related_name='books')
enter code here
class AuthorManager(models.Manager):
def get_queryset(self):
return AuthorQuerySet(self.model, using=self._db)
def annotate_with_copies_sold(self):
return self.get_queryset().annotate_with_copies_sold()
class AuthorQuerySet(models.QuerySet):
def annotate_with_copies_sold(self):
return self.annotate(copies_sold=Sum('Book_Author__copies_sold'))
class Author(models.Model):
first_name = models.CharField(max_length=50)
last_name = models.CharField(max_length=50)
objects = AuthorManager()
class Meta:
verbose_name_plural = "Author"
verbose_name = 'Author'
ordering = ('first_name','last_name')
class Book(models.Model):
title = models.CharField(max_length=250, unique=True)
copies_sold = models.PositiveIntegerField(default=0)
author = models.ForeignKey(Author, on_delete=models.CASCADE, related_name='Book_Author')
class Meta:
verbose_name_plural = "Book"
verbose_name = 'Book'
ordering = ('title','copies_sold')
from vehicles.models import Author, Book
try:
author = Author.objects.get(first_name='Mark', last_name='Twain')
except Author.DoesNotExist:
author = Author.objects.create(first_name='Mark', last_name='Twain')
try:
book = Book.objects.get(author=author, title='Adventrure of Huckleberry Finn', copies_sold=7)
except Book.DoesNotExist:
book = Book.objects.create(author=author, title='Adventrure of Huckleberry Finn', copies_sold=7)
pass
try:
book = Book.objects.get(author=author, title='Adventrure of Tomm Saywer', copies_sold=4)
except Book.DoesNotExist:
book = Book.objects.create(author=author, title='Adventrure of Tomm Saywer', copies_sold=4)
pass
author = Author.objects.annotate_with_copies_sold().first()
print(author.copies_sold)
11
1.Create AuthorManager, AuthorQuerySet classes from Author and Books
2.Create Author, Book models
3.Prepare Test Data and use model manager to filter the queryset
Count books sold by authors using Django ORM
Wihtout writing custom manager you can use "AuthorQueryset" in Author Manager
Just a menthion AuthorQueryset.as_manager() in Author models, that's it.
Here are the Django Docs
from django.db import models
from django.db.models import Sum, Value
from django.db.models.functions import Coalesce
# Create your models here.
class AuthorQuerySet(models.QuerySet):
def annotate_with_copies_sold(self):
return self.annotate(copies_sold=Coalesce(Sum('books__copies_sold'),Value(0)))
class Author(models.Model):
first_name = models.CharField(max_length=30)
last_name = models.CharField(max_length=30)
objects = AuthorQuerySet.as_manager()
class Book(models.Model):
title = models.CharField(max_length=30)
copies_sold = models.PositiveIntegerField()
author = models.ForeignKey(Author, on_delete=models.CASCADE, related_name="books")
Related
I want to make the string representation of a field show data based on a JOIN, for instance:
For Penciler - I want the string representation to resolve to
John Doe (DC) - But the publisher value in that class is a Foreign Key - How do I reference the publisherName?
from django.db import models
class Series(models.Model):
seriesId = models.AutoField(primary_key=True)
series_name = models.CharField(max_length=300)
publisher = models.ForeignKey('Publisher', on_delete = models.PROTECT)
first_published = models.DateField()
last_published = models.DateField()
discontinued = models.BooleanField(default=False)
def __str__(self):
return f'{self.series_name} - {self.publisher} ({self.first_published - self.last_published})'
class Meta:
ordering = ['publication_year','title']
class Publisher(models.Model):
publisherId = models.AutoField(primary_key=True)
publisherName = models.CharField(max_length=250, null=False)
def __self__(self):
return self.publisherName
class Penciler(models.Model):
pencilerID = models.AutoField(primary_key=True)
pencilerName = models.CharField(max_length=200)
publisher = models.ForeignKey('Publisher', on_delete= models.PROTECT)
def __str__(self):
return self.pencilerName (self.publisher)
You can access the related Publisher instance through the ForeignKey field and get the publisherName in the __str__() method so:
def __str__(self):
publisher_name = self.publisher.publisherName
return f'{self.pencilerName} ({publisher_name})'
Additionally, I'd recommend you to use string formatting, such as using f-strings.
It is as simple as that:
def __str__(self):
return f"{self.pencilerName} ({self.publisher})"
I have a question with count() method. I have the class Kategorie in my models.py
from django.db import models
from django.utils import timezone
class Kategorie(models.Model):
glowna = models.CharField(max_length=150, verbose_name='Kategoria')
class Meta:
verbose_name='Kategoria'
verbose_name_plural='Kategorie'
def __str__(self):
return self.glowna
class Witryna(models.Model):
nazwa = models.CharField(default="", max_length=150, verbose_name = 'Nazwa strony')
adres_www = models.CharField(max_length=70, verbose_name='Adres www')
slug = models.SlugField(max_length=250, verbose_name='Przyjazny adres url')
email = models.CharField(max_length=100, verbose_name='Adres e-mail')
text = models.TextField(max_length=3000, verbose_name='Opis strony')
kategoria = models.ForeignKey(Kategorie, verbose_name='Kategoria')
data_publikacji = models.DateTimeField(blank=True, null=True, verbose_name='Data publikacji')
class Meta:
verbose_name='Strona www'
verbose_name_plural = 'Strony www'
def publikacja(self):
self.data_publikacji=timezone.now()
self.save()
def __str__(self):
return self.nazwa
And I made definition in views.py
def widok_kategorii(request):
kategorie = Kategorie.objects.all()
wpisy_kat = Kategorie.objects.count()
return render(request, 'firmy/widok_kategorii.html', {'kategorie': kategorie, 'wpisy_kat': wpisy_kat})
the view in html file showing me the number of all Kategories but I want to have a result for example how many websites are in the for example category Business? I have to use count() with some arguments it filters?
If you want to know how many Witryna are in the category Business you can do:
Witryna.objects.filter(kategoria__glowna="Business").count()
You may try:
e_comm_count = Witryna.objects.filter(kategoria__glowna='Business').count()
# Your value here^^^^
For count witryna for each category you may use annotate, it looks like:
from django.db.models import Count
wpisy_kat = Kategorie.objects.annotate(cnt_witryna=Count('Witryna'))
in the queryset you may find new attr cnt_witryna, hope it help.
I have to create a view which returns me the posts of a particular owner/author
This error in coming from view bellow. I know this is a simple thing that I am missing. Please help me on this: (marlm is the ID I created to test)
def view_by_owner(request):
user = request.user.username
posts_owner = Post.objects.filter(owner=user)
return render_to_response('view_post.html',{'view_owner':posts_owner})
Models:
from django.db import models
from django.db.models import permalink
from django.contrib.auth.models import User
class Post(models.Model):
title = models.CharField(max_length=100)
body = models.TextField()
datposted = models.DateTimeField('date posted')
category = models.ForeignKey('Category')
owner = models.ForeignKey('UserProfile')
def __str__(self):
return '%s' % self.title
class Category(models.Model):
title = models.CharField(max_length=100)
def __str__(self):
return self.title
class UserProfile(models.Model):
# This line is required. Links UserProfile to a User model instance.
user = models.OneToOneField(User)
# The additional attributes we wish to include.
website = models.URLField(blank=True)
picture = models.ImageField(upload_to='profile_images', null=True)
# Override the __unicode__() method to return out something
def __unicode__(self):
return self.user.username
class Logout(User):
force_logout_date = models.DateTimeField(null=True, blank=True)
The problem is that owner is a foreign key to User, not the value of the user name. To lookup by that, you will need to span that relationship, like so:
posts_owner = Post.objects.filter(owner__user__username=user)
Or, more simply, you could do this:
posts_owner = Post.objects.filter(owner__user=request.user)
I just start to learn Django and I want to create a Product model with attributes, custom fields and custom field options. Custom field options exemple:
Line 1: [YOUR TEXT] | Custom field options: [FONT] [FONT SIZE] [...]
Line 2: [YOUR TEXT] | Custom field options: [FONT] [FONT SIZE] [...]
So I've created this models:
from django.db import models
from django.utils import timezone
class Product(models.Model):
name = models.CharField(max_length=100)
description = models.TextField()
sku = models.CharField(max_length=100)
slug = models.CharField(max_length=100)
price = models.DecimalField(max_digits=6, decimal_places=2)
active = models.BooleanField()
created_at = models.DateTimeField(auto_now_add=True)
updated_at = models.DateTimeField(auto_now=True)
def __unicode__(self):
return self.name
class ProductMeta(models.Model):
product = models.OneToOneField('Product')
title = models.CharField(max_length=100)
description = models.TextField(max_length=250)
class ProductImage(models.Model):
def upload_path(self, filename):
return 'static/uploads/images/%s%s' % (timezone.now().strftime('%Y/%m/%d/%Y%m%d_'), filename)
product = models.ForeignKey('Product')
name = models.CharField(max_length=100)
default = models.BooleanField()
image = models.ImageField(upload_to=upload_path)
def __unicode__(self):
return self.name
class ProductCharacteristic(models.Model):
product = models.ForeignKey('Product', related_name="characteristics")
name = models.CharField(max_length=100)
value = models.CharField(max_length=100)
def __unicode__(self):
return self.name
class ProductAttribute(models.Model):
category = models.ForeignKey('ProductAttributeCategory')
products = models.ManyToManyField('Product', related_name="attributes")
name = models.CharField(max_length=100)
ordering = ['-category']
def __unicode__(self):
return u'%s : %s' % (self.category, self.name)
class ProductAttributeCategory(models.Model):
name = models.CharField(max_length=100)
def __unicode__(self):
return self.name
class ProductAttributeValue(models.Model):
attribute = models.ForeignKey('ProductAttribute', related_name="values")
name = models.CharField(max_length=100)
def __unicode__(self):
return self.name
class ProductCustomField(models.Model):
product = models.ForeignKey('Product', related_name="custom_fields")
name = models.CharField(max_length=100)
description = models.TextField(max_length=250)
def __unicode__(self):
return self.name
class ProductCustomFieldOption(models.Model):
fields = models.ManyToManyField('ProductCustomField', related_name="options")
name = models.CharField(max_length=100)
def __unicode__(self):
return self.name
class ProductCustomFieldOptionValue(models.Model):
option = models.ForeignKey('ProductCustomFieldOption', related_name="values")
name = models.CharField(max_length=100)
def __unicode__(self):
return self.name
But now I don't know how to create the form in product details page in which the user can choose the product attributes (color, size...) and the product custom fields (and custom fields options). I've tried a lot of things but no results.
Can you help me please? :)
your question is unclear to me and your even more confusing. However see this if it helps
In your models.py
from django.db import models
from model_utils import Choices
colour_choices = ('Blue', 'Green')
class Product(models.Model):
name = models.CharField(max_length=100)
def __unicode__(self):
reuturn self.name
class ProductAttributes(models.Model):
product = models.Foreignkey(Product, related_name='products')
colour = models.CharField(choices=Choices(*colour_choices))
In your forms.py
from django import forms
from .models import Product, ProductAttributes
class ProductForm(forms.ModelForm):
class Meta:
model = Product
class ProdductAttributesForm(forms.ModelForm):
class Meta:
model = ProductAttributes
Write your views.py, urls.py and template accordingly
this method will give you a text box to enter products and drop-down for choosing color.
Hope it helped!
I have this code:
class Reference(models.Model):
title = models.CharField(max_length=200, verbose_name = _('title'))
def __unicode__(self):
return u"%s" % (self.title)
class Meta:
verbose_name = _('bibliographic reference')
verbose_name_plural = _('bibliographic references')
class Relation(models.Model):
reference = models.ForeignKey(Reference)
circuit = models.ManyToManyField('Circuit', related_name = 'relation_circuit', verbose_name = _('Circuits'))
def __unicode__(self):
return u"%s " %(self.reference)
class Meta:
verbose_name = _('relation')
verbose_name_plural = _('relations')
class Circuit(models.Model):
name = models.CharField(max_length=200, verbose_name = _('name'))
reference = models.ManyToManyField(Relation, through=Relation.circuit.through, related_name='relation_circuit', verbose_name = _('Bibliographic References'))
def __unicode__(self):
return u"%s" % (self.name)
class Meta:
verbose_name = _('circuit')
verbose_name_plural = _('circuits')
Relation is shown as an inline in Reference.
I need to create a bidirectional relationship between my Circuits and the References, but I have no idea how to show all my References instead only those who had a Relation, cause Relation is between them.
Anybody can help me?
Thank you very much.
This would be my starting point.
class Reference(models.Model):
title = models.CharField(max_length=200)
relations = models.ManyToManyField('Relation', related_name="reference_relations", null=True, blank=True)
def __unicode__(self):
return u"%s" % (self.title,)
class Relation(models.Model):
reference = models.ForeignKey(Reference)
circuit = models.ForeignKey('Circuit')
def __unicode__(self):
return u"%s <-> %s " %(self.reference, self.circuit)
class Circuit(models.Model):
name = models.CharField(max_length=200)
relations = models.ManyToManyField(Relation, related_name="circuit_relations", null=True, blank=True)
def __unicode__(self):
return u"%s" % (self.name)
admin.py
from django.contrib import admin
from web.models import *
class RelationInline(admin.TabularInline):
model = Relation
class CircuitAdmin(admin.ModelAdmin):
inlines = [
RelationInline,
]
class ReferenceAdmin(admin.ModelAdmin):
inlines = [
RelationInline,
]
admin.site.register(Reference,ReferenceAdmin)
admin.site.register(Relation)
admin.site.register(Circuit, CircuitAdmin)
Of course you can do this without the through table, but my preference is to keep relations simple.
I'm not sure if I completely understood what you need, but wouldn't a table with a foreignKey to both be enough?
Something like
class Reference(models.Model):
title = models.CharField(max_length=200, verbose_name = _('title'))
class Circuit(models.Model):
name = models.CharField(max_length=200, verbose_name = _('name'))
class Relation(models.Model):
reference = models.ForeignKey(Reference)
circuit = models.ForeignKey(Circuit)
Then you can link them by creating an instance of Relation like so:
circuit = Circuit(name="cool_circuit")
reference = Reference(title="cool_reference")
relation = Relation(reference=reference, circuit=circuit)
It's also easy to get all references linked to some circuit
circuit = Circuit.objects.get(id=1)
references_linked_to_circuit_1 = Reference.objects.filter(relation__circuit=circuit)
and likewise for all circuits linked to a reference
reference = Circuit.objects.get(id=1)
circuits_linked_to_reference_1 = Reference.objects.filter(relation__reference=reference)