Trying to get Count('foo__bar') inside annotate() - django

Im trying to get the following line works:
artists = models.Artists.objects.all().annotate(tot_votes=Count('votes__work')).order_by('-tot_votes')
(i.e. I want simply to annotate the count of all votes corresponding to every artist.)
But whenever the above line is executed I get the FieldError error Cannot resolve keyword 'votes' into field.
Where
class Votes(models.Model):
work = models.OneToOneField(Works, models.DO_NOTHING, db_column='work')
user = models.OneToOneField(AuthUser, models.DO_NOTHING, db_column='user')
and
class Works(models.Model):
artist = models.ForeignKey(Artists, models.DO_NOTHING, db_column='artist')
# other irrelevant fields
OR simply the relation between the tables is (Votes --> Works --> Artists)

I think you've got that relationship the wrong way round, haven't you? Artist doesn't have any kind of direct relationship to Votes, it only does to Works. The annotate call should be to Count('work__votes').
(Also note that normal naming convention for Django is to use singular names: Vote, Work, Artist.)

Related

How to join multiple model using select_related?

i have few models namely
class Alpha(models.Model):
name = models.CharField()
class XXX(models.Model):
owner = models.ForeignKey(Alpha)
class YYY(models.Model):
name = models.OneToOneField(Alpha)
Now while doing select_related like this
test = Alpha.objects.filter(id=pk).select_related('XXX')
It gives me Invalid field name(s) given in select_related, choices are YYY
I understand that YYY is at OneToOne, so its showing up - but is there a way to fetch XXX also ? or should i use "prefetch_related". But i dont wanna use prefetch as its just making slow queries and meanwhile i have 7 models which needs to be select_related :(
You can use prefetch_related in order to achieve this. Also, add related_name in foreign key fields for referencing.
class Alpha(models.Model):
name = models.CharField()
class XXX(models.Model):
owner = models.ForeignKey(Alpha, related_name='xxx')
class YYY(models.Model):
name = models.OneToOneField(Alpha, related_name='yyy')
Alpha.objects.filter(id=pk).prefetch_related('xxx', 'yyy')
You can use select_related when going in the direction of the 1 model.
For example XXX.objects.all().select_related('alpha')
But when you go from 1 towards many you have to use prefetch_related.
so Alpha.objects.all().prefetch_related('xxx')
Check out this article

Lookup that spans across 3 tables in Django

I want to do a lookup that spans three model classes. I want to find all the PartListings that match the Specific_part in the ListItem. Say Specific part = Radio, there could be several Radios in the PartListings and I want to return the PartListing id of all of them so that I can get other attributes like quantity.
I have these models:
class SpecificPart(BaseModel):
class PartListing(BaseModel):
specific_part = models.ForeignKey(
SpecificPart, on_delete=models.CASCADE, blank=True, null=True,
related_name="part_listing")
class ListItem(BaseModel):
specific_part = models.ForeignKey(SpecificPart, on_delete=models.CASCADE,
related_name="listitem")
I'm trying to put the lookup under the ListItem class like this:
def item_match(self):
part = self.specific_part
return PartListings.filter(specific_part__specific_part=part)
I tried to set it up as a Lookup that spans relationshipsbut am getting an error that PartListing is not defined. I also suspect that I'm referencing the foreign keys incorrectly. I'm also ok with redefining the models if a One to One would be better.
I am a Django newbie so thanks so much for your help!
You can try like this using reverse relation between SpecificPart and PartListing models:
class ListItem(BaseModel):
...
def item_match(self):
return self.specific_part.part_listing.all()

Django: How to make many filters on the same related field?

I have a Django model called Format, that has some fields, and another model called DepartmentFormat that looks like this
class DepartmentFormat(models.Model):
department = models.ForeignKey(Department, on_delete=models.CASCADE)
format = models.ForeignKey(Format, on_delete=models.CASCADE, related_name='format_dptfmt')
status = models.ForeignKey(FormatStatus, on_delete=models.CASCADE, null=True, default=None)
In my view to display the formats, I have some filters, like this:
class FormatFilter(FilterUserMixin):
# SOME OTHER FILTERS
class Meta:
model = Format
fields = ("business_type", "rfc", "economic_sector", "cellphone",
"format_dptfmt__status__status")
However, the same Format can have multiple DepartmentFormat objects related to it, because they can have the same Format, but different Department.
For example, this is a possible case:
A format has two DepartmentFormat objects related to it. One of those has "Ecology department" as its department, and another has "Public works department" as its department.
There exists a third Department, which has still no DepartmentFormat object related to it.
So this same Format could have zero, one, two or three DepartmentFormat objects related to it, with each of the Department objects that exist.
What I'm after, is having three filters, one for each of the departments. The first one, for instance, could filter only those Formats for which there is a related DepartmentFormat that happens to have "Ecology department", and the status selected in the filter. I can do this properly by adding format_dptfmt__status__status to the fields in the Filter, since format_dptfmt is the related_name I specified.
However, I can only do this once, and I need to do it three times. I can handle the filtering itself by just making def filter_<field_name> methods, but I can't do that if I need three filters filtering the exact same field (format_dptfmt__status__status). Is there a way to add multiple filters that filter the same field?
I can achieve this by adding format_dptfmt__status__status multiple times in the ```fields", and then three identical filters render, but I cannot distinguish them and make filter methods for them, because they are all called the same.
So, either a name identifier for each filter, or another method altogether, is what I'm after, and I don't know how to try it another way.
This should solve your problem if I don't get it very wrong
from django.db.models import Q
model.objects.filter(Q(field1='x') | Q(field1='y'))
What about filtering this way:
list_of_options = ['x', 'y', 'z']
model.objects.filter(field__in=list_of_options)
At the end, I used:
fields = ("business_type", "rfc", "cellphone", "format_dptfmt__status__status_1", "format_dptfmt__status__status_2", "format_dptfmt__status__status_3")
And
format_dptfmt__status__status_1 = django_filters.ChoiceFilter(empty_label='---Ecología---', label='Ecología', field_name='format_dptfmt__status__status', choices=((1, 'Aceptado'), (2, 'Rechazado')), method='filter_format_dptfmt__status__status_1')
format_dptfmt__status__status_2 = django_filters.ChoiceFilter(empty_label='---Protección civil---', label='Protección civil', field_name='format_dptfmt__status__status', choices=((1, 'Aceptado'), (2, 'Rechazado')), method='filter_format_dptfmt__status__status_2')
format_dptfmt__status__status_3 = django_filters.ChoiceFilter(empty_label='---Obras públicas---', label='Obras públicas', field_name='format_dptfmt__status__status', choices=((1, 'Aceptado'), (2, 'Rechazado')), method='filter_format_dptfmt__status__status_3')
And then just filtered by each Department object in the method for each filter. I don't know why Django allowed this, since format_dptfmt__status__status_1 is not a field for the Format object, but just adding the three filters individually, and just using the same field_name for all of them, seemed to work.

Django sort objects with foreign key case insensitive

I'm trying to sort a query according to a foreign key field case insensitive.
My models are:
class Post(models.Model):
title = models.CharField(max_length = 80)
author = models.ForeignKey(User, default = User)
trade_option = models.CharField(max_length= 10)
class Book(models.Model):
book_title = models.CharField(max_length = 60)
post = models.ForeignKey(Post)
I want to sort my post objects according to the book_title field case insensitive.
I know if I want to sort case insensitive with the fields in Class Post I can just do:
posts = Post.objects.filter(trade_option= 'buy').extra(select =
{'lower_name' : 'lower( title )'}).order_by('lower_name')
However, when I try the same technique with sorting with foreign key book with book_title:
posts = Post.objects.filter(trade_option= 'buy').extra(select =
{'lower_name' : 'lower( book__book_title )'}).order_by('lower_name')
I get the error "no such column: book__boot_title"
I would like to know where I'm doing this wrong. Thanks
I had the same problem. Here's what you should do:
from django.db.models.functions import Lower
posts = Post.objects.filter(trade_option= 'buy').order_by(Lower('title'))
A related lookup like book__book_title only works in the context of Django. Anything in extra is not processed by Django, so these lookups won't work. You have to explicitly fetch the result from the related table.
Please note that the ordering you're trying to define is most likely not what you expect it to be: a Post object can have multiple related Book objects. Ordering by book__book_title (manually or through the orm) can give you either an indeterminate ordering or duplicate rows, depending on the exact details of your query. You need to define which related book_title the posts should be ordered by.

How can i get a list of objects from a postgresql view table to display

this is a model of the view table.
class QryDescChar(models.Model):
iid_id = models.IntegerField()
cid_id = models.IntegerField()
cs = models.CharField(max_length=10)
cid = models.IntegerField()
charname = models.CharField(max_length=50)
class Meta:
db_table = u'qry_desc_char'
this is the SQL i use to create the table
CREATE VIEW qry_desc_char as
SELECT
tbl_desc.iid_id,
tbl_desc.cid_id,
tbl_desc.cs,
tbl_char.cid,
tbl_char.charname
FROM tbl_desC,tbl_char
WHERE tbl_desc.cid_id = tbl_char.cid;
i dont know if i need a function in models or views or both. i want to get a list of objects from that database to display it. This might be easy but im new at Django and python so i having some problems
Django 1.1 brought in a new feature that you might find useful. You should be able to do something like:
class QryDescChar(models.Model):
iid_id = models.IntegerField()
cid_id = models.IntegerField()
cs = models.CharField(max_length=10)
cid = models.IntegerField()
charname = models.CharField(max_length=50)
class Meta:
db_table = u'qry_desc_char'
managed = False
The documentation for the managed Meta class option is here. A relevant quote:
If False, no database table creation
or deletion operations will be
performed for this model. This is
useful if the model represents an
existing table or a database view that
has been created by some other means.
This is the only difference when
managed is False. All other aspects of
model handling are exactly the same as
normal.
Once that is done, you should be able to use your model normally. To get a list of objects you'd do something like:
qry_desc_char_list = QryDescChar.objects.all()
To actually get the list into your template you might want to look at generic views, specifically the object_list view.
If your RDBMS lets you create writable views and the view you create has the exact structure than the table Django would create I guess that should work directly.
(This is an old question, but is an area that still trips people up and is still highly relevant to anyone using Django with a pre-existing, normalized schema.)
In your SELECT statement you will need to add a numeric "id" because Django expects one, even on an unmanaged model. You can use the row_number() window function to accomplish this if there isn't a guaranteed unique integer value on the row somewhere (and with views this is often the case).
In this case I'm using an ORDER BY clause with the window function, but you can do anything that's valid, and while you're at it you may as well use a clause that's useful to you in some way. Just make sure you do not try to use Django ORM dot references to relations because they look for the "id" column by default, and yours are fake.
Additionally I would consider renaming my output columns to something more meaningful if you're going to use it within an object. With those changes in place the query would look more like (of course, substitute your own terms for the "AS" clauses):
CREATE VIEW qry_desc_char as
SELECT
row_number() OVER (ORDER BY tbl_char.cid) AS id,
tbl_desc.iid_id AS iid_id,
tbl_desc.cid_id AS cid_id,
tbl_desc.cs AS a_better_name,
tbl_char.cid AS something_descriptive,
tbl_char.charname AS name
FROM tbl_desc,tbl_char
WHERE tbl_desc.cid_id = tbl_char.cid;
Once that is done, in Django your model could look like this:
class QryDescChar(models.Model):
iid_id = models.ForeignKey('WhateverIidIs', related_name='+',
db_column='iid_id', on_delete=models.DO_NOTHING)
cid_id = models.ForeignKey('WhateverCidIs', related_name='+',
db_column='cid_id', on_delete=models.DO_NOTHING)
a_better_name = models.CharField(max_length=10)
something_descriptive = models.IntegerField()
name = models.CharField(max_length=50)
class Meta:
managed = False
db_table = 'qry_desc_char'
You don't need the "_id" part on the end of the id column names, because you can declare the column name on the Django model with something more descriptive using the "db_column" argument as I did above (but here I only it to prevent Django from adding another "_id" to the end of cid_id and iid_id -- which added zero semantic value to your code). Also, note the "on_delete" argument. Django does its own thing when it comes to cascading deletes, and on an interesting data model you don't want this -- and when it comes to views you'll just get an error and an aborted transaction. Prior to Django 1.5 you have to patch it to make DO_NOTHING actually mean "do nothing" -- otherwise it will still try to (needlessly) query and collect all related objects before going through its delete cycle, and the query will fail, halting the entire operation.
Incidentally, I wrote an in-depth explanation of how to do this just the other day.
You are trying to fetch records from a view. This is not correct as a view does not map to a model, a table maps to a model.
You should use Django ORM to fetch QryDescChar objects. Please note that Django ORM will fetch them directly from the table. You can consult Django docs for extra() and select_related() methods which will allow you to fetch related data (data you want to get from the other table) in different ways.