Django queries: how to annotate with a filtered count? - sql

Suppose I have a Book model with a language field and a foreign key to a Publisher model.
Currently I use a Count annotation in a custom Publisher manager to allow me to add to the admin a sortable column with the number of books by each publisher. (see How to add a sortable count column to the Django admin of a model with a many-to-one relation? )
My problem now is that I need to have a different column count for the books published in each language.
Is there any way to make the annotation subject to a filter of the related model?

You can use the double underscore __ for this purpose. Something like this (snippet taken from question linked to by OP):
class PublisherManager(models.Manager):
def get_query_set(self):
return super(PublisherManager,self).get_query_set().annotate(lang_count=Count('book__language'))

Related

odoo inherit a model and "key error [my_database]"

I want to try to learn Odoo _inherit. But I have this error right now. And I couldn't solve the problem.
my module name is stock.info and I want the inherit product.template model.
but this error came.
TypeError: Many2many fields stock.info.taxes_id and product.template.taxes_id use the same table and columns
I added product.template to my depends in manifest too. Any advice?
Reminder for future questions: You should provide code for your Problem and not only an error message.
Like the error says you have 2 many2many fields which refers to the same table and columns.
You have to know that many2many fields in Odoo generate a mapping table in the database with two columns which are foreign keys to tables of the referenced models. The name of the mapping table and the column names are automatically generated by default. So if the automatic generation for your field creates the same name for table/columns which are already in use, you will get this error.
To solve this, you can assign additional attributes when defining your field.
So your field could like like this:
taxes_ids = fields.Many2many(relation='stock_info_account_tax_rel', column1='product_id', column2='tax_id')
(remember that many2many fields should be named with suffix _ids and not _id)
Take a look at the documentation for further informations: odoo.fields.Many2many
Parameters:
comodel_name – name of the target model (string) mandatory
except in the case of related or extended fields
relation (str) – optional name of the table that stores the relation
in the database
column1 (str) – optional name of the column referring to “these”
records in the table relation
column2 (str) – optional name of the column referring to “those”
records in the table relation
The attributes relation, column1 and column2 are optional. If not
given, names are automatically generated from model names, provided
model_name and comodel_name are different!
Note that having several fields with implicit relation parameters on a
given model with the same comodel is not accepted by the ORM, since
those field would use the same table. The ORM prevents two many2many
fields to use the same relation parameters, except if
both fields use the same model, comodel, and relation parameters are
explicit; or
at least one field belongs to a model with _auto = False.

Why related fields use Write function

_name = "my.table"
building_id = fields.Many2one('building', related='floor_id.building_id', readonly=False)
floor_id = fields.Many2one('building.floor')
A user with the read access to 'building' and 'building.floor' tables, tries to create a record in "my.table" If the user chooses building_id and floor_id together an error occurs. The error says that my user has no access to write 'building.floor' table. My question is: why a related field use the write function, what is the difference between the compute and related in this scenario?
Related fields are very simple computed fields. So simple they can be "implemented" with one parameter on field definition. Odoo has generic methods for those fields. For example a lot of developers don't write inverse methods for computed fields, which inverse the compute method, because the simply don't need it. But without it and without storing the computed field, Odoo sets the field readonly.
Related fields have a generic inverse method. In your case changing building_id when there was already a floor_id chosen, Odoo will write the building_id on that floor_id.building_id, because that's how related fields work (i know that's not the best explanation).
The user obviously has no write/update rights on builiding.floor model and that's why there will be the access error message in the end, because Odoo wants to write the new building on the floor.
Seems to me you want to filter the floors by buildings, but you shouldn't use a related field for that. Just put a domain on floor_id which filters by the chosen building_id:
floor_id = fields.Many2one('building.floor', domain="[('building_id', '=?', building_id)]")
You could also use domain operator =, but =? will show all floors when no building was set yet.

Compute many2many field with values from another model using Odoo developer interface

