Django Datetime Issue - python

What I am trying isn't difficult, however it really isn't working. I cannot see where an error is. In my abstract user model I have an is_donator method that just does not work.
#property
def is_donator(self):
if(self.donator >= datetime.now()):
return True
else:
return False
Some reason it just does not return anything, it all looks alright to me though, any ideas?

You have two related issues. The first is you are using the wrong comparison.
if(self.donator >= datetime.now()):
This means that the donor must become a donor at some point in the future.
Change it to
if(self.donator <= datetime.now()):
This will ensure they became a donor in the past.
The other issue you have is that you are using auto_now:
Automatically set the field to now every time the object is saved.
Useful for “last-modified” timestamps. Note that the current date is
always used; it’s not just a default value that you can override.
This, then, relates to your first issue. Every time the user field is updated - if you don't explicitly set your field - it defaults to now.
Update based on comments: This is checking if your donator is not null and also ensure that it exists. If it doesn't exist, it is up to you to determine your logic, though if it doesn't exist, your user isn't a donator. You can probably just return False in your except block. This block is pretty verbose, but it shows you explicitly what is happening.
def is_donator(self):
try:
if self.donator: # This is checking that self.donator is not null
if(self.donator >= datetime.now()):
return True
else:
return False
else:
# return false? # This runs if self.donator is null
except NameError:
# do something (or just 'pass', because your self.donator value doesn't exist)

Related

Django Model Form doesn't seem to validate the BooleanField

In my model the validation is not validating for the boolean field, only one time product_field need to be checked , if two time checked raise validation error.
product_field = models.BooleanField(default=False)
def clean(self):
if (self.product_field is not None).count() < 1:
raise ValidationError(
{
"product_field": _(" Product field can be select once")
}
)
Boolean and None are not always the same. I think that is the root of your problem. Here is None vs False:
# python3
> False is None
False
I find the code and information confusing.
I assume product_filed is a typo. Generally models.BooleanField have to possibilities True and False. If blank=True and required=False are set then None can happen (unset aka NULL).
Keep the default=False and don't check for None, you should never see None with a default on a Bool.
You mention if two time checked raise validation error - Huh? This is also confusing. What are you trying to accomplish? The logic and details do not make complete sense to me.
To check the bool you can use if not self.product_field: ... raise.
What is being counted?

Should you check before setting a Django model's field?

I have a background service that imports django, and uses my django project's ORM directly.
It monitors something, in a loop, very often - every few seconds.
It goes through every user in my database, checks a condition, and based on that, sets a flag to either be True or False. I might have thousands of users in the database, so the efficiency here can add up.
while True:
time.sleep(5)
for user in User.objects.all():
if user.check():
user.flag = True
else:
user.flag = False
user.save()
I'm using MySQL as my database.
What I'm curious about is this: if a particular user has .flag set to True, am I doing a disk write every time I run user.flag = True; user.save(), even though nothing changed? Or is Django or MySQL smart enough not to do a disk write if nothing changed?
I assume a MySQL read operation is less expensive than a write operation. Would it make more sense to check the value of user.flag, and only try to set user.flag if the value actually changed? This would essentially be exchanging a database read for a database write, from what I understand (except in cases where something actually changed, in which case, first a read is performed, and then a write).
Note: This is just a basic example. I'm not actually dealing with users.
If you can move the logic of check into a .filter() clause, that would be best. That way you could do:
User.objects.filter(match_check, flag=False).update(flag=True)
User.objects.filter(~Q(match_check), flag=True).update(flag=False)
Or if you could annotate the value:
User.objects.annotate(
new_flag=some_check,
).exclude(flag=F('new_flag')).update(flag= ('new_flag'))
Otherwise if you can't then maybe do it like this:
new_flag = user.check()
if new_flag != user.flag:
user.flag = new_flag
user.save(update_fields=['flag']) # This will only update that single column.

Django - NullBooleanField won't retain False value from custom save() method

Newcomer to Django, so forgive me if I'm missing something obvious or doing something stupid here...
I have a Django model with a custom save() extension. Trimming the unrelated fields and methods, it looks like this:
class Content(models.Model):
url = models.URLField(max_length=1000)
image = models.URLField(blank=True, max_length=1000)
image_type = models.NullBooleanField(default=None)
def save(self, *args, **kwargs):
if self.url:
img, img_type = image_extractor(self.url)
print 'extractor returned: ', img_type
print 'before set: ', self.image_type
setattr(self, 'image', img)
setattr(self, 'image_type', img_type)
print 'after set: ', self.image_type
super(Content, self).save(*args, **kwargs)
print 'from query: ', Content.objects.get(url=self.url).image_type
The image_extractor function returns a url string and a boolean value representing the image type: True for images larger than a certain width, False for smaller images, or None if no suitable image was found. The problem is, when I query Content.objects and check image_type, all objects return either True or None. Hence the print statements. The images with image_type None or True work as expected, but when image_type is returned False, this is what prints:
extractor returned: False
before set: None
after set: False
from query: True
Somehow the call to super().save always reverts image_type to True if I try to set False (but not if I set None). I admit, I don't understand super() very well, but based on the documentation it seems to be necessary when extending the model function. Can anyone explain what's going on here, and how I can fix it?
Edit: I notice that I can change the value to False through the admin page and it stays False. But I still need to fix the save() method. For now, I have just replaced the boolean field with an integer field and saved values as 0 or 1, which does work. But I'd still like to know why the more appropriate field doesn't.
Since writing this question, I had moved ahead with a temporary solution of using an IntegerField to store the boolean as 0 or 1. Upon deciding to revisit the problem tonight and switching back to the NullBooleanField, suddenly everything works as intended. So it seems danodonovan was correct: the code above is correct, and unfortunately I still have no idea what was causing the error. Something else I changed while using the IntegerField must have resolved the issue. Thanks to those of you who have taken a look and offered some opinions, and I'm sorry to have wasted your time.
the way you overload save method looks good.
I think you are not loading the good object from database.
Use the primary key will probably works better.
In your case just replace that:
Content.objects.get(url=self.url).image_type
by that:
Content.objects.get(pk=self.pk).image_type
Looks at the documentation: https://docs.djangoproject.com/en/dev/ref/models/instances/#the-pk-property
Extract from the django documention:
Once the object has been saved, you must reload the object in order to
access the actual value that was applied to the updated field:
product = Products.objects.get(pk=product.pk)
print(product.number_sold)

