As a follow-up to this question, I'd like to pinpoint the actual error that was occurring. Am I doing something wrong, or is this a bug?
f = {'groups__isnull': 'True'}
students1 = models.Student.objects.filter( **f )
students2 = models.Student.objects.filter(groups__isnull=True)
These two queries should be identical, but are not.
For reference, my models:
class Student (models.Model):
user = models.ForeignKey(User, unique=True, null=False, related_name='student')
teacher = models.ForeignKey(User, null=False, related_name='students')
assignment = models.ForeignKey(LabJournal, blank=True, null=True, related_name='students')
class JournalGroup (models.Model):
title = models.CharField(null=False, max_length=256)
owner = models.ForeignKey(User, null=True, related_name='journal_groups')
members = models.ManyToManyField(Student, blank=True, related_name='groups')
I see an obvious difference between queries.
{'groups__isnull': True} is never equal to {'groups__isnull': 'True'}.
One provides True as boolean, other as a string.
Related
I want to add one subquery to my query. And I created a #property in Transaction. Found on the Internet that this is what I need. But I do not fully understand how they work. How to use it?
views.py(Query)
paymentsss = Transaction.objects.all().select_related('currency',
'payment_source__payment_type',
'deal__service__contractor',).
models.py
class PayerPaymentSource(models.Model):
id = models.BigIntegerField(blank=True, null=False, primary_key=True)
payer_id = models.BigIntegerField(blank=True, null=True)
payment_type = models.ForeignKey(PaymentType, max_length=64, blank=True, null=True, on_delete=models.CASCADE)
source_details = models.TextField(blank=True, null=True) # This field type is a guess.
class Meta:
managed = False
db_table = '"processing"."payer_payment_source"'
class Transaction(models.Model):
id = models.BigIntegerField(blank=True, null=False, primary_key=True)
currency = models.ForeignKey(Currency, null=True, on_delete=models.CASCADE)
deal = models.ForeignKey(Deal, null=True, on_delete=models.CASCADE)
# service_instance = models.ForeignKey(ServiceInstance, null=True, on_delete=models.CASCADE)
payment_source = models.ForeignKey(PayerPaymentSource, null=True, on_delete=models.CASCADE)
payment_date = models.DateTimeField(blank=True, null=True)
amount = models.IntegerField(blank=True, null=True)
status = models.CharField(max_length=255, blank=True, null=True)
context = models.TextField(blank=True, null=True)
#property
def bank_card_details(self):
return PayerPaymentSource.objects.filter(self.payment_source.source_details,
payment_type='bank_card_details')
class Meta:
managed = False
db_table = '"processing"."transaction"'
UPD: print(payment.bank_card_details) works, but it creates a lot of similar queries. How to fix it?
The #property decorator is just a convenient way to call the property() function, which is built in to Python. This function returns a special descriptor object which allows direct access to the method's computed value.
For example in your view
obj = Transaction.objects.get(pk=pk)
#now you can get the bank_card_details like this:
print(obj.bank_card_details)
I want to make a request from two tables at once, I registered dependencies in the class. But the request does not work for me. What is wrong with him?
views.py
def payments(request):
paymentsss = Transaction.objects.select_related("currency_id")[:5]
return render(request, "payments.html", {"paymentsss": paymentsss})
models.py
class Transaction(models.Model):
id = models.BigIntegerField(blank=True, null=False, primary_key=True)
currency_id = models.ForeignKey(Currency, null=True, on_delete=models.CASCADE)
deal_id = models.ForeignKey(Deal, null=True, related_name='deal', on_delete=models.CASCADE)
service_instance_id = models.ForeignKey(ServiceInstance, null=True, related_name='service_instance', on_delete=models.CASCADE)
payment_source_id = models.ForeignKey(PayerPaymentSource, null=True, related_name='payment_source', on_delete=models.CASCADE)
payment_date = models.DateTimeField(blank=True, null=True)
amount = models.IntegerField(blank=True, null=True)
status = models.CharField(max_length=255, blank=True, null=True)
context = models.TextField(blank=True, null=True) # This field type is a guess.
class Meta:
managed = False
db_table = '"processing"."transaction"'`enter code here`
And Currency for example:
class Currency(models.Model):
id = models.SmallIntegerField(blank=True, null=False, primary_key=True)
name = models.CharField(max_length=128, blank=True, null=True)
iso_name = models.CharField(max_length=3, blank=True, null=True)
minor_unit = models.SmallIntegerField(blank=True, null=True)
class Meta:
managed = False
db_table = '"processing"."currency"'
My Error:
I would be glad if there is an example of how to make a larger request. From 3-4 tables.
Change the db_table
class Meta:
managed = False
db_table = 'processing.transaction'
class Meta:
managed = False
db_table = 'processing.currency'
You need to change the column names for the foreign keys: e.g. currency = ForeignKey(...) and deal = ForeignKey(...).
The field is a reference to the object itself, not to the id of the object. You can see that behind the scenes, Django queries using currency_id_id which doesn't make sense.
If your column name is currency_id (in your database), then your field name should be currency.
I have those classes (simplified for sake of clarity):
class Entity(models.Model):
adresses = models.ManyToManyField(Address,
related_name='persons',
through='EntityAddress')
class EntityAddress(models.Model):
entity = models.ForeignKey(Entity, on_delete=models.CASCADE,
blank=False, null=False)
address_type = models.ForeignKey(AddressType, models.CASCADE,
blank=False, null=False)
address = models.ForeignKey(Address, on_delete=models.CASCADE,
blank=False, null=False)
class Address(models.Model):
summary = models.CharField(max_length=250, blank=True, null=True)
way = PolygonField(default=None, blank=True, null=True)
class Person(Entity):
user = models.OneToOneField(User, blank=False, null=False,
on_delete=models.CASCADE)
I want to have all Person's whose addresses have a "not null" way.
I do it like this:
for p in Person.objects.all():
for e_a in EntityAddress.objects.filter(entity=p,
address__way__isnull=False,):
# do whatever here:
pass
This is way too slow!
Is there a way to make only one request?
You could do it maybe with a nested in query?
Something like:
not_null_ea = Entity.objects.filter(addresses__way__isnull=False).values('addresses')
for p in Person.objects.filter(
addresses__in=not_null_ea).prefetch_related('entityaddress_set):
for a_e in p.entityaddress_set:
pass
This way at least you would not be looping through Person objects yourself which really is quite slow.
I don't have a django project with concrete (multi-table) model inheritance at hand so I can't double-check it works, but theoretically this should do what you want:
Person.objects.filter(adresses__way__isnull=False)
This might help by the way...
Which way should I create multiple self referenced ForeignKey fields in Django model? My current Model looks like:
class WordCoreModel(models.Model, BaseModel):
word_core = models.CharField(max_length=255, default="")
word_russian_typed = models.CharField(max_length=255, default="", blank=True)
word_english_typed = models.CharField(max_length=255, default="", blank=True)
homonym = models.ForeignKey(
'self',
on_delete=models.CASCADE,
null=True, blank=True,
related_name="core_words",
related_query_name='homonym')
synonym = models.ForeignKey(
'self', on_delete=models.CASCADE,
null=True, blank=True,
related_name="core_words",
related_query_name='synonym')
antonym = models.ForeignKey(
'self', on_delete=models.CASCADE,
null=True, blank=True,
related_name="core_words",
related_query_name='antonym')
class Meta:
indexes = [models.Index(fields=['word_core'])]
verbose_name = 'Core Word'
verbose_name_plural = 'Core Words'
def __str__(self):
return self.word_core
Please give me some best-practices examples. I searched a lot for different solutions. I don’t find examples when there are several fields in the model.
I especially need help in determining related_name and related_query_name in this case.
I doubt that you need a ForeignKey here in the first place, since that would mean that a WordCoreModel has zero or one homonyms, zero or one synonyms, zero or one antonyms in one direction, and many in the other direction.
You likely want to use a ManyToManyField [Django-doc] here. That means that a word can have multiple homonyms, synonyms and antonyms, like:
class WordCoreModel(models.Model, BaseModel):
word_core = models.CharField(max_length=255, default='', db_index=True)
word_russian_typed = models.CharField(max_length=255, default='', blank=True)
word_english_typed = models.CharField(max_length=255, default='', blank=True)
homonyms = models.ManyToManyField('self')
synonyms = models.ManyToManyField('self')
antonyms = models.ManyToManyField('self')
class Meta:
verbose_name = 'Core Word'
verbose_name_plural = 'Core Words'
def __str__(self):
return self.word_core
By default, a ManyToManyField that refers to itself is symmetrical. That means that if a is a synonym of b, then b is a synonym of a. It also means that you do not need related_names here: there is no direction in the relation, so a WordCoreModel has only relations named homonyms, synonyms and antonyms.
Following are my models:
class A(models.Model):
owner = models.ForeignKey(User, null=False)
a_name= models.CharField(max_length=200, null=False, unique=True)
class B(models.Model):
owner = models.ForeignKey(User)
b_name= models.CharField(max_length=100, null=False)
class C(models.Model):
a= models.OneToOneField(
A,
on_delete=models.CASCADE,
null=False,
unique=True,
)
b= models.OneToOneField(
B,
on_delete=models.CASCADE,
null=False,
unique=True,
)
class D(models.Model):
c= models.OneToOneField(C,
on_delete=models.CASCADE,
null=False,
unique=True,
)
d1 = models.IntegerField(null=False, default=1)
I am trying to override the queryset in ListView generic class to get the list of all the objects in model 'D' where the 'owner' in model 'A' in current logged in user. I am unable to write the filter for the query.
D.objects.filter(self.c__a__owner==self.request.user)
But I am getting error as:
'MyListView' object has no attribute 'c__a__owner'
Please guide me how to achieve this.
Thanks.
Your query shouldn't have self. Also, you use a keyword assignment instead of a comparison in the filter method. It should like:
D.objects.filter(c__a__owner=self.request.user)