I need a new field inside Contact model that would hold information about Allowed companies of the related user.
Now there is only field about Currently picked company by that user (and it is not enough for me to make a record rule).
The field I want to copy values from is inside model Users and it is called company_ids.
I’m trying to add this field in the developer mode (Settings > Technical > Fields) like this:
But I’m having trouble with code that would fill my field with values from the another model.
for record in self:
record[("x_company_ids")] = env['res.users'].company_ids
I’m guessing that the record is referring to a record inside Contact model and it does not contain fields from another models like Users. So I can’t figure it out how to reference a field from another model.
Something similar to this: env['res.users'].company_ids?
It is even harder for me because it is many2many field and should always update when the source changes.
Maybe better solution would be to use Automatic action to write values to this field?
I saw some threads like this: Computed many2many field dependencies in Odoo 10.
But it seems like in those cases they had clear connection between the fields and I don't have it. I don't know how to get related user while I'm inside Contact model. I know only how to this oposite way (from user to contact): user.partner_id.id
Here in below given code you haven't specified related user from which you will get company_ids, you have directly accessing company_ids
for record in self:
record[("x_company_ids")] = env['res.users'].company_ids
You can write as following :
for record in self:
record["x_company_ids"] = self.env['res.users'].search([('partner_id','=',record.id)]).company_ids

How to create a temp boolean field with Django orm

Image I have following models:
class Product(models.Model):
name = models.CharField(max_length=20)
class Receipt(models.Model):
product = models.ForeignKey(Product)
user = models.ForeignKey(User)
I have an input list of product ids and a user. I want to query for each product, whether it's been purchased by this user. Notice I need a queryset with all exist products based on given input because there are other fields I need for each product even not purchased by this user, so I cannot use Product.objects.filter(receipt__user=user).
So can I create a temp Boolean field to present this property in one single query? I am using Django 1.8 and postgresql 9.3
Update requirements:To separate products into two groups. One is bought by this specific user, the other one is not. I don't think any given filter can implement this. This should be implement by creating a new temp field either by annotate or F expression.
I think, you need .annotate() expression as
from django.db.models.expressions import Case, When, Value
product_queryset = Product.objects.annotate(
is_purchased=Case(
When(receipt__user=current_user, then=Value('True')),
default=Value('False')
))
How to access the annotated field?
product_queryset.first().is_purchased
Thx for #JPG's answer.
I just realize except conditional expressions, there's another easy way to do it.
Just using prefetch_related will implement everything in two queries. Although it's double than conditional expressions, but it's still a considerable time complexity solution.
products = Product.objects.filter(id__in=[1,2,3,4,5]).prefetch_related ('receipt_set').all()
Then we can detect user for this product in Python by
for p in products:
print user in [receipt.user_id for receipt in p.purchase_set.all()]

How to work with map property in RQL (Oracle's ATG Web Commerce)

We use Oracle's ATG Web Commerce for our project. And currently we need construct RQL query which obtain products which SKU's tacticalTradeStatuses contains certain status and ordered by status value.
I briefly describe the relationship between entities: Product item descriptor contains list of SKUs. Each SKU contains map tacticalTradeStatuses (key - tactical trade status, value - sequense)
For example, how to obtain all products which SKU's tacticalTradeStatuses property contains key 'BEST_SELLER' and ordered by value associated with key 'BEST_SELLER'.
Key by which we want to select products we want to pass as RQL parameter.
i have two ways to doing that
1) first create a query which fetches all the product based on map key BEST_SELLER
2) Now pass it to foreach droplet and add sort properties. which help to sort the result based on your requirements
for sorting please refer to below link
http://docs.oracle.com/cd/E23095_01/Platform.93/PageDevGuide/html/s1316foreach01.html
2 way i think is to use query options in RQLStatement.. which work same as sort properties in for each
If you provide some XML Repository structure that will be good..hope it will help you