I'm serving a Python app through Django. Within the app I'm storing the classic "created" field within a few tables.
This is how the field looks like within the Django form:
created = models.DateTimeField(blank=True, default=datetime.now())
Unfortunately, datetime.now() is not accurate. In fact in the database I have sets of rows with the exact same timestamp.
The datetime.now() value seems to change every 30-45 minutes.
My Django app is served on Windows Server 2005 behind IIS6.
Help would be amazing!
This is a common newbie mistake, unfortunately. You have called the datetime.now() method in the definition - this means the default will be the time at which the definition was executed, ie when your server process starts up.
You need to pass the callable instead:
created = models.DateTimeField(blank=True, default=datetime.now)
ie without the calling brackets.
(Or, just use auto_now_add=True).
because datetime.now() is being called when your module is initialised and that value is being used for the default.
You want to use the auto_now_add=True parameter
created = models.DateTimeField(auto_now_add=True)
edit: no need for 'blank' if you're setting the auto option.
You don't have auto_now or auto_now_add fields set to True. Consequently, the default value is what's filled in on the form. When the form is sent to the browser. Of course there will be duplicates.
http://docs.djangoproject.com/en/1.2/ref/models/fields/#datetimefield
Related
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.
I have two models, both of which have a date field defaulting to the current date, whatever that may be. Today someone pointed out they were getting an error from one of them, which was setting dates to 19 December instead of 23 December (today at the time of writing).
I had thought both fields were set up identically so I checked for an unintended difference between the two and found one. But I was surprised because the 'working' one was the one that looked to me like it contained an error. The fields are set up like this:
# Working field
date_stamp = models.DateField(default=datetime.date.today)
# Broken field
date_statp = models.DateField(default=datetime.date.today())
I always thought the today function needed to be called to ensure the value wasn't cached. Is the reverse in fact true? Can someone explain how these two are actually interpreted on model instance creation?
The first field:
date_stamp = models.DateField(default=datetime.date.today)
takes a callback as a default value. That means that the function will be called everytime the default value needs to be filled.
The other one:
date_statp = models.DateField(default=datetime.date.today())
executes the function datetime.date.today, which returns the value of the date at that moment. So when Django initializes the models, it will set the default value to the date at that precise moment. This default value will be used untill Django reinitializes the models again, which is usually only at startup.
The class definition is run when the module is first imported, and the datetime.data.today() call is executed then. So, it runs when Django starts basically, and doesn't change after the first import.
Without parens, you set the default to the function object, a callable. When Django creates a new instance, and a default value is a callable, Django calls it and uses the return value as the default value. So that's what you want here -- no quotes.
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
I have the below db model:
from datetime import datetime
class TermPayment(models.Model):
# I have excluded fields that are irrelevant to the question
date = models.DateTimeField(default=datetime.now(), blank=True)
I add a new instance by using the below:
tp = TermPayment.objects.create(**kwargs)
My issue: all records in database have the same value in date field, which is the date of the first payment. After the server restarts, one record has the new date and the other records have the same as the first. It looks as if some data is cached, but I can't find where.
database: mysql 5.1.25
django v1.1.1
it looks like datetime.now() is being evaluated when the model is defined, and not each time you add a record.
Django has a feature to accomplish what you are trying to do already:
date = models.DateTimeField(auto_now_add=True, blank=True)
or
date = models.DateTimeField(default=datetime.now, blank=True)
The difference between the second example and what you currently have is the lack of parentheses. By passing datetime.now without the parentheses, you are passing the actual function, which will be called each time a record is added. If you pass it datetime.now(), then you are just evaluating the function and passing it the return value.
More information is available at Django's model field reference
Instead of using datetime.now you should be really using from django.utils.timezone import now
Reference:
Documentation for django.utils.timezone.now
so go for something like this:
from django.utils.timezone import now
created_date = models.DateTimeField(default=now, editable=False)
From the documentation on the django model default field:
The default value for the field. This can be a value or a callable object. If callable it will be called every time a new object is created.
Therefore following should work:
date = models.DateTimeField(default=datetime.now,blank=True)
David had the right answer. The parenthesis () makes it so that the callable timezone.now() is called every time the model is evaluated. If you remove the () from timezone.now() (or datetime.now(), if using the naive datetime object) to make it just this:
default=timezone.now
Then it will work as you expect:
New objects will receive the current date when they are created, but the date won't be overridden every time you do manage.py makemigrations/migrate.
I just encountered this. Much thanks to David.
The datetime.now() is evaluated when the class is created, not when new record is being added to the database.
To achieve what you want define this field as:
date = models.DateTimeField(auto_now_add=True)
This way the date field will be set to current date for each new record.
datetime.now() is being evaluated once, when your class is instantiated. Try removing the parenthesis so that the function datetime.now is returned and THEN evaluated. I had the same issue with setting default values for my DateTimeFields and wrote up my solution here.
From the Python language reference, under Function definitions:
Default parameter values are evaluated when the function definition is executed. This means that the expression is evaluated once, when the function is defined, and that that same “pre-computed” value is used for each call.
Fortunately, Django has a way to do what you want, if you use the auto_now argument for the DateTimeField:
date = models.DateTimeField(auto_now=True)
See the Django docs for DateTimeField.
The answer to this one is actually wrong.
Auto filling in the value (auto_now/auto_now_add isn't the same as default). The default value will actually be what the user sees if its a brand new object. What I typically do is:
date = models.DateTimeField(default=datetime.now, editable=False,)
Make sure, if your trying to represent this in an Admin page, that you list it as 'read_only' and reference the field name
read_only = 'date'
Again, I do this since my default value isn't typically editable, and Admin pages ignore non-editables unless specified otherwise. There is certainly a difference however between setting a default value and implementing the auto_add which is key here. Test it out!
In Django 3.0 auto_now_add seems to work with auto_now
reg_date=models.DateField(auto_now=True,blank=True)
if you need only DateField try this
date = models.DateField(auto_now=False, auto_now_add=False, null=True, blank=True)
if you need Both Date and Time try this
date = models.DateTimeField(auto_now_add=True, null=True, blank=True)
I am writing a Django application that stores IP addresses with optional routing information. One of the fields for the IP model I have created is nexthop (for next-hop routes), which will usually be empty. Originally we intended to use MySQL, but now project requirements have changed to use PostgreSQL.
Here is a stripped down version of my model:
class IP(models.Model):
address = models.IPAddressField()
netmask = models.IPAddressField(default='255.255.255.255')
nexthop = models.IPAddressField(null=True, blank=True, default=None)
active = models.BooleanField('is active?', default=1)
So, with MySQL I did not have a problem leaving the nexthop field empty. However, now that I switched the development environment to Postgres, we've run into a known issue in Django 1.1.1 in which a blank IP address raises a DataError
invalid input syntax for type inet: ""
LINE 1: ...-14 13:07:29', 1, E'1.2.3.4', E'255.255.255.255', E'', true)
^
As you can see, it bombs because it is trying to insert an empty string when the column will only accept a NULL.
I have a very real need to be able to keep this field empty, because if an IP doesn't have a next-hop, then its behavior changes.
Short of hacking the Django code manually, which is my ultimate last resort, I have also thought of defaulting next-hop to 255.255.255.255 and wrapping some business logic around that (i.e. If next-hop is 255.255.255.255, treat as normal route), but that just feels like a hack.
I would like to know if there are any suggestions on a better way to do this that would not require hacking Django or writing hacky logic, or if there is a completely different approach altogether that can satisfy my requirement.
Thanks in advance!
Edit: Interim Solution
For the time-being (as an interstitial fix) I decided to go with the sentinel value for the next-hop:
In the model:
IP_NEXTHOP_SENTINEL = '255.255.255.255'
class IP(models.Model):
nexthop = models.IPAddressField(
null=True,
blank=True,
default=IP_NEXTHOP_SENTINEL,
help_text='Use %s to indicate no next-hop' % IP_NEXTHOP_SENTINEL
)
def save(self, *args, **kwargs):
## hack for Django #5622 (http://code.djangoproject.com/ticket/5622)
if self.nexthop and self.nexthop == IP_NEXTHOP_SENTINEL:
self.nexthop = None
Overview:
Creation of IP objects outside of the admin portal works as intended, which is why I kept the null=True argument on the nexthop field. The only place where 255.255.255.255 would ever be set as the next-hop would be through the admin portal, so I decided that overloading save() to always replace the sentinel with None would give me the final result I desire and it doesn't really feel too much like a hack.
Thanks for your input on this!
If you can convince the devs to accept one of the patches, I'd say just run a patched copy of Django until the patched version lands. If not, then it might be less headache to just use a sentinel value, as you suggested, even though it is a hack. You might also just use a regular CharField instead of an IPAddressField, but then you get stuck having to maintain validation logic on your own.
Have you tried just using blank=True for nexthop, rather than both blank=True and null=True? As noted in the Django docs:
Only use null=True for non-string fields such as integers, booleans and dates.
And what about using empty string as sentinel, instead of 255.255.255.255 ?
As admin back-end stores empty field as empty string (when blank=true), this solution has the advantage to be transparent for the user and doesn't force him to use a faked value...