Is there a way to order result of a model queryset by update time of its instances? i.e. the instance that has been saved most recently comes first and so on.
You will need to add a timestamp field to your model. For example in my own code I add a date_updated field for this very purpose.
Your custom models don't have this by default so you have to add it.
last_edit = models.DateTimeField(auto_now_add=True)
You will have to update this in the save method (or another method) of your model.
import datetime
self.last_edit = datetime.datetime.now()
If you have a field on your model that tracks this update time (more information on this here), then yes, you can just use that in a normal ordering specification.
If you don't track updates on your model, no, that is not possible.
Related
my projects is bidding site, i wanted to close the bid after some specific date. but i don't know
how to implement it. please any one suggest me anything
models.py
class products(models.Model):
produtname=models.CharField(max_length=255)
productdesc=models.CharField(max_length=255)
amount=models.FloatField()
image=models.ImageField(upload_to='pics')
featured=models.BooleanField(default=False)
enddate=models.DateTimeField()
after the end date I wanted to add the details to the another model automatically another model which has product id and user id
Simply don't have a soldout field; instead you can just filter for products whose end date is later than today:
from django.utils.timezone import now
# ...
products.objects.filter(enddate__gt=now())
One way to do it is to make soldout a computed #property instead of a Django field. You'll lose the ability to set it manually (however this still can be achieved with another field) and to query it with the ORM directly (but can be done as in #AKX answer).
class products(models.Model):
...
#property
def soldout(self):
return self.enddate > now()
In addition to soldout field you can add a computed property expired in your Data Model. Whenever you need to access the products available for bidding you can use not (expired or soldout).
Edit #1(add code)
Add a new field in your Model
#property
def expired(self):
return self.enddate > now()
While retrieving.
products.objects.exclude(expired=True, soldout=True)
I'm building a Django application, and in it I would like to track whenever a particular model was last accessed.
I'm opting for this in order to build a user activity history.
I know Django provides auto_now and auto_now_add, but these do not do what I want them to do. The latter tracks when a model was created, and the former tracks when it was last modified, which is different from when it was last accessed, mind you.
I've tried adding another datetime field to my model's specification:
accessed_on = models.DateTimeField()
Then I try to update the model's access manually by calling the following after each access:
model.accessed_on = datetime.utcnow()
model.save()
But it still won't work.
I've gone through the django documentation for an answer, but couldn't find one.
Help would be much appreciated.
What about creating a model with a field that contains the last save-date. Plus saving the object every time is translated from the DB representation to the python representation?
class YourModel(models.Model):
date_accessed = models.DateTimeField(auto_now=True)
#classmethod
def from_db(cls, db, field_names, values):
obj = super().from_db(db, field_names, values)
obj.save()
return obj
few years ego I worked with Odoo framework. and Odoo has very nice feature like this:
partner_id = field.Many2one(Partner)
partner_name = fields.Char(string='Partner name', related='partner_id.name')
basically whenever you would assign different partner_id from Partner table, partner_name would be assigned automatically. Now I started to work with django (absolute newbie), and I can't seem to find a similar functionality.
My question is what could be possible solution for this problem. Maybe there are already established external libraries that has this sort of functionality?
Expected result:
product = models.ForeignKey(Product)
product_color = models.CharField(string='Partner name', related='product.color')
having in mind that product object would have color field and it would be assigned to product_color whenever product field value Product object color value changes. Also what about storing it to database? Would be nice if there was an option to chose between storing it in database or getting it on the fly.
Cheers!
Creating a getter is pretty easy, because you can simply have functions in a Python object behave as a property:
class SampleModel(models.Model):
product = models.ForeignKey(Product)
#property
def product_color(self):
return self.product.color
This does retrieve the property on the fly, which will cause a call to the database.
Duplicating data, is usually a (more severe) antipattern. Synchronizing data, even in two tables in the same database, often turns out harder than one might expect. Even if you would use Django's signal framework for example, then some Django ORM calls can circumvent that (for example .update(..) [Django-doc]). But even if you somehow would cover those cases, then another program that talks to the database could update one of the two fields.
Most databases have triggers that can help. But again, the number of cases to cover are often larger than expected. For example, if the Product that we refer to is removed, then or the foreign key now points to a different Product, then we will need to update that field.
Therefore it is often better, to fetch the name of the related product when we need it. We can do so by (a) defining a property; or (b) make an annotation, for example in the manager.
Defining a property
We can define a property that will load the related product, and fetch the related name, like:
class Order(models.Model):
product = models.ForeignKey(Product, on_delete=models.PROTECT)
#property
def product_name(self):
return self.product.name
Then we can fetch the product name with some_order.product_name. This might not be very efficient if we need to fetch it often, since the relations are, by default, loaded lazily in Django, and thus can result in an N+1 problem.
Annotate the queryset
We can make an annotation that will fetch the name of the product in the same query when we fetch the Order, for example:
from django.db.models import F
class OrderManager(models.Manager):
def get_queryset(self):
return super().get_queryset().annotate(
product_name=F('product__name')
)
class Order(models.Model):
product = models.ForeignKey(Product, on_delete=models.PROTECT)
objects = OrderManager()
Then if we fetch an order. For example with Order.objects.get(pk=1), then that Order object will have an attribute product_name with the name of the product.
I'm using q.latest() for retrieving most recent object from the queryset, setting get_latest_by = 'created' in it's model's Meta class.
For example:
class A(models.Model):
created = models.DateTimeField(auto_now=True)
class Meta:
get_latest_by = 'created'
But since django's DateTimeField supports only to seconds, with no micro second support, I think my system isn't properly retrieving latest object from the queryset.
Maybe this is because there are some records in the table with the same created value, though they are not created at exactly same time (within micro seconds).
So I'm trying to use pk for get_latest_by attribute in Meta class rather than created, but due to absence of my deep understanding of how the latest() and get_latest_by works together, I'm not sure it is correct way to just put get_latest_by = 'pk'.
Is it ok to just put get_latest_by = 'pk'? and what does latest() exactly do on the backside of django?
latest is basically just a shortcut for order_by followed by get to get the last item in the queryset ordered by get_latest_by field.
pk ordering is ok, but it relies on assumptions about how your app and the db backend work (eg you import data starting at high number pk 9999... will it ever 'fill in' the missing 1, 2, 3, 100, 2000 keys if you insert new data later?)
in future Django will support microseconds https://code.djangoproject.com/ticket/19716
for now the best thing would be to combine the two, i.e. order_by('created', 'pk')
unfortunately get_latest_by and latest don't let you specify a compound ordering (and it removes the default pk ordering) so you might prefer to manually do:
.order_by('-created', '-pk').get()
(note that get gets the first item in the queryset so you need to invert the order with a - prefix to fetch the latest)
Django has added support for multiple columns in the get_latest_by field. Use list syntax, eg ['created_at', 'pk']
I have a model (lets call it Entity) that has an attribute (Attribute) that changes over time, but I want to keep a history of how that attribute changes in the database. I need to be able to filter my Entities by the current value of Attribute in its manager. But because Django (as far as I can tell) won't let me do this in one query natively, I have created a database view that produces the latest value of Attribute for every Entity. So my model structure looks something like this:
class Entity(models.Model):
def set_attribute(self, value):
self.attribute_history.create(value=value)
def is_attribute_positive(self, value):
return self.attribute.value > 0
class AttributeEntry(models.Model):
entity = models.ForeignKey(Entity, related_name='attribute_history')
value = models.IntegerField()
time = models.DateTimeField(auto_now_add=True)
class AttributeView(models.Model)
id = models.IntegerField(primary_key=True, db_column='id',
on_delete=models.DO_NOTHING)
entity = models.OneToOneField(Entity, related_name='attribute')
value = models.IntegerField()
time = models.DateTimeField()
class Meta:
managed = False
My database has the view that produces the current attribute, created with SQL like this:
CREATE VIEW myapp_attributeview AS
SELECT h1.*
FROM myapp_attributehistory h1
LEFT OUTER JOIN myapp_attributehistory h2
ON h1.entity_id = h2.entity_id
AND (h1.time < h2.time
OR h1.time = h2.time
AND h1.id < h2.id)
WHERE h2.id IS NULL;
My problem is that if I set the attribute on a model object using set_attribute() checking it with is_attribute_positive() doesn't always work, because Django may be caching that the related AttributeView object. How I can I make Django update its model, at the very least by requerying the view? Can I mark the attribute property as dirty somehow?
PS: the whole reason I'm doing this is so I can do things like Entity.objects.filter(attribute__value__exact=...).filter(...), so if someone knows an easier way to get that functionality, such an answer will be accepted, too!
I understand that the attribute value is modified by another process (maybe not even Django) accessing the same database. If this is not the case you should take a look at django-reversion.
On the other hand if that is the case, you should take a look at second answer of this. It says that commiting transaction invalidate query cache and offer this snippet.
>>> from django.db import transaction
>>> transaction.enter_transaction_management()
>>> transaction.commit() # Whenever you want to see new data
I never directly solved the problem, but I was able to sidestep it by changing is_attribute_positiive() to directly query the database table, instead of the view.
def is_attribute_positive(self, value):
return self.attribute_history.latest().value > 0
So while the view gives me the flexibility of being able to filter queries on Entity, it seems the best thing to do once the object is received is to operate directly on the table-backed model.