display rawqueryset value in a model using django #property field - python

I am trying to insert a #property field into a django model.
However this field gets its value from a RawQuerySet like so;
class Medication_List(models.Model):
id = models.AutoField(primary_key=True)
medication_name = models.CharField(max_length=250, blank=True, editable=True)
...
def stock_level(self):
# "Returns the totalstock remaining"
current_stock = Medications_Bridge.objects.raw("SELECT T3.total_quantity_sold AS total_quantity_sold FROM (SELECT * FROM ...
return({'current_stock' : current_stock})
stock = property(stock_level)
def __str__(self):
return "%s %s %s" % (self.medication_name, self.supplier,self.stock)
This works fine with no errors, but django is not showing value for the queryset in the str function, rather it just shows the whole query just as it was written above. i.e. "SELECT T3.total_quantity....."
I want to know if it is even possible to use #property field to show a value from another unrelated database table.
I have seen some examples on StackOverflow where calculated values are shown using values from the same model with help of self.field_name but i cant find any example where the values for the calculations are derived from another model or from a raw SQL query.
Kindly help. Any hint will be very much appreciated. Thanks

Okay so upon further reading, i just found from this post
Django RawQuerySet not working as expected
that QuerySets in django are not evaluated until necessary, that is, it does not hit the database until necessary.
Upon following the links to the QuerySet API i was able to find a way to do exactly what i wanted.
As is mostly always the case, you find the answer soon after you blurt out the question. LOL

Related

Prefetch object not working with order_by queryset

Using Django 11 with PostgreSQL db. I have the models as shown below. I'm trying to prefetch a related queryset, using the Prefetch object and prefetch_related without assigning it to an attribute.
class Person(Model):
name = Charfield()
#property
def latest_photo(self):
return self.photos.order_by('created_at')[-1]
class Photo(Model):
person = ForeignKey(Person, related_name='photos')
created_at = models.DateTimeField(auto_now_add=True)
first_person = Person.objects.prefetch_related(Prefetch('photos', queryset=Photo.objects.order_by('created_at'))).first()
first_person.photos.order_by('created_at') # still hits the database
first_person.latest_photo # still hits the database
In the ideal case, calling person.latest_photo will not hit the database again. This will allow me to use that property safely in a list display.
However, as noted in the comments in the code, the prefetched queryset is not being used when I try to get the latest photo. Why is that?
Note: I've tried using the to_attr argument of Prefetch and that seems to work, however, it's not ideal since it means I would have to edit latest_photo to try to use the prefetched attribute.
The problem is with slicing, it creates a different query.
You can work around it like this:
...
#property
def latest_photo(self):
first_use_the_prefetch = list(self.photos.order_by('created_at'))
then_slice = first_use_the_prefetch[-1]
return then_slice
And in case you want to try, it is not possible to use slicing inside the Prefetch(query=...no slicing here...) (there is a wontfix feature request for this somewhere in Django tracker).

Django Model: Default method for field called multiple times

I have the following two models (just for a test):
class IdGeneratorModel(models.Model):
table = models.CharField(primary_key=True, unique=True,
null=False, max_length=32)
last_created_id = models.BigIntegerField(default=0, null=False,
unique=False)
#staticmethod
def get_id_for_table(table: str) -> int:
try:
last_id_set = IdGeneratorModel.objects.get(table=table)
new_id = last_id_set.last_created_id + 1
last_id_set.last_created_id = new_id
last_id_set.save()
return new_id
except IdGeneratorModel.DoesNotExist:
np = IdGeneratorModel()
np.table = table
np.save()
return IdGeneratorModel.get_id_for_table(table)
class TestDataModel(models.Model):
class Generator:
#staticmethod
def get_id():
return IdGeneratorModel.get_id_for_table('TestDataModel')
id = models.BigIntegerField(null=False, primary_key=True,
editable=False, auto_created=True,
default=Generator.get_id)
data = models.CharField(max_length=16)
Now I use the normal Django Admin site to create a new Test Data Set element. What I expected (and maybe I'm wrong here) is, that the method Generator.get_id() is called exactly one time when saving the new dataset to the database. But what really happens is, that the Generator.get_id() method is called three times:
First time when I click the "add a Test Data Set" button in the admin area
A second time shortly after that (no extra interaction from the user's side)
And a third time when finally saving the new data set
The first time could be OK: This would be the value pre-filled in a form field. Since the primary key field is not displayed in my form, this may be an unnecessary call.
The third time is also clear: It's done before saving. When it's really needed.
The code above is only an example and it is a test for me. In the real project I have to ask a remote system for an ID instead from another table model. But whenever I query that system, the delivered ID gets locked there - like the get_id_for_table() method counts up.
I'm sure there are better ways to get an ID from a method only when really needed - the method should be called exactly one time - when inserting the new dataset. Any idea how to achieve that?
Forgot the version: It's Django 1.8.5 on Python 3.4.
This is not an answer to your question, but could be a solution to your problem
I believe this issue is very complicated. Especially because you want a transaction that spans a webservice call and a database insert... What I would use in this case: generate a uuid locally. This value is practially guaranteed to be unique in the 4d world (time + location) and use that as id. Later, when the save is done, sync with your remote services.

Using Property to duck type two models

I have a django model that can have one of two objects related to it via foreign key (call them object1 and object2). The two other classes are functionally almost identical, but contain slightly different information. At the suggestion of another StackOverflow question, I am using the python method property() to set and get whichever object is present. It looks like the following:
class Master(models.Model):
object1=models.ForeignKey(Object1, null=True)
object2=models.ForeignKey(Object2, null=True)
def get_object(self):
if self.object2_id:
return self.object2
else:
return self.object1
def set_object(self, instance):
if isinstance(instance, Object2):
self.object2 = instance
self.object1 = None
else:
self.object2 = None
self.object1 = instance
objectInstance = property(get_object, set_object)
This is a simplified version of the class. I thought everything was working correctly. I was able to set, and get the information, and could display the data held in objectInstance on several of my pages. I'm using django-tables2 to display information in tables, and it too was able to show all the information. However, when I attempt to sort the data (using the convenient arrows that are provided) I get a FieldError:
FieldError at /workflow/list/request/
Cannot resolve keyword u'objectInstance' into field. Choices are: object1, object2
Any idea what's causing this? Or what snippet of code you'd need to see to help determine what the cause is?
EDIT:
So it looks like I'm not the only one with this problem. This post seems to indicate that it's a problem with django-tables2. Non-queryset data ordering in django-tables2
It seems that while the table can display information held in a property it has trouble sorting it.
If you want to use a decorator, see this response.
But the best way is using Generic relations
EDIT
Maybe that:
class Master(models.Model):
content_type = models.ForeignKey(ContentType)
object_id = models.PositiveIntegerField()
objectInstance = generic.GenericForeignKey('content_type', 'object_id')
So, you can do:
>>> t = Master(objectInstance=Object2())
>>> t.save()
>>> t.objectInstance
<Object2: a_description>
>>> t.objectInstance = Object1()
>>> t.save()
>>> t.objectInstance
<Object1: a_description>
Hope this helps!
Found an answer.
The problem was that django-tables2 didn't know how to order non-queryset data. This was solved by explicitly giving the table an order_by argument for each column.
Documentation is here: http://django-tables2.readthedocs.org/en/latest/#specifying-alternative-ordering-for-a-column

Django dynamic class cannot be updated

I have a set of DB tables which store customer order counts per minute per day. Each month of the year is a different table in order to avoid excessively large tables. In order to retrieve this data in my Django webpage, I dynamically create a model class with db_table being populated based on the date received from an html form input. The problem is that when I resubmit the form with a new date value, the class does not update to what should be the new model, it still maintains the old value.
My models.py looks something like this:
class baseModel(models.Model):
id = models.CharField(max_length=40)
date = models.IntegerField()
minute = models.IntegerField()
totalorders = models.IntegerField()
class Meta:
abstract = True
managed = False
def getModel(type, yyyymm):
if type == 'duration':
class DurationClass(baseModel):
medianduration = models.IntegerField()
avgduration = models.IntegerField()
class Meta:
db_table='orderTable' + yyyymm
#debug statement
print db_table
return DurationClass
yyyymm is just a string, like '201204' for April 2012. So if I enter April 2012 into the input box it works fine but then if I change to March 2012, it still queries for April data. I can see from the debug statement that db_table is being properly updated, but for some reason it's not working. Do I need to deallocate the old dynamic model before allocating a new one or something? In view.py, I'm just doing this (not in a loop):
myModel = getModel('duration', startyyyymm)
QS = myModel.objects.using( ...etc
Many thanks for any ideas.
You have a problem about how python manage the creation of dynamic clases. I don't know exactly how python works, but it seems to be that the way you do it is not totally correct. I think it is because python classes are attached to one module, so the first time you execute "getModel" it creates the model as you expect. But, after that, every time you execute "getModel", as the class has always the same name, python can't create the same class at the same module, so it somehow returns you the same class you create the first time you call "getModel". (I hope you understand my English, although i might be wrong about how python dynamic classes creation works)
I search a little and make some tests before giving you an answer. It seems to be that the best way of creating a dynamic class is using "type" (python built-in method), so you can create one class per table (this classes must have a different name).
Here's an example of what you can do (it worked for me):
def getModel(type, yyyymm):
if type == 'duration':
newModelClass = type(
'newModelName', #It could be the table name you are going to search in. It must be different for every different db table you want to use. For example: 'orderTable' + yyyymm
(baseModel, ), #Base class for your new model
{
'medianduration' : models.IntegerField(), #New model's attribute
'avgduration' : models.IntegerField(), #New model's attribute
'__module__':__name__, #This is required. If not given, type raises a KeyError
'Meta': type(
'Meta',
(object,),
{
'db_table':'orderTable' + yyyymm, #Here you put the table name you want to use
'__module__':__name__,
}
)
}
)
return newModelClass
If i didn't make any copy/paste mistake, it should now work for you.
Again, sorry if i make any English mistake. I'm a little bit rusty at writing in English and in English in general :S
I hope it helps you. Althought i agree that your database should work fine without using multiple tables...
All you need is given the below link: https://code.djangoproject.com/wiki/DynamicModels

Django Query using .order_by() and .latest()

I have a model:
class MyModel(models.Model):
creation_date = models.DateTimeField(auto_now_add = True, editable=False)
class Meta:
get_latest_by = 'creation_date'
I had a query in my view that did the following:
instances = MyModel.objects.all().order_by('creation_date')
And then later I wanted instances.latest(), but it would not give me the correct instance, in fact it gave me the first instance. Only when I set order_by to -creation_date or actually removed the order_by from the query did .latest() give me the correct instance. This also happens when I test this manually using python manage.py shell instead of in the view.
So what I've done now is in the Model's Meta I've listed order_by = ['creation_date'] and not used that in the query, and that works.
I would have expected .latest() to always return the most recent instance based on a (date)(time) field. Could anyone tell me whether it's correct that .latest() behaves strangely when you use order_by in the query?
I would have expected .latest() to always return the most recent instance based on a (date)(time) field.
The documentation says that
If your model's Meta specifies get_latest_by, you can leave off the field_name argument to latest(). Django will use the field specified in get_latest_by by default.
All this means is that when you fire MyModel.objects.latest() you will get the latest instance based on the date/time field. And when I tested your code using sample data, it indeed did.
And then later I wanted instances.latest(), but it would not give me the correct instance, in fact it gave me the first instance.
You have misunderstood the way latest() works. When called on MyModel.objects it returns
the latest instance in the table. When called on a queryset, latest will return the first object in the queryset. Your queryset consisted of all instances of MyModel ordered by creation_date in ascending order. It is only natural then that latest on this queryset should return the first row of the queryset. This incidentally happens to be the oldest row in the table.
One way to get a better understanding is to view the query fired for latest.
Case 1:
from django.db import connection
MyModel.objects.latest()
print connection.queries[-1]['sql']
This prints:
SELECT "app_mymodel"."id", "app_mymodel"."creation_date" FROM
"app_mymodel" ORDER BY "app_mymodel"."creation_date" DESC LIMIT 1
Note the ordering by creation_date DESC and the LIMIT clause. The former is thanks to get_latest_by whereas the latter is the contribution of latest.
Now, case 2:
MyModel.objects.order_by('creation_date').latest()
print connection.queries[-1]['sql']
prints
SELECT "app_mymodel"."id", "app_mymodel"."creation_date" FROM
"app_mymodel" ORDER BY "app_mymodel"."creation_date" ASC LIMIT 1
Note that the ordering has changed to creation_date ASC. This is the result of the explicit order_by. The LIMIT is tacked on er, later courtesy latest.
Let us also see Case 3: where you explicitly specify the field_name for objects.latest().
MyModel.objects.latest('id')
print connection.queries[-1]['sql']
shows
SELECT "app_mymodel"."id", "app_mymodel"."creation_date" FROM "app_mymodel"
ORDER BY "app_mymodel"."id" DESC LIMIT 1
I guess this is a known bug in Django that was fixed after 1.3 was released.
This worked for me
latestsetuplist = SetupTemplate.objects.order_by('-creationTime')[:10][::1]
if we have the value of id or date
post_id = BlogPost.objects.get(id=id)
try:
previous_post = BlogPost.objects.all().order_by('id')[post_id.id-2:post_id.id-1]
except:
previous_post = None
try:
next_post = BlogPost.objects.all().order_by('id')[post_id.id:post_id.id+1]
except:
next_post = None
it worked for me, even if an id is missing it picks next or previous value to that

Categories