making query using class method in Django - python

I am trying to use this way,
models.py
class Father(models.Model):
name = models.CharField(...)
def last_child_age(self):
children = self.child.order_by('-pk')
if len(children) > 0:
return find_Year(datetime.datetime.now()-children[0].birth_day)
return -1
class Child(models.model):
father = models.ForeignKey(Father, related_name='child')
birth_day = models.DateTimeField(auto_now_add=True)
views.py
def get_old_fathers(request):
father_list = Father.objects.filter(last_child_age__gte=15)
Returns:
Cannot resolve keyword
error.
What is the correct way of making this query other than iterating one by one.

You cant make queries using model class method (passing function to filter) in Django
If you need list of Father objects which have childs with age > 15 years:
d = datetime.date.today()
father_list = Father.objects.filter(
child__birth_day__lte=datetime.date(d.year-15, d.month, d.day))
Without adding flags to Child you can decide which is last (youngest) by making subqueries to child table. Annotation with max birthday (last son -> bigger birth_day date) can help. Try this query (im not test it):
from django.db.models import Max
father_list = Father.objects.annotate(max_birthday=Max('child__birth_day')
).filter(max_birthday__lte=datetime.date(d.year-15, d.month, d.day))

You have not posted your Child model and last_child_age code, but something like this should work:
Child.objects.filter(age__gte=15).prefetch_related('father')

last_child_age is a method, not a column. ORM queries generate SQL, and SQL don't know zilch about your models methods - how would the SQL database call back on your Python code ?

Related

get all from table django not only __str__(self)

models.py
class club(models.Model):
name = models.CharField(max_length=30)
city = models.CharField(max_length=30)
premiere_leauge = models.BooleanField(default=False)
def __str__(self):
return self.name
Views.py
...
a = request.POST['club']
b = request.POST['city']
result = club.objects.all.get(name__exact=a, city__exact=b)
....
All is fine, however I believe result returns me:
def __str__(self):
return self.name
Whatsover, I would like an equivalent of 'SELECT * FROM APP_CLUB where name='something and city='something'; so i would be able to do further manipulation in django like:
if result[3] is True:
do_something()
As suggested in the offical documentation:
club.objects.filter(name='something')
It will return exactly the same as:
'SELECT * FROM APP_CLUB where name='something';
Example:
clubs = club.objects.filter(name__exact='something')
for club in clubs:
if club.premier_league:
do_something()
If you want to get only one club, then do it like this:
club = club.objects.get(name='something')
premier_league_value_of_club = club.premier_league
Use filter instead of get.
results = club.objects.filter(name__exact=a, city__exact=b)
You can then iterate over it to access all the model attributes like below
for result in results:
print result.name, result.city, result.premier_league
Also, according to PEP-8, you should name your class name should ideally be titlecase Club instead of lowercase club.
You're nearly there, I think you're missing the filter function here. You can use it like this :
a = request.POST['club']
b = request.POST['city']
result = club.objects.filter(name__exact=a, city__exact=b)
It will return you a query set with the actual database entries.
The __str__(self) function is used in transforming your query set entry into a string, whether you string-cast it or print it.
Then about this :
if result[3] is True:
do_something()
I don't get well what you mean about this, but if 3 is the id of the entry in the database, you then can do this :
if result.get(id=3).premiere_leauge:
do_something()
But you might want to check if the entry with the id exists first to avoid errors :
if result.filter(id=3).exists() and result.get(id=3).premiere_leauge:
do_something()
You should modify you query as shown below
result = club.objects.filter(name__exact=a, city__exact=b)
Good Luck !!

Looking for ForeignKey active and add to QuerySet

class Control(models.Model):
period = models.DurationField()
active = models.BooleanField()
device_collection = models.ForeignKey(DeviceSet)
class DeviceSet(models.Model):
name = models.CharField()
date_last_control = models.DateField()
def get_next_control(self):
return self.date_last_control + self.control_actif.period
#property
def control_actif(self):
if not hasattr(self, "_control"):
setattr(self, "_control", self.control_set.get(active=True))
return self._control
There are several Control associated with DeviceSet but only one Control which is active by DeviceSet.
I'd like to get the active Control of the DeviceSet when I get the queryset in a column _control.
I already try :
DeviceSet.objects.annotate(_control = Q(control__active=True))
That don't work
'WhereNode' object has no attribute 'output_field'
And after set output_field=Control I have the following exception:
type object 'Control' has no attribute 'resolve_expression'
I just want to have like a prefetch_related with filter but in a new column to use the _control attribute in model's method.
You are getting errors from what you've attempted because annotate method needs an aggregate function (eg Sum, Count etc) rather than a Q object.
Since Django 1.7 it's possible to do what you want using prefetch_related, see docs here:
https://docs.djangoproject.com/en/1.8/ref/models/querysets/#django.db.models.Prefetch
DeviceSet.objects.prefetch_related(
Prefetch('control_set',
queryset=Control.objects.filter(active=True),
to_attr='_control')
)

hierarchal permission on same model

Sorry, I couldn't find a suitable title, please edit the title if you understood the problem.
I want to achieve 4 level hierarchy (django Group): Country-Manager,State-Manager, City-Manager and Field-staff.
One user can belong to only one group at a time and any user can add a lead.
I have a model named Lead and I want to realize the following hierarchy:
"User of higher level (say State-Manager) can view leads added by him and and all entries added by users of lower level (say City-Manager and Field Staff) but can not view entries added by other users of same level or higher lever (say Country-Manager)"
To keep track who has added the entry, I am saving user and Group object as foreign key in the Lead model.
Please suggest any strategy or code snippet.
--
p.s: I am on Django 1.5
I solved this problem with help of mixins. ( http://eflorenzano.com/blog/2008/05/17/exploring-mixins-django-model-inheritance/ )
for I create a Hierarchy class:
class Hierarchy(models.Model):
parent = models.ForeignKey('self',null=True,blank=True)
def get_children(self):
return self._default_manager.filter(parent=self)
def get_descendants(self):
descs = set(self.get_children())
for node in list(descs):
descs.update(node.get_descendants())
return descs
class Meta:
abstract = True
and inherited it in class named GroupHirerarchy:
class GroupHierarchy(Hierarchy):
group = models.ForeignKey(Group)
def __unicode__(self):
return self.group.name
Now I can get children of a group using
group_object.get_children()
and all descendants by :
group_object.get_descendants()
Now using this I achieve get hierarchical permission on model:
glist = []
groups = request.user.groups.all()
for group in groups:
try:
group_hierarchy = GroupHierarchy.objects.get(group = group)
group_descendants = group_hierarchy.get_descendants()
for group_descendant in group_descendants:
glist.append(Group.objects.get(name=group_descendant.group))
except:
pass
obj = Model.objects.filter(user_group__in = glist)

sqlalchemy access parent class attribute

Looking at the bottom of the post you can see i have three classes. The code here is pseudo code written on the fly and untested however it adequately shows my problem. If we need the actual classes I can update this question tomorrow when at work. So ignore syntax issues and code that only represents a thought rather than the actual "code" that would do what i describe there.
Question 1
If you look at the Item search class method you can see that when the user does a search i call search on the base class then based on that result return the correct class/object. This works but seems kludgy. Is there a better way to do this?
Question 2
If you look at the KitItem class you can see that I am overriding the list price. If the flag calc_list is set to true then I sum the list price of the components and return that as the list price for the kit. If its not marked as true I want to return the "base" list price. However as far as I know there is no way to access a parent attribute since in a normal setup it would be meaningless but with sqlalchemy and shared table inheritance it could be useful.
TIA
class Item(DeclarativeBase):
__tablename__ = 'items'
item_id = Column(Integer,primary_key=True,autoincrement=True)
sku = Column(Unicode(50),nullable=False,unique=True)
list_price = Column(Float)
cost_price = Column(Float)
item_type = Column(Unicode(1))
__mapper_args__ = {'polymorphic_on': item_type}
__
def __init__(self,sku,list_price,cost_price):
self.sku = sku
self.list_price = list_price
self.cost_price = cost_price
#classmethod
def search(cls):
"""
" search based on sku, description, long description
" return item as proper class
"""
item = DBSession.query(cls).filter(...) #do search stuff here
if item.item_type == 'K': #Better way to do this???
return DBSession.query(KitItem).get(item.item_id)
class KitItem(Item):
__mapper_args__ = {'polymorphic_identity': 'K'}
calc_list = Column(Boolean,nullable=False,default=False)
#property
def list_price(self):
if self.calc_list:
list_price = 0.0
for comp in self.components:
list_price += comp.component.list_price * comp.qty
return list_price
else:
#need help here
item = DBSession.query(Item).get(self.item_id)
return item.list_price
class KitComponent(DeclarativeBase):
__tablename__ = "kit_components"
kit_id = Column(Integer,ForeignKey('items.item_id'),primarykey=True)
component_id = Column(Integer,ForeignKey('items.item_id'),primarykey=True)
qty = Column(Integer,nullable=False, default=1)
kit = relation(KitItem,backref=backref("components"))
component = relation(Item)
Answer-1: in fact you do not need to do anything special here: given that you configured your inheritance hierarchy properly, your query will already return proper class for every row (Item or KitItem). This is the advantage of the ORM part. What you could do though is to configure the query to immediatelly load also the additional columns which do belong to children of Item (from your code this is only calc_list column), which you can do by specifying with_polymorphic('*'):
#classmethod
def search(cls):
item = DBSession.query(cls).with_polymorphic('*').filter(...) #do search stuff here
return item
Read more on this in Basic Control of Which Tables are Queried.
To see the difference, enabled SQL logging, and compare your tests scripts with and without with_polymorphic(...) - you will most probably require less SQL statements being executed.
Answer-2: I would not override one entry attributed with one which is purely computed. Instead I would just create another computed attribute (lets call it final_price), which would look like following for each of two classes:
class Item(Base):
...
#property
def total_price(self):
return self.list_price
class KitItem(Item):
...
#property
def total_price(self):
if self.calc_list:
_price = 0.0
for comp in self.components:
_price += comp.component.list_price * comp.qty
return _price
else:
# #note: again, you do not need to perform any query here at all, as *self* is that you need
return self.list_price
Also in this case, you might think of configuring the relationship KitItem.components to be eagerly loaded, so that the calculation of the total_price will not trigger additional SQL. But you have to decide yourself if this is beneficial for your use cases (again, analyse the SQLs generated in your scenario).

how to get entities which don't have certain attribute in datastore

I'm trying to make an appraisal system
This is my class
class Goal(db.Expando):
GID = db.IntegerProperty(required=True)
description = db.TextProperty(required=True)
time = db.FloatProperty(required=True)
weight = db.IntegerProperty(required=True)
Emp = db.UserProperty(auto_current_user=True)
Status = db.BooleanProperty(default=False)
Following things are given by employee,
class SubmitGoal(webapp.RequestHandler):
def post(self):
dtw = simplejson.loads(self.request.body)
try:
maxid = Goal.all().order("-GID").get().GID + 1
except:
maxid = 1
try:
g = Goal(GID=maxid, description=dtw[0], time=float(dtw[1]), weight=int(dtw[2]))
g.put()
self.response.out.write(simplejson.dumps("Submitted"))
except:
self.response.out.write(simplejson.dumps("Error"))
Now, here Manager checks the goals and approve it or not.. if approved then status will be stored as true in datastore else false
idsta = simplejson.loads(self.request.body)
try:
g = db.Query(Goal).filter("GID =", int(idsta[0])).get()
if g:
if idsta[1]:
g.Status=True
try:
del g.Comments
except:
None
else:
g.Status=False
g.Comments=idsta[2]
db.put(g)
self.response.out.write(simplejson.dumps("Submitted"))
except:
self.response.out.write(simplejson.dumps("Error"))
Now, this is where im stuck..."filter('status=',True)".. this is returning all the entities which has status true.. means which are approved.. i want those entities which are approved AND which have not been assessed by employee yet..
def get(self):
t = []
for g in Goal.all().filter("Status = ",True):
t.append([g.GID, g.description, g.time, g.weight, g.Emp])
self.response.out.write(simplejson.dumps(t))
def post(self):
idasm = simplejson.loads(self.request.body)
try:
g = db.Query(Goal).filter("GID =", int(idasm[0])).get()
if g:
g.AsmEmp=idasm[1]
db.put(g)
self.response.out.write(simplejson.dumps("Submitted"))
except:
self.response.out.write(simplejson.dumps("Error"))
How am I supposed to do this? as I know that if I add another filter like "filter('AsmEmp =', not None)" this will only return those entities which have the AsmEmp attribute what I need is vice versa.
You explicitly can't do this. As the documentation states:
It is not possible to query for entities that are missing a given property.
Instead, create a property for is_assessed which defaults to False, and query on that.
could you not simply add another field for when employee_assessed = db.user...
and only populate this at the time when it is assessed?
The records do not lack the attribute in the datastore, it's simply set to None. You can query for those records with Goal.all().filter('status =', True).filter('AsmEmp =', None).
A few incidental suggestions about your code:
'Status' is a rather unintuitive name for a boolean.
It's generally good Python style to begin properties and attributes with a lower-case letter.
You shouldn't iterate over a query directly. This fetches results in batches, and is much less efficient than doing an explicit fetch. Instead, fetch the number of results you need with .fetch(n).
A try/except with no exception class specified and no action taken when an exception occurs is a very bad idea, and can mask a wide variety of issues.
Edit: I didn't notice that you were using an Expando - in which case #Daniel's answer is correct. There doesn't seem to be any good reason to use Expando here, though. Adding the property to the model (and updating existing entities) would be the easiest solution here.

Categories