4

After typing on my command line in the app's directory:

python manage.py runserver

I get this error:

Traceback (most recent call last):
  File "manage.py", line 15, in <module>
    execute_from_command_line(sys.argv)
  File "C:\Users\Paulo\Coding\Python\lib\site-packages\django\core\management\__init__.py", line 371, in execute_from_command_line
    utility.execute()
  File "C:\Users\Paulo\Coding\Python\lib\site-packages\django\core\management\__init__.py", line 347, in execute
    django.setup()
  File "C:\Users\Paulo\Coding\Python\lib\site-packages\django\__init__.py", line 24, in setup
    apps.populate(settings.INSTALLED_APPS)
  File "C:\Users\Paulo\Coding\Python\lib\site-packages\django\apps\registry.py", line 112, in populate
    app_config.import_models()
  File "C:\Users\Paulo\Coding\Python\lib\site-packages\django\apps\config.py", line 198, in import_models
    self.models_module = import_module(models_module_name)
  File "C:\Users\Paulo\Coding\Python\lib\importlib\__init__.py", line 126, in import_module
    return _bootstrap._gcd_import(name[level:], package, level)
  File "<frozen importlib._bootstrap>", line 994, in _gcd_import
  File "<frozen importlib._bootstrap>", line 971, in _find_and_load
  File "<frozen importlib._bootstrap>", line 955, in _find_and_load_unlocked
  File "<frozen importlib._bootstrap>", line 665, in _load_unlocked
  File "<frozen importlib._bootstrap_external>", line 678, in exec_module
  File "<frozen importlib._bootstrap>", line 219, in _call_with_frames_removed
  File "C:\Users\Paulo\Coding\Django projects\Project 1\freezer\models.py", line 5, in <module>
    class Item(models.Model):
  File "C:\Users\Paulo\Coding\Django projects\Project 1\freezer\models.py", line 31, in Item
    added_date = models.DateField("date added", default=datetime.date.today)
NameError: name 'datetime' is not defined

This similarly titled question did not help me. I have

from datetime import date

in my models.py.

I am running python 3.6.5 and Django 2.0.4. I put this app online a while ago, it is still working and models.py is identical. I'm confused as to what I've done wrong. Could it be linked to having to reset my windows 10 recently? It removed a python install in the process (in my program files directory) and lots of other things.
It left one of my python installs alone. From the command line I opened it up and imported datetime and used the function to return today's date.

Here is my models.py:

from django.db import models
from django.utils import timezone
from datetime import date

class Item(models.Model):

    FREEZER_DRAWERS = (
            (1, 'Kitchen: Top tray'),
            (2, 'Kitchen: Middle drawer'),
            (3, 'Kitchen: Bottom drawer'),
            )

    TYPES = (
            (1, 'Raw meat'),
            (2, 'Fruit and veg'),
            (3, 'Meal'),
            )

    author = models.ForeignKey('auth.User', on_delete=models.CASCADE)
    title = models.CharField("food", max_length=100)
    item_type = models.IntegerField(choices = TYPES, default = 1)
    added_date = models.DateField("date added", default=datetime.date.today)
    where = models.IntegerField(choices = FREEZER_DRAWERS, default = 1)
    expires_date = models.DateField(default = datetime.date.today)
    on_shopping_list = models.BooleanField()

    def __str__(self):
        return self.title

Thank you! The is the first question in ages I haven't been able to answer by looking on these forums!

Mark
  • 405
  • 5
  • 10
  • 1
    replace `from datetime import date` to `import datetime` or `datetime.date.today` to `date.today` – Rakesh Aug 23 '18 at 14:11
  • 1
    See also https://stackoverflow.com/questions/15707532/python-import-datetime-v-s-from-datetime-import-datetime – clodal Aug 23 '18 at 14:11
  • @Joel Koh I also found this example and it is interesting, but unfortunately it didn't help me to see my mistake. – Mark Aug 23 '18 at 16:14

1 Answers1

4

The problem is that you did not imported the datetime module (or at least not in a qualified way): you imported the date attribute.

