Django - Get related objects - django-models

I have 3 Models (lets say A, B, C). Model C has both A and B as Foreign keys. Now I have primary_key of A and I want to retrieve the list of related B objects.
I want entire object of B not just fields which I can get using values() or values_list(). My Models are as below:
class A(models.Model):
name = models.CharField(max_length=200)
description = models.CharField(max_length=200)
class B(models.Model):
name = models.CharField(max_length=200)
description = models.CharField(max_length=200)
class C(models.Model):
name = models.CharField(max_length=200)
roll_number = models.IntegerField(default=0)
a = models.ForeignKey(A,related_name='c_a')
b = models.ForeignKey(A,related_name='c_b')

You can slightly modify the answer from #Piyush S. Wanare like that:
c.objects.filter(a=primary_key_a).values('b')
Or if you only want a list with only b objects you can use values_list():
c.objects.filter(a=primary_key_a).values_list('b', flat=True)
This gives you a flat list of b (in this case). values returns a dictionary, values_list is similar but the output is a list of tuples instead of a dict. The additional option flat=True (works if only one one field is retrieved) returns a flat list of objects instead of a list of tuples of objects.
The docs for reference:
https://docs.djangoproject.com/en/1.11/ref/models/querysets/#values
https://docs.djangoproject.com/en/1.11/ref/models/querysets/#values-list

Related

odoo domain search "id in ids"

I have a model B with a Many2many field referencing model A.
Now given an id of model A, I try to get the records of B that reference it.
Is this possible with Odoo search domains? Is it possible doing some SQL query?
Example
class A(models.Model):
_name='module.a'
class B(models.Model):
_name='module.b'
a_ids = fields.Many2many('m.a')
I try to do something like
a_id = 5
filtered_b_ids = self.env['module.b'].search([(a_id,'in','a_ids')])
However, this is not a valid search in Odoo. Is there a way to let the database do the search?
So far I fetch all records of B from the database and filter them afterward:
all_b_ids = self.env['module.b'].search([])
filtered_b_ids = [b_id for b_id in b_ids if a_id in b_id.a_ids]
However, I want to avoid fetching not needed records and would like to let the database do the filtering.
You should create the equivalent Many2many field in A.
class A(models.Model):
_name='module.a'
b_ids = fields.Many2many('module.b', 'rel_a_b', 'a_id', 'b_id')
class B(models.Model):
_name='module.b'
a_ids = fields.Many2many('module.a', 'rel_a_b', 'b_id', 'a_id')
In the field definition, the second argument is the name of the association table, and the two next ones are the name of the columns referencing the records of the two models. It's explained in the official ORM documentation.
Then you just have to do my_a_record.b_ids.
If you prefer doing an SQL request because you don't want to add a python field to A, you can do so by calling self.env.cr.execute("select id from module_b b, ...").fetchall(). In your request you have to join the association table (so you need to specify a name for it and its columns, as described in my code extract, otherwise they are automatically named by Odoo and I don't know the rule).
I think it's still possible to use search domains without the field in A but it's tricky. You can try search([('a_ids','in', [a_id])]) but I'm really not sure.
class A(models.Model):
_name='module.a'
class B(models.Model):
_name='module.b'
a_ids = fields.Many2many('module.a')
Now you want to search a_id = 5
To do so simply use browse or search ORM methods i.e,
a_id = 5
filtered_b_ids = self.env['module.b'].search([(a_id,'in',self.a_ids.ids)])
or
a_id = 5
filtered_b_ids = self.env['module.a'].search([(a_id)])

How to sort query set (or array) with more than one type of elements (classes) by common attribute using Django Python

I need help with creating a query set (or array) that as more than one type of elements (different classes) by a common attribute.
here are the classes:
class aaa(models.Model):
fd = models.CharField(max_length=100, unique=True)
timestamp = models.DateTimeField(auto_now_add=True, auto_now=False)
updated = models.DateTimeField(auto_now_add=True, auto_now=False)
#more attributes...
def __str__(self):
return self.fd
class bbb(models.Model):
fd = models.CharField(max_length=100)
date = models.DateTimeField(blank=True, null=True)
#more attributes...
timestamp = models.DateTimeField(auto_now_add=True, auto_now=False)
updated = models.DateTimeField(auto_now_add=True, auto_now=False)
class Meta:
ordering = ["-timestamp"]
def __str__(self):
return self.fd
I want to sort all this elements by the attribute "timestamp" (that is the same in the two classes).
So far, this is what i got:
my_objects = (aaa.objects.all(),bbb.objects.all())
That creates the query set of all the elements. I prefer the query set way, if its better to use array or some other structure please let me know.
thanks!
Use the pipe to merge querysets:
combined = qs1 | qs2 | qs3
But this wont work for querysets from distinct models, at least not if they have diffferent fields. You will get an Cannot combine queries on two different base models. error.
A possible solution is to use itertools.chain, like in this blog post, which i quote here for reference.
from itertools import chain
result_lst = list(chain(queryset1, queryset2))
Now, you can sort the resulting list by any common field, e.g. creation date
from operator import attrgetter
result_lst = sorted(
chain(queryset1, queryset2),
key=attrgetter('created_at'))

how to get model name that has m2m relation to a specific model

Suppose I have two models A and B:
class A(models.Model):
name = models.CharField()
class B(models.Model):
field = models.ManyToManyField(A)
How can I get the model name B and field from string A? or how can I get model name A and field from string B? Either is ok.
Try this out:
B._meta.get_field('field').related_model._meta.model_name

Foreign key in django returns all data from related model

I have two Model classes, A and B. B has a ForeignKey to A.
Both models have a corresponding ModelForm.
When I do this:
bbb = BForm();
for b in bbb:
print b;
If b is a ForeignKey field it prints a combobox with all data from the database (from class A).
Why?
According to Django ModelForms documentation:
ForeignKey is represented by django.forms.ModelChoiceField, which is a ChoiceField whose choices are a model QuerySet.
ChoiceField is rendered using select tag by default.

Django's ManyToMany Relationship with Additional Fields

I want to store some additional information in that, automatically created, ManyToMany join-table. How would I do that in Django?
In my case I have two tables: "Employees" and "Projects". What I want to store is how much each of the employees receives per hour of work in each of the projects, since those values are not the same. So, how would I do that?
What occurred to me was to, instead of the method "ManyToManyField", create explicitly a third class/table to store those new informations and to set its relationship with "Employees" and "Projects" using the "ForeignKey" method. I'm pretty sure it will work, but is this the best approach?
Here is example of what you want to achieve:
http://docs.djangoproject.com/en/dev/topics/db/models/#extra-fields-on-many-to-many-relationships
In case link ever breaks:
from django.db import models
class Person(models.Model):
name = models.CharField(max_length=128)
def __str__(self): # __unicode__ on Python 2
return self.name
class Group(models.Model):
name = models.CharField(max_length=128)
members = models.ManyToManyField(Person, through='Membership')
def __str__(self): # __unicode__ on Python 2
return self.name
class Membership(models.Model):
person = models.ForeignKey(Person)
group = models.ForeignKey(Group)
date_joined = models.DateField()
invite_reason = models.CharField(max_length=64)

Resources