(Django) filtering objects in view - django

I have 2 classes in model
class A(models.Model):
name = models.CharField(max_length = 20)
class B(models.Model):
a = models.ForeignKey(A)
and I want to filter objects of B which does not have 'a' not has name of "exclude".
I tried
objects = B.objects.exclude(a.name == "exclude")
in my view, but it does not work.
How can I do this?

This will work:
objects = B.objects.exclude(a__name="exclude")

objects = B.objects.exclude(a__name="exclude")
or
from django.db.models import Q
objects = B.objects.filter(~Q(a__name="exclude"))
but the former one is good enough..

Related

how to access to property in view(django)

I'm beginner and I need some solution
First, I have Racket and Detail class.
class Racket(models.Model):
name = models.CharField(max_length=20)
class RacketDetail(models.Model):
racket = models.OneToOneField(Racket, related_name='detail', on_delete=models.CASCADE)
adminReview = models.TextField()
adminPower = models.FloatField(default=0)
adminSpin = models.FloatField(default=0)
adminManeuverability = models.FloatField(default=0)
adminStability = models.FloatField(default=0)
adminComfort = models.FloatField(default=0)
#property
def adminAvgScore(self):
scoreAvg = (
self.adminPower +
self.adminSpin +
self.adminManeuverability +
self.adminStability +
self.adminComfort
) / 5
return round(scoreAvg, 2)
Second, I want to rander list using the #property(adminAvgScore), so I made view like this.
def racketMain(request: HttpRequest):
getRacket = Racket.objects.all().order_by('detail__adminAvgScore')
return render(request, "racket/racketMain.html", {'racketItems': getRacket, })
Unfortunally when I use 'RacketDetail' class's column I can access all column except 'adminAvgScore' using by "order_by('detail__".
If I use like "order_by('detail__adminAvgScore')" then Django show to me error "Unsupported lookup 'adminAvgScore' for BigAutoField or join on the field not permitted."
How can I solve it? Or should I think in a different way?
You cannot use property with Query as Property is Function. You can use annotate and aggregate combination to get the result as your property function but inside a query.Something like this will do the trick.
from django.db.models import F, Sum, FloatField, Avg
Model.objects.filter(...)\
.values('id')\
.annotate(subtotal=Sum(...math here..., output_field=FloatField()))\
.aggregate(total=Avg(F('subtotal')))

Django reverse lookup foreign keys with multiple conditions

I am trying to do a reverse lookup in Django with multiple conditions, hopefully, my question does not duplicate with other questions. Let me explain:
I have two models:
Model A:
class A(models.Model):
title = models.CharField(max_length=200)
... other fields
Model B:
class B(models.Model):
a = models.ForeignKey(A)
label = models.CharField(max_length=200)
value = models.CharField(max_length=200)
... other fields
How can I get A that:
1) has a B with label = name, value=John
2) and, has a B with label =age, value =20
I tried the following, it does not work:
A.objects.filter(b__label="name", b__value="John", b__label="age", b__value=20)
You can use Q object:
from django.db.models import Q
A.objects.filter(
(Q(b__label="name") & Q(b__value="John")) | (Q(b__label="age") & Q(b__value=20))
)

How to declare and call a model method navigating through relations in django?

I Have 3 models
class Room(models.Model):
house = models.ForeignKey('Property', related_name='rooms')
beds = models.IntegerField(max_length=10)
class Property(models.Model):
......
def free_places():
places = 0
for r in self.rooms:
x = r.beds - ((r.tenant).size())
places = places + x
return places
class Profile(model.Models):
room = models.ForeignKey(Room, blank=True, null=True, related_name='tenant')
First of all I would like to know if free_places method should be: free_places(self) or free_places(). I think it has some errors too but I don't know how to test it, so here it's the question how can I call the method? and is it correct the function?
I want to call it from a django template.
To try it from "./manage.py shell" what do I need?
Thanks
It should be free_places(self):
You can define the method as a property and then call that from the template:
https://docs.djangoproject.com/en/dev/topics/db/models/#model-methods
Last example in that code block
def _free_places(self):
places = 0
for r in self.rooms:
x = r.beds - ((r.tenant).size())
places = places + x
return places
free_places = property(_free_places)

Django models order_by non db field

I have this model:
class Foo(models.Model):
foo_id = models.IntegerField()
foo_old_prize = models.FloatField()
foo_new_prize = models.FloatField()
def get_dif(self):
return self.foo_old_prize - self.foo_new_prize
Is there some trick how to do this Foo.objects.all().order_by('get_dif') ?
Thx
Look into the extra Django queryset operator:
q = Foo.objects.extra(select={'dif': 'foo_old_prize - foo_new_prize'})
q = q.extra(order_by = ['dif'])
You can use extra for this:
Foo.objects.extra(
select={'diff':'foo_old_prize - foo_new_prize'},
order_by=('diff',)
)
I'm not sure you can do it like that.
Here's another method that should work:
objList = Foo.objects.all()
objList.sort(key = get_dif)

Django ORM equivalent for this SQL..calculated field derived from related table

I have the following model structure below:
class Master(models.Model):
name = models.CharField(max_length=50)
mounting_height = models.DecimalField(max_digits=10,decimal_places=2)
class MLog(models.Model):
date = models.DateField(db_index=True)
time = models.TimeField(db_index=True)
sensor_reading = models.IntegerField()
m_master = models.ForeignKey(Master)
The goal is to produce a queryset that returns all the fields from MLog plus a calculated field (item_height) based on the related data in Master
using Django's raw sql:
querySet = MLog.objects.raw('''
SELECT a.id,
date,
time,
sensor_reading,
mounting_height,
(sensor_reading - mounting_height) as item_height
FROM db_mlog a JOIN db_master b
ON a.m_master_id = b.id
''')
How do I code this using Django's ORM?
I can think of two ways to go about this without relying on raw(). The first is pretty much the same as what #tylerl suggested. Something like this:
class Master(models.Model):
name = models.CharField(max_length=50)
mounting_height = models.DecimalField(max_digits=10,decimal_places=2)
class MLog(models.Model):
date = models.DateField(db_index=True)
time = models.TimeField(db_index=True)
sensor_reading = models.IntegerField()
m_master = models.ForeignKey(Master)
def _get_item_height(self):
return self.sensor_reading - self.m_master.mounting_height
item_height = property(_get_item_height)
In this case I am defining a custom (derived) property for MLog called item_height. This property is calculated as the difference of the sensor_reading of an instance and the mounting_height of its related master instance. More on property here.
You can then do something like this:
In [4]: q = MLog.objects.all()
In [5]: q[0]
Out[5]: <MLog: 2010-09-11 8>
In [6]: q[0].item_height
Out[6]: Decimal('-2.00')
The second way to do this is to use the extra() method and have the database do the calculation for you.
In [14]: q = MLog.objects.select_related().extra(select =
{'item_height': 'sensor_reading - mounting_height'})
In [16]: q[0]
Out[16]: <MLog: 2010-09-11 8>
In [17]: q[0].item_height
Out[17]: Decimal('-2.00')
You'll note the use of select_related(). Without this the Master table will not be joined with the query and you will get an error.
I always do the calculations in the app rather than in the DB.
class Thing(models.Model):
foo = models.IntegerField()
bar = models.IntegerField()
#Property
def diff():
def fget(self):
return self.foo - self.bar
def fset(self,value):
self.bar = self.foo - value
Then you can manipulate it just as you would any other field, and it does whatever you defined with the underlying data. For example:
obj = Thing.objects.all()[0]
print(obj.diff) # prints .foo - .bar
obj.diff = 4 # sets .bar to .foo - 4
Property, by the way, is just a standard property decorator, in this case coded as follows (I don't remember where it came from):
def Property(function):
keys = 'fget', 'fset', 'fdel'
func_locals = {'doc':function.__doc__}
def probeFunc(frame, event, arg):
if event == 'return':
locals = frame.f_locals
func_locals.update(dict((k,locals.get(k)) for k in keys))
sys.settrace(None)
return probeFunc
sys.settrace(probeFunc)
function()
return property(**func_locals)