"Fixed default value provided" after upgrading to Django 1.8 - django

Django 1.8 now has some problem detection for models, which is nice. However, for one warning that it is giving me, I understand the problem, but I don't understand how the hint that it is giving me is any better.
This is my (bad) model field:
my_date = DateField(default=datetime.now())
and it's easy to see why that's bad. But this is the hint it's giving me:
MyMoel.my_date: (fields.W161) Fixed default value provided.
HINT: It seems you set a fixed date / time / datetime value as default for this field. This may not be what you want. If you want to have the current date as default, use `django.utils.timezone.now`
So, it says to use timezone.now, but how is that any better than datetime.now? They're both "fixed default" values... timezone.now just returns a datetime instance, which is a fixed value...
I suspect that it actually wants me to insert some sort of flag that says "use timezone.now later". But that's not what the hint says... so what is that flag?

The function datetime.now() is currently executed as soon as your code is imported, i.e. when you (re)start your server. All subsequent model instances will have the same value.
Instead, you should pass a callable function to default, that is executed each time a model instance needs a default value. The hint wants to convey that you should literally use DateField(default=django.utils.timezone.now) without the parentheses.
The message is slightly misleading, but Django doesn't know whether you used datetime.now() or django.utils.timezone.now().

The difference between timezone.now() and datetime.now() has been explained well in the above answers.
However, the reason you're getting an error is because you are running the function which will set the default time as the time while applying migrations to the database.
All you had to do was use,
my_date = DateField(default=datetime.now)
instead of
my_date = DateField(default=datetime.now())
In the above method, the timezone.now function will be called while inserting/ modifying an Object.

Related

Avoiding DateTime "auto_now" field to be changed when nothing actually has changed

What is the most efficient way to make sure my updated_at field- which has the auto_now param not to be changed when the object remains the same on PATCH request for example?
From the doc
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.
The field is only automatically updated when calling Model.save().
So by implication, your code is invoking object.save() even if nothing has been changed. You'll have to find a way to avoid this, or accept the unwanted auto-update.

Django Models : How to update value if case matches else keep the current value

I want to perform an update operation on a Django queryset conditionally such that the value of an attribute is updated only when it matches a condition otherwise keep the value it is currently having.
I know that conditional updates in django are performed using Case, When, then, default but not getting how to keep the existing value for the default case. I tried leaving default from the query but then it throws an error.
I want something like the following. Say there are 4 types of schemes: PRO, REGULAR, HOME, FREE.
Customer.objects.filter(age__lte=18)\
.update(type=Case(When(type=HOME,
then=FREE),
default=<keep current value>),
subscribed=False)
Okay so I can use a F() object for it. eg. F('field_name')
So, the query I need becomes:
Customer.objects.filter(age__lte=18)\
.update(type=Case(When(type=HOME,
then=FREE),
default=F('type')),
subscribed=False)

Django: "missing 1 required positional argument: 'lookup _name'" when it is not missing?

I am working with Django 3.1 ORM and am running (with pytest) a test involving a complex nested query. I get this failure:
self = <django.db.models.expressions.Subquery object at 0x0000027CE184D2B0>
lookup = 'lte'
def get_lookup(self, lookup):
> return self.output_field.get_lookup(lookup)
E TypeError: get_lookup() missing 1 required positional argument: 'lookup_name'
That get_lookup(lookup) to be called is defined (as far as I can see) in django.db.models.query_utils.RegisterLookupMixin as
def get_lookup(self, lookup_name):
...
The corresponding source statement of my test involves something like
value = now() - OuterRef(OuterRef('myattr2')) * timedelta(days=1)
queryset2.annotate(has_x=Exists(queryset.filter(myattr__lte=value)))
and there is more query construction code around it.
My debugger tells me that self.output_field is a DateTimeField object.
So overall:
The context is an Exists subquery.
The lookup is 'lte' (as intended).
The call provides a DateTimeField as self (from output_field) and 'lte' as lookup_name.
The method-to-be-called expects self and lookup_name.
The call should work, shouldn't it?
Where is the TypeError?
The comment by #AlexandrTatarinov is right on; that was my problem as well; myattr is a computed attribute created thusly:
annotate(myattr=Subquery(queryset3,
output_field=DateTimeField))
But for some reason, Django firmly wants a field instance for the output field, not a field class.
So output_field=DateTimeField() works, but my output_field=DateTimeField does not.
Add the parentheses and my problem is solved.
Ironically, The output_field= is not even required in this case! Removing it works as well as adding the parens.
To reflect on my work process, these were my mistakes:
I checked in the debugger that a proper self would be present -- but obviously not carefully enough, mistaking the DateTimeField class for a DateTimeField instance.
I had inserted the output_field=DateTimeField clause while I debugged a previous problem, but did not take it out again when it did not help. Bad idea.
When I wrote my question, I hesitated when I wrote "My debugger tells me that self.output_field is a DateTimeField object." and asked myself "Do I know it is a DateTimeField object and not the DateTimeField class?", but I did not go and look in the debugger again, I only recalled that I had checked it and had been satisfied.
So my take-home lessons are:
(from number 2): Don't do half-baked things.
(from numbers 1&3): Trust yourself as little as possible.

Equivalence of Django queryset filteration

I've been using the following two interchangeably in a Django project:
Comments.objects.filter(writer=self.request.user).latest('id')
and
Comments.objects.get(writer=self.request.user)
Are they equivalent in practice? The docs don't seem to explicitly address this.
They are not equivalent at all, but this greatly depends on the particular model. We do not know the particulars of your model Comments, but if we assume that field writer is not unique:
For the first statement:
Comments.objects.filter(writer=self.request.user).latest('id')
Returns in essence the object with the largest id amongst a queryset of all comments with the particular writer. If one takes a look at the django.db.connections['default'].queries, will see that the resulting query is a SELECT .. ORDER_BY .. LIMIT .. statement.
For the second statement:
Comments.objects.get(writer=self.request.user)
Returns the particular record fot that writer. In case there are more than one, you get a MultipleObjectsReturned exception. If no object is found, you get a DoesNotExist exception. In the event that this would be a unique field or there would be a single object by chance, the resulting query would be a SELECT .. WHERE statement which is faster.
Regarding the documentation, if you take a look at the Options.get_latest_by reference, there is more information regarding the purpose of the latest function. Think of it more of a convenience provided by Django. It is nonetheless very important to understand how Django evaluates queries and the resulting SQL, and there are always many ways to achieve the same query so it is a matter of logic.
I don't know why you would think these are equivalent, or why the docs should address this specifically.
In the case where you only have one matching Comment, yes this will give the same result. But the first version will do it via a more complex query, with an added sort on id.
If you have more than one Comment for that writer - as seems likely - the second version will always give a MultipleObjectsReturned error.
filter gives all lines corresponding your filter.
latest gives the most recent line (highest id value)
For example:
Comments.objects.filter(writer=self.request.user).latest('id') gets in first place all Comments written by self.request.user and then latest get the newest from them.
get is made to get a unique line, so :
Comments.objects.get(writer=self.request.user) will give the comment written by self.request.user. There should be only one. If a user can write many comments then you have to use filter or maybe all. It depends on what you want exactly.
More info here

Django - Insert Without Returning the Id of the Saved Object

Each time the save() method is called on a Django object, Django executes two queries one INSERT and one SELECT. In my case this is usefull except for some specific places where each query is expensive. Any ideas on how to sometimes state that no object needs to be returned - no SELECT needed.
Also I'm using django-mssql to connect to, this problem doesn't seem to exist on MySQL.
EDIT : A better explanation
h = Human()
h.name='John Foo'
print h.id # Returns None, No insert has been done therefore no id is available
h.save()
print h.id # Returns the ID, an insert has taken place and also a select statement to return the id
Sometimes I don't the need the retruning ID, just insert
40ins's answer was right, but probably it might have higher costs...
When django execustes a save(), it needed to be sure if the object is a new one or an existing one. So it hits the database to check if related objext exists. If yes, it executes an UPDATE, orherwise it executes an ISERT
Check documentatin from here...
You can use force_insert or force_update ,but that might be cause serious data integrity problems, like creating a duplicate entry instead of updating the existing one...
So, if you wish to use force , you must be sure whether it will be an INSERT or an UPDATE...
Try to use save() method with force_insert or force_update attributes. With this attributes django knows about record existence and don't make additional query.
The additional select is the django-mssql backend getting the identity value from the table to determine the ID that was just inserted. If this select is slow, then something is wrong with your SQL server/configuration because it is only doing SELECT CAST(IDENT_CURRENT(*table_name*) as bigint) call.