Is there a better way to deal with DoesNotExist query sets

There is probably a better way of dealing with non existant query sets...!
The problem i have with this code is that it raises an exception if the normal case will be true! That is: if a workspace name with the same name in the db is not existent.
But instead of having an exception i would like to go for a query that does not return DoesNotExist but true or false
My unelegant code:
try:
is_workspace_name = Workspace.objects.get(workspace_name=workspace_name,user=self.user.id )
except:
return workspace_name
if is_workspace_name:
raise forms.ValidationError(u'%s already exists as a workspace name! Please choose a different one!' %workspace_name )
Thanks a lot!
You can use exists() method. Quoting docs:
Returns True if the QuerySet contains any results, and False if not.
This tries to perform the query in the simplest and fastest way
possible, but it does execute nearly the same query as a normal
QuerySet query.
Remarks: the simplest and fastest way. It is cheaper to use exists (than count) because with exists the database stops counting at first occurrence.
if Workspace.objects.filter(workspace_name=workspace_name,
user=self.user.id).exists()
raise forms.ValidationError(u'%s already exists ...!' % workspace_name)
else:
return workspace_name
Checking for the existence of a record.
If you want to test for the existence of a record in your database, you could be using Workspace.objects.filter(workspace_name = workspace_name,user = self.user.id).count().
This will return the number of records matching your conditions. This number will be 0 in case there is none, which will be readily usable with an if clause. I believe this to me the most standard and easy way to do what you need here.
## EDIT ## Actually that's false, you might want to check danihp's answer for a better solution using Queryset.exists!
A word of warning: the case of checking for existence before insertion
Be cautious when using such a construct however, especially if you plan on checking whether you have a duplicate before trying to insert a record. In such a case, the best solution is to try to create the record and see if it raises an exception.
Indeed, you could be in the following situation:
Request 1 reaches the server
Request 2 reaches the server
Check is done for request 1, no object exist.
Check is done for request 2, no object exist.
Proceed with creation in request 1.
Proceed with creation in request 2.
And... you have a duplicate - this is called a race condition, and is a common issue when dealing with parallel code.
Long story short, you should use try, expect and unique constraints when dealing with insertion.
Using get_or_create, as suggested by init3, also helps. Indeed, get_or_create is aware of this, and you'll be safe so long as unwanted duplicated would raise an IntegrityError
obj, created = Workspace.objects.get_or_create(workspace_name=workspace_name, user=self.user.id)
if created:
# everything ok
# do something
pass
else:
# not ok
# respond he should choose anything else
pass
read more at the docs

qtreeview data inconsistency

I have a QTreeView GUI based on editabletreemode.py in the PyQt examples. Inside the model, I re-implemented setData() for my need: for some out-of-bound value, I'm returning False, otherwise, it returns True
def setData(self, index, value, role=QtCore.Qt.EditRole):
if role != QtCore.Qt.EditRole:
return False
item = self.getItem(index)
result = item.setData(index.column(), value)
if result:
self.dataChanged.emit(index, index)
self.modified = True
print "setData() returning ", result
return result
Problem is, even when setData is returning False, GUI still accepts the changed value. So I now have inconsistent data between the model and view. What would make sense to me is that when setData() return False to reject the value, view should revert back to old value. Is this possible?
[SOLVED]
Actually the return value of setData() doesn't seem to matter. The QTreeView seem to call data() to re-retrieve the value afterwards anyway. The problem I was having was because setData() changed the internal data even though it returned False.
If somebody could explain to me what is the return value of setData() is used for, that'd be great.
The only issue I can see is the signature of .setData(), which is .setData(index, value, role). Neither your code snippet nor the description of your problem are verbose enough to say anything else.
Edit: Indeed, after looking at the Qt sources, I stand corrected. Unlike I've stated before this edit, the return value of .setData() is not actually used by the view.
The data is committed to the model by .setModelData() of the delegate. Normally, Qt uses a QStyledItemDelegate, whose .setModelData() method actually ignores the return value of .setData(). Thus the view does indeed not care for whether the data was successfully set. When the editor for a cell in the view is closed, the view just displays whatever is now the value of that cell (as retrieved by .data()).
However, the return value of .setData() is still important, and well-behaving models should take care to return a proper value. Models generally abstract data sources, and are in and by themselves independent from views. Thus models are also accessed directly, and in this case, the caller needs to check the return value of .setData() to know, whether the operation was successful.

Categories