Use the date class

You can replace datetime.date with just date (and this is the only element you need):

from django.db import models
from django.utils import timezone
from datetime import date

class Item(models.Model):

    FREEZER_DRAWERS = (
            (1, 'Kitchen: Top tray'),
            (2, 'Kitchen: Middle drawer'),
            (3, 'Kitchen: Bottom drawer'),
            )

    TYPES = (
            (1, 'Raw meat'),
            (2, 'Fruit and veg'),
            (3, 'Meal'),
            )

    author = models.ForeignKey('auth.User', on_delete=models.CASCADE)
    title = models.CharField("food", max_length=100)
    item_type = models.IntegerField(choices = TYPES, default = 1)
    added_date = models.DateField("date added", default=date.today)
    where = models.IntegerField(choices = FREEZER_DRAWERS, default = 1)
    expires_date = models.DateField(default = date.today)
    on_shopping_list = models.BooleanField()

    def __str__(self):
        return self.title

Perform an import of the module

Alternatively, you can import the module, and then use datetime.date:

from django.db import models
from django.utils import timezone
import datetime

class Item(models.Model):

    FREEZER_DRAWERS = (
            (1, 'Kitchen: Top tray'),
            (2, 'Kitchen: Middle drawer'),
            (3, 'Kitchen: Bottom drawer'),
            )

    TYPES = (
            (1, 'Raw meat'),
            (2, 'Fruit and veg'),
            (3, 'Meal'),
            )

    author = models.ForeignKey('auth.User', on_delete=models.CASCADE)
    title = models.CharField("food", max_length=100)
    item_type = models.IntegerField(choices = TYPES, default = 1)
    added_date = models.DateField("date added", default=datetime.date.today)
    where = models.IntegerField(choices = FREEZER_DRAWERS, default = 1)
    expires_date = models.DateField(default = datetime.date.today)
    on_shopping_list = models.BooleanField()

    def __str__(self):
        return self.title

Use auto_now_add of the DateField

Regardless how we import this, in fact Django has already support for such default: with auto_now_add=True [Django-doc]: this will add a default value that is equal to today. Furthermore it will make the field blank=True, and editable=False, to prevent it to show up in forms, etc. So it is not completely equivalent, although it is likely what you mean:

# Note: makes the fields blank=True, and editable=False as well.

from django.db import models
from django.utils import timezone

class Item(models.Model):

    FREEZER_DRAWERS = (
            (1, 'Kitchen: Top tray'),
            (2, 'Kitchen: Middle drawer'),
            (3, 'Kitchen: Bottom drawer'),
            )

    TYPES = (
            (1, 'Raw meat'),
            (2, 'Fruit and veg'),
            (3, 'Meal'),
            )

    author = models.ForeignKey('auth.User', on_delete=models.CASCADE)
    title = models.CharField("food", max_length=100)
    item_type = models.IntegerField(choices = TYPES, default = 1)
    added_date = models.DateField("date added", auto_now_add=True)
    where = models.IntegerField(choices = FREEZER_DRAWERS, default = 1)
    expires_date = models.DateField(auto_now_add=True)
    on_shopping_list = models.BooleanField()

    def __str__(self):
        return self.title
Willem Van Onsem
  • 443,496
  • 30
  • 428
  • 555
  • But maybe also `today()`, no? – Kemeia Aug 23 '18 at 14:16
  • 1
    @Kemeia: no... You do not want to *call* the method, you want to pass a *callable*, such that it is called by Django to obtain the correct value. If you run your server today, then next week, the default should not be the day when the server started, but the day next week when the user constructs an object. – Willem Van Onsem Aug 23 '18 at 14:17
  • @ Willem Van Onsem Thank you. I have used your first suggestion which works, and auto_add_now also improves this because I don't want to edit one of the fields. I was confused why my online version is working - I looked at it again line by line and it is different - I imported the module. I've no idea how I managed to do this to my offline version, but I'll be more careful in future! – Mark Aug 23 '18 at 16:12