Updating DateTimeField in Django - django

I have a DateTimeField() in my models.py. What I am trying to do is to update it, along with some other values in the model.
Everything else updates fine apart from my DateTimeField(). the error i get says that AttributeError: module 'datetime' has no attribute 'now'
anyone see where I am going wrong with m update?
sModel.objects.all().update(sPasses=pass_number_for_graph, sFails=fail_number_for_graph, sNds=p_number_for_graph, sTimestamp=datetime.now())

Import _datetime as instead of datetime
import _datetime

Related

Change attribute field type in SQLite3

I am trying to change the field type of one of attributes from CharField to DecimalField by doing an empty migrations and populate the new field by filling the migrations log with the following:
from __future__ import unicode_literals
from django.db import migrations
from decimal import Decimal
def populate_new_col(apps, schema_editor): #Plug data from 'LastPrice' into 'LastPrice_v1' in the same model class 'all_ks'.
all_ks = apps.get_model('blog', 'all_ks')
for ks in all_ks.objects.all():
if float(ks.LastPrice): #Check if conversion to float type is possible...
print ks.LastPrice
ks.LastPrice_v1, created = all_ks.objects.get_or_create(LastPrice_v1=Decimal(float(ks.LastPrice)*1.0))
else: #...else insert None.
ks.LastPrice_v1, created = all_ks.objects.get_or_create(LastPrice_v1=None)
ks.save()
class Migration(migrations.Migration):
dependencies = [
('blog', '0027_auto_20190301_1600'),
]
operations = [
migrations.RunPython(populate_new_col),
]
But I kept getting an error when I tried to migrate:
TypeError: Tried to update field blog.All_ks.LastPrice_v1 with a model instance, <All_ks: All_ks object>. Use a value compatible with DecimalField.
Is there something I missed converting string to Decimal?
FYI, ‘LastPrice’ is the old attribute with CharField, and ‘LastPrice_v1’ is the new attribute with DecimalField.
all_ks.objects.get_or_create() returns an All_ks object which you assign to the DecimalField LastPrice_v1. So obviously Django complains. Why don't you assign the same ks's LastPrice?
ks.LastPrice_v1 = float(ks.LastPrice)
That said, fiddling around with manual migrations seems a lot of trouble for what you want to achieve (unless you're very familiar with migration code). If you're not, you're usually better off
creating the new field in code
migrating
populating the new field
renaming the old field
renaming the new field to the original name
removing the old field
migrating again
All steps are vanilla Django operations, with the bonus that you can revert until the very last step (nice to have when things can take unexpected turns as you've just experienced).

Django 1.11 - ModelForm: change default form widget for DateTimeField

I need some help in rendering a datetime picker in my form insead of the default text field that is displayed. I am using Django 1.11 and have followed the recent solution posted here: Django 1.11 - forms.Models: change default form widget for DateTimeField however
I receive errors when using the same code.
The first error I receive is: cannot import name 'widget'. I can pass this error by importing 'widgets' instead. Has this been renamed?
The second error I receive after renaming to widgets is NameError: name 'forms' is not defined. I can pass this error by changing the code to:
Class DateInput(widgets.DateInput):
Is this the correct treatment for this error?
The third error I receive is: NameError: name 'Date_Input' is not defined I can pass this error by changing the final piece of code (removing underscore in Date_Input) above to:
widgets = {
'missing_date': DateInput()
}
After these changes, I no longer get any errors however the date field in my form is still rendering as a text field and not as a date picker.
Can anyone shed any further light on the solution above and why it possibly isn't working for me?
Additionally I would like to modify the solution mentioned in the link above to render a datetime picker not just date picker, but I first wanted to test the functionality using the code from the previous post solution. Thanks!
I ended up resolving this by splitting the datetime into seperate fields of date and time and using the following code in forms.py:
class TimeInput(forms.TimeInput):
input_type = 'time'
class DateInput(forms.DateInput):
input_type = 'date'
and within my ModelForm Class:
widgets = {
'start_date': DateInput(),
'start_time': TimeInput(),
'end_date': DateInput(),
'end_time': TimeInput(),
}

South migrate error: name 'UUID' is not defined

I have a model with a CharField field with a default value of uuid4:
f = models.CharField(default=uuid4, max_length=36, unique=True, blank=True)
and this is causing the following error:
Cannot successfully create field 'f' for model
'm': name 'UUID' is not defined.
running the migrate commmand! Ho can I fix this issue? so far I tried:
to define a "wrapper function" in the module for uuid (ie: def getUUID())
to set the default value of "f" by overriding the Model constructor
...but the problem remains :(
ps. I know that I can instruct south for custom fields, but I'm not using custom fields in my opinion :P
I solved defining the following helper function in my model's module:
from uuid import uuid4
def generateUUID():
return str(uuid4())
then:
f = models.CharField(default=generateUUID, max_length=36, unique=True, editable=False)
south will generate a migration file (migrations.0001_initial) with a generated UUID like:
default='5c88ff72-def3-4842-8d48-a75bb3240bb5'
this is pretty unhappy... since that string is "static", instead it must be created dynamically using the helper function... anyway in the django's world al seems working as expected... I added some records into the database and a new UUID was generated for each one. I then tried my first schema migration by adding a couple of fields to my model and they has been added to the database table as expected.
You can also import UUID in your migration:
from uuid import UUID
I simply removed a uuid directory from 'node_modules' directory.
And then I reinstall uuid and it worked.
I hope it helped you guys <3
step 1 : install uuid
npm install uuid
step 2: then import it
import { v4 as uuid } from 'uuid';
step 3: Use it
id:uuid()

Django JSONField dumping/loading

I'm using JSONField in some of my Django models and would like to migrate this data from Oracle to Postgres.
So far I haven't had any luck keeping this JSON data intact when using Django's dumpdata and loaddata commands, the data is transformed into string representations of the JSON. I've yet to find a good solution to this... Ideas?
I ended up solving this problem by overriding Django's included JSON serializer, specifically the handle_field method, in a custom serializer file called custom_json_serializer.py. By doing this I can ensure that specific JSONFields stay as is, without being converted to string.
On the chance anyone else runs into this issue, these are the steps I took. I had to add this custom serializer to the settings.py file:
SERIALIZATION_MODULES = {
'custom_json': 'myapp.utils.custom_json_serializer',
}
and then call it when serializing the data from Django:
python manage.py dumpdata mymodel --format=custom_json --indent=2 --traceback > mymodel_data.json
The custom serializer looks like:
from django.core.serializers.json import Serializer as JSONSerializer
from django.utils.encoding import is_protected_type
# JSONFields that are normally incorrectly serialized as strings
json_fields = ['problem_field1', 'problem_field2']
class Serializer(JSONSerializer):
"""
A fix on JSONSerializer in order to prevent stringifying JSONField data.
"""
def handle_field(self, obj, field):
value = field._get_val_from_obj(obj)
# Protected types (i.e., primitives like None, numbers, dates,
# and Decimals) are passed through as is. All other values are
# converted to string first.
if is_protected_type(value) or field.name in json_fields:
self._current[field.name] = value
else:
self._current[field.name] = field.value_to_string(obj)
The really strange part is that before this fix some JSONFields were serializing just fine, while others were not. That is why I took the approach of specifying the fields to be handled. Now all data is serializing correctly.
I haven't used the JSONField before, but what I do is:
import json
data_structure = json.loads(myData)
Maybe that will work for what you need as well. There's likely a better way to deal with this.
EDIT: If you end up using the package json - only then is the following solution applicable.
If you are using Python 2.6 and above you can use:
import json
otherwise, you can use the simplejson that is bundled with django.utils (for Python < 2.6).
from django.utils import simplejson as json
That way you can continue to use the same package name, and take your code to Google App Engine as it supports Python 2.5.2 at the moment.

Django - Custom Model Method - How to specify datatype so Admin formats it properly?

Example:
class MyModel(models.Model):
field1=models.CharField(..)
field2=models.DateTimeField()
def today(self):
return self.field2
When I look at this in the admin site, field2 is formatted differently than the today field.
How can I tell the admin site to treat today like it's treating field2? I.e., tell Django admin that 'today' is a models.DateTimeField?
Here is what it's showing:
Field2 today
April 5, 2011, 9:10 a.m. 2011-04-11 08:47:27
To obtain DateTime object call datetime.datetime.now() instead of datetime.datetime.today()
EDIT:
Or use models.DateField() for field2 instead of models.DateTimeField() :-)
EDIT2:
Here is the solution:
def today(self):
from django.utils import formats
return formats.localize(self.field2)
That's some really really weird behaviour. At a total guess, it may have something to do with django settings; specifically the DATETIME_FORMAT (and related) settings. The framework probably does introspection on fields, and if they are of DateTime type, are rendered according to the aforementioned settings.
Introspection on methods wouldn't make sense in the majority of cases, so I could understand this behaviour if it is the case.
Try modifying the settings accordingly (provide different datetime formats), and see if the fields change and the method remains the same.
Edit:
Looking at django.contrib.databrowse.datastructures, there is a section of code that does something like:
if isinstance(self.field, models.DateTimeField):
objs = capfirst(formats.date_format(self.raw_value, 'DATETIME_FORMAT'))
I'd imagine a similar thing happening within the admin app, though I can't find an exact reference at the moment.
To achieve what you want, you'll need to format your datetime appropriately:
def today(self):
from django.conf import settings
return self.field2.strftime(settings.DATETIME_FORMAT)
Or, using #cata's comment:
def today(self):
from django.utils.formats import localize
return localize(self.field2)
If you choose to supply a "list_display" item through your own function, and you're not happy with the default output, you'll need to format it yourself. In this case, if you want to have identical formatting to what the DateTime database field ends up with:
from django.utils import formats
def today(self):
return formats.localize(self.field2)
Background:
templates/admin/change_list.html
uses the template tag
django.contrib.admin.templatetags.admin_list.result_list
which in turn will call
django.contrib.admin.templatetags.admin_list.items_for_result()
to render the individual column values for each row.
You'll see that both your values start off being a DateTime instance, either through database lookup or calling your function, see
django.contrib.admin.util.lookup_field()
but the return value "f" will only be a field if there was a database field. You provided a function, so lookup_field() will only provide the value, and "f" will be None.
So in items_for_result(), your value will run through the "if f is None" block and miss out on
result_repr = display_for_field(value, f)
In other words,
django.contrib.admin.util.display_for_field()
will only be called on the database value to format according to the field type, so this is the treatment your function value is missing out on:
elif isinstance(field, models.DateField) or isinstance(field, models.TimeField):
return formats.localize(value)
and you'll need to do that last line yourself, as shown above.
EDIT: Regarding your question
How can I tell the admin site to treat
today like it's treating field2? I.e.,
tell Django admin that 'today' is a
models.DateTimeField?
It's not a models.DateTimeField, it's a function value. If it were a models.DateTimeField, it would be describing your model. Look at all the stuff that entails: http://docs.djangoproject.com/en/dev/ref/models/fields/
In your example, you really could just use field2. Apparently you want to do things to its value, calculate it etc. - so what's today.db_column then?
That said, it would be nice if function values that are DateTime instances were run through format.localize() by default, as that's what the documentation on localization seems to be promising.
By the way, I would rather define a formatted value in the ModelAdmin than in the model itself. I usually call it something like "formatted_today" (to keep the datetime value of the original today()), it's just that if the Admin is the only place that needs the formatted value, imho that's where it should be defined.
All previous answers provide solutions, that will handle timezone info incorrectly in new Django versions.
field2 and today will generally show different time if settings.USE_TZ==True.
I found this question today and have spent some time to figure out the correct way:
from django.db import models
from django.contrib import admin
from django.utils.timezone import template_localtime
from django.utils.formats import localize
class MyModel(models.Model):
# ...
field2=models.DateTimeField()
class MyModelAdmin(admin.ModelAdmin):
# ...
def today(self, obj):
return localize(template_localtime(obj.field2))
admin.site.register(MyModel, MyModelAdmin)