How to make Q queries with models with foreign keys? - django

my model is defined like this:
class Model2(models.Model):
id = models.IntegerField(primary_key=True)
name = ...
class Model1(models.Model):
id = models.IntegerField(primary_key=True)
model2 = models.ForeignKey(Model2, to_field='id', db_column='model2')
The problem is I do not know how to make OR queries with queryset.
qs = Model1.objects.filter(Q(model2.id__icontains=search) | Q(id__icontains=search))
I get
keyword can't be an expression
So the question is how can I reference to the field of the related model in Q queries? Thanks

This should work:
qs = Model1.objects.filter(Q(model2__id=search) | Q(id=search))
I would revisit the implementation if you are looking for id__icontains
If you search for 1, then it would look for 1, 11, 121, 166..., (any id with 1 in it) which is probably not what you want.
To specifically point out your error,
Q(model2.id__icontains=search)
should be
Q(model2__id__icontains=search)

Related

How to query on OneToOne relation of a related_name object in django

I have this model:
class ProgramRequirement(Model):
program = OneToOneField(Program, related_name='program_requirement')
prereq_program = ForeignKey(Program, related_name='prereq_program_requirement')
is_english_required = BooleanField()
and this model
class Program(Model):
field_1 = ...
field_3 = ...
I need to write a query that would return the primary key of the programs of which is_english_required of the prereq_program is True.
I tried this but it seems to be a wrong query:
ProgramRequirement.objects.filter(prereq_program__prereq_program_requirement__is_english_required =True).values_list('program__pk', flat=True)
However, it is not returning the correct result.
I am not sure if it is what I want but I am also thinking of this:
Program.objects.filter(prereq_program_requirement__is_english_required =True).values_lis('pk', flat=True)
Any idea of how to retrieve do the abovementioned result?
You might try:
ProgramRequirement.objects.filter(prereq_program__programrequirement__is_english_required = True).values('pk')

Django ORM: Combine exlude with not in filter

For this (strongly simplified) Django model setup:
class A(models.Model)
class B(models.Model)
a = models.ForeignKey(A, null=True, blank=True)
class C(models.Model)
b = models.ForeignKey(B, null=True, blank=True)
I would like to make sure that for a query on C, no related objects that are not [a1,a2] are part of a query.
Something like:
qs = C.objects.exclude(b__a__NOT_in=[a1, a2]).
What I'm searching for is not
qs = C.objects.filter(b__a__in=[a1, a2])
as my foreign keys are nullable, and I would also like to fetch cases in which any of the fks on the way is null.
What's the most elegant way to solve this ?
Thank you!
If I understand correctly, you want C instances for which b is null or b__a is null or b__a is one of (a1, a2). A possible solution here is to use the models.Q object to build an or query, ie:
from django.db.models import Q
query = Q(b__a__in=[a1, a2]) | Q(b__a__isnull=True) | Q(b__isnull=True)
qs = C.objects.filter(query)
or just "OR" querysets directly:
qs = C.objects.filter(b__a__in=[a1, a2]) | C.objects.filter(b__a__isnull=True) | C.objects.filter(b__isnull=True)
which will yield the very same SQL query but is a bit more verbose...

How can I get a full dict when I have performed a Many-to-one relationships?

class EbConfig(models.Model):
id = models.IntegerField(primary_key=True)
specific_field_config_id = models.IntegerField()
judge_result = models.CharField(max_length=50)
class EbResult(models.Model):
eb_config = models.ForeignKey(EbConfig, on_delete=models.CASCADE)
cc_log_info_base_id = models.BigIntegerField(primary_key=True)
eb_config_id = models.IntegerField()
result = EbResult.objects.filter(...)...
After satisfying my condition, I got a QuerySet named "result".
When I input:
result.select_related('eb_config').values()
I get something like this:
<QuerySet [{'eb_config_id': 1, 'cc_log_info_base_id': 10001},...>
But what I want to get is like this:
"<QuerySet [{'eb_config_id': 1, 'cc_log_info_base_id': 10001, 'id ':'', 'specific_field_config_id ':'', 'judge_result ':''},...>"
What can I do to get that?
I knew, I can get an object of EbConfig by:
list(test)[0].eb_config
But what I truely want is a full dict of EbConfig INNER JOIN EbResult.
When I print result.query, I find a right SQL sentence which can successfully run in MySQL and get a result I expect.
Soft ForeignKey and serializer.
You can totally perform it in Django.
serializer doc recommend by Willem Van Onsem in question comment
How can I perform ManyToOne without ForeignKey in db?

Django-orm Queryset for Find object by count a particular field

Let's say I have two models:
class Testmodel1():
amount = models.IntegerField(null=True)
contact = models.ForeignKey(Testmodel2)
entry_time = models.DateTimeField()
stage = choicesfiled
class Testmodel2():
name = models.CharField()
mobile_no = models.CharField()
I want to find out the object of Testmodel1 for contact > 3 which is created in the last 24 hours last = arrow.utcnow().shift(hours=-24).date().
I am applying a query:
n1=Testmodel1.objects.filter(entry_time__gte=last, stage=1).annotate(t_count=Count('contact')).filter(t_count__gt=3)
But it seems it's not working. Because I am getting an empty queryset.
Any help would be appreciated.
Only a partial answer. Sorry! Your code looks fine to me, so I'm just trying to find a solution by approaching it from a different direction.
Here's how I structure (sort of) similar code on one of my projects.
from datetime import timedelta, date
....
base_date = date.today()
start_date = base_date + timedelta(days=30)
end_date = base_date
possible_holidays = Holiday.objects.filter(
start_date__lte=start_date, end_date__gte=end_date)
From there, could you just do something like:
if possible_holidays.contact_set.count() > 3:
pass
Does that work?
The problem is your Many-to-One relationship is inverted. This relationship is a parent-child relationship, where a parent can have multiple children, but a children can only have one parent. In database this relationship is stored as a child's ForeignKey field that points to the child's parent.
In your case Testmodel1 is a parent and Testmodel2 is a child (Testmodel1 can have multiple contacts represented by Testmodel2) This means that ForeignKey field should belong to Testmodel2, not Testmodel1.
class Testmodel1():
amount = models.IntegerField(null=True)
entry_time = models.DateTimeField()
stage = choicesfiled
class Testmodel2():
name = models.CharField()
mobile_no = models.ForeignKey()
parent = models.ForeignKey(Testmodel1,
related_name='contacts',
)
With this model structure you can reference Testmodel1's contacts as testmodel1.contacts.all(). Your query then should look like this:
n1 = (Testmodel1.objects
.filter(entry_time__gte=last, stage=1)
.annotate(t_count=Count('contacts'))
.filter(t_count__gt=3)
)
docs reference

django filter based on field/column values

I have a model ModelA.
class ModelA:
m2m_1_field = models.BooleanField()
#lots of other fields
It has 2 m2m relations m2m_1 and m2m_2 both returning the same type.
If field m2m_1_field of ModelA is True, then we need to get the m2m results from m2m_1 (like instance.m2m_1.all()).
If field m2m_1_field of ModelA is False, then we need to get the m2m results from m2m_2 (Like instance.m2m_2.all()).
So, while searching this model, I also have to search these m2m relations.
Lets say, we need to search for m2m objects with ids 1 and 2. Then, we should do this:
if m2m_1_field is True:
for id in [1,2]:
queryset = queryset.filter(m2m_1__id=id)
if m2m_1_field is False:
for id in [1,2]:
queryset = queryset.filter(m2m_2__id=id)
Above is just theoritical explanation, how can we do it practically?
Or simply forget about m2m, just assume there are 2 more fields f1, f2 (both char fields). If m2m_1_field is True, we need to search f1 field and if m2m_1_field if False, we need to search f2 field. How ?
Just a guess:
filter(Q(m2m_1_field=True, f1=val) | Q(m2m_1_field=False, f2=val))) Is this right?
Please let me know for further clarification.
You're pretty close with your last example. I think what you want is the following:
I'm going to define what I assume your models are.
class M2MModel:
pass
class ModelA:
m2m_1_field = models.BooleanField()
m2m_1 = models.ManyToManyField(M2MModel, related_name="m2m_1_set", null=True, blank=True)
m2m_2 = models.ManyToManyField(M2MModel, related_name="m2m_2_set", null=True, blank=True)
In order to return the correct set of M2MModels back, you'd want to perform the query on M2MModel rather than ModelA.
model_a_id = SOME_ID_VALUE
results = M2MModel.objects.filter(
Q(m2m_1_set__id=model_a_id, m2m_1_set__m2m_1_field=True)
| Q(m2m_2_set__id=model_a_id, m2m_2_set__m2m_1_field=False)
).distinct()