Django ORM call manager method from another manager? - python

Any tips on how I should be accessing other manager methods from within Manager.py?
No matter what I do, I can't seem to access my other manager's method. Python complains that it isn't defined...
Is it going to cause problems if I import models inside of managers.py? Circular includes or whatever?
managers.py:
# Returns the whole family who are active
def get_active_dependents_including_guardian( self, consumer, connectedOnly = False ):
logger.debug('get_active_dependents_including_guardian')
results = self.model.objects.filter( guardian = consumer,
is_active = True ).order_by('dob')
if connectedOnly:
from myir import models
#OPTIMIZE: this can be optimized if I query for all patient ids for each dependent in one trip. But I don't even know how to do this yet cause I'm a noob.
results = [d for d in results if models.DependentPatientID.objects.get_patient_ids(d)[0].patient_id_integer == 0] **#HERE IS PROBLEM**
return results
# some stuff omitted...
# this is the manager of models.DependentPatientId
class DependentPatientIDManager( models.Manager ):
def get_patient_ids(self, dependent ):
dpid = self.model.objects.get( dependent = dependent.id )
return dpid

You need to change:
from myir import models
to
from myir.models import DependentPatientID
The reason being, you might have already done from django.db import models and the names are conflicting.
Now,
class DependentPatientIDManager( models.Manager ):
def get_patient_ids(self, dependent ):
dpid = self.model.objects.get( dependent = dependent.id )
return dpid
returns an object, and not a queryset. So, DependentPatientID.objects.get_patient_ids(d)[0] would fail.
So try this
if connectedOnly:
from myir.models import DependentPatientID
patient_id_integer = 0
dep_patient_id = DependentPatientID.objects.get_patient_ids(d)
if dep_patient_id:
patient_id_integer = dep_patient_id.patient_id_integer
results = [d for d in results if patient_id_integer == 0]
#Or just
if not patient_id_integer:
results = []

Related

How can I intercept database requests(Peewee ORM) in pytest?

I have a main database and a replica (they are the same in the test environment):
core_db = PooledPostgresqlExtDatabase(**DB_COFIG)
replica_db = PooledPostgresqlExtDatabase(**DB_REPLICA_COFIG)
A controllers that executes a query in different databases depending on the model
class BaseController:
def _get_logs(self):
query = self.model.select()
if is_instance(self.model, ModelToReplica)
query = query.bind(replica_db)
return list(query)
class ReplicaExampleController(BaseLogsController):
model = ModelToReplica
def process(self):
return self._get_logs()
class BaseExampleController(BaseLogsController):
model = BaseModel
def process(self):
return self._get_logs()
Controllers are linked to two urls:
/get_core_result/ # Returns the result from BaseExampleController (core_db)
/get_replica_result/ # Returns the result from ReplicaExampleController (replica_db)
I want to check that each of the corners accesses the right base. And I know that the reference to the database object is stored in the request object. How do I get it from the test? I'm using a PyTest. I understand that I probably need to use mock, but I don't understand how.
Unfortunately, this is all I have so far:
class TestSwitchDB:
def test_switch_db_to_replica():
url_core = url_for('core_db_controller')
core_result = self.client.get(url_core)
url_replica = url_for('replica_db_controller')
replica_result = self.client.get(url_replica)
In test_switch_db_to_replica you can mock the db query and patch it, something
with patch(BaseController._get_logs) as mock_get_logs:
mock_get_logs.return_value="your expected return"
As a reference: https://docs.python.org/3/library/unittest.mock-examples.html

Return missing values in google app engine query

In google app engine, say I have a Parent and a Child Entity:
class Parent(ndb.Model):
pass
class Child(ndb.Model):
parent_key = ndb.KeyProperty(indexed = True)
... other properties I don't need to fetch ...
I have a list of parents' keys, say parents_list, and I'm trying to answer efficiently: what parent in parents_list has a child.
Ideally, I would run this query:
children_list = Child.query().filter(Child.parent_key = parents_list).fetch(projection = 'parent_key')
It does not work because of the projection property (parent_key) being in the equality filter. So I would have to retrieve all properties, which seems inefficient.
Is there a way to efficiently solve this?
Your child model should actually be
class Child(ndb.Model):
parent_key = ndb.KeyProperty(kind="Parent", indexed = True)
If you were doing this in Python2, you could use an ndb_tasklet (see code below; note that I haven't executed this code myself so it's not guaranteed to work; it's just here to serve as a guide but I have used tasklets in the past before). If python3, try and create async queries
class Parent(ndb.Model):
#classmethod
def parentsWithChildren(cls, parents_list):
#ndb.tasklet
def child_callback(parent_key):
q = Child.query(Child.parent_key == parent_key)
output = yield q.fetch_async(projection = 'parent_key')
raise ndb.Return ((parentKey, output))
# For each key in parents_list, invoke the callback - child_callback which returns a result only if the parent_key matches
# ndb.tasklet is asynchronous so code is run in parallel
final_output = [ child_callback(a) for a in parents_list]
return final_output

Django Python Where to add Auxiliary Functions to not repeat code?

I come from native POO programming languages and I'm new in Python, also Django.
I see that in Django they put all code from an app in same views.py or models.py.
Now I'm in a view called:
def create_ticket(self):
....
And inside I have this code
is_staff=User.objects.get(pk=request.user.id).is_staff
if is_staff==1:
R_Client_Accountant = LinkUserContable.objects.filter(contable=mongoId)
print(R_Client_Accountant)
accountantList = []
for relation in R_Client_Accountant:
try:
rmongosql = RMongoSql.objects.get(mongoId=relation.user.id)
user = User.objects.get(pk=rmongosql.helpdeskId)
accountantList.append((user.id,user.username))
except:
pass
else:
R_Client_Accountant = LinkUserContable.objects.filter(user=mongoId)
accountantList = []
for relation in R_Client_Accountant:
try:
rmongosql = RMongoSql.objects.get(mongoId=relation.contable.id)
user = User.objects.get(pk=rmongosql.helpdeskId)
accountantList.append((user.id,user.username))
except:
pass
As you can see I repeat code inside the 'try' just exchanging {user XOR contable}
If I want to write a function passing by parameter this {user XOR contable} where should I place it ?
To me, in corresponding model from models.py is not correct because there are so much code lines referring to different models and views.py is just for view functions right ?
Regards,
VĂ­ctor.
you can use the getattr function to use a string to get the required attribute getattr(relation, relation_attr)
your function would look like this
def create_ticket(self):
is_staff=User.objects.get(pk=request.user.id).is_staff
if is_staff==1:
relation_attr = 'user'
else:
relation_attr = 'contable'
R_Client_Accountant = LinkUserContable.objects.filter(contable=mongoId)
print(R_Client_Accountant)
accountantList = []
for relation in R_Client_Accountant:
try:
rmongosql = RMongoSql.objects.get(mongoId=getattr(relation, relation_attr).id)
user = User.objects.get(pk=rmongosql.helpdeskId)
accountantList.append((user.id, user.username))
except:
pass

Django getting objects from a mixin

I have a small model method I'm using to get the previous and next object relative to the current object. It looks something like this:
class Article
...
def get_prev_next(self):
articles = list(Article.objects.all())
i = articles.index(self)
try:
p = articles[i - 1]
except IndexError:
p = None
try:
n = articles[i + 1]
except IndexError:
n = None
return {'prev': p, 'next': n}
It works, and may well be inefficient, but now I want to use it in a different model.
I'd like to make this into a mixin, but I can't figure out how to get the original model class name so I can run Model.objects.all() and get my list.
I have so far:
class PrevNextMixin(object):
objects = list(???.objects.all())
i = objects.index(self)
...
A mixin is still a class. The code still needs to go into a method. That method will get a self argument just as it does now.
class PrevNextMixin(object):
def get_prev_next(self):
objects = list(self.__class__.objects.all())

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