0

I'm writing a basic Django CMS (purely for my own use as a coding exercise). As part of this I have an abstract 'Displayable' class which both my Post and Comment classes extend:

class Displayable(models.Model):
    text = models.TextField()
    created = models.DateTimeField(editable=False)
    modified = models.DateTimeField(editable=False)

    class Meta:
        abstract = True

class Post(Displayable):
    title = models.CharField(max_length=128)
    author = models.ForeignKey(User)

The view code is as follows, with 'year' being a four-digit number from the parameterised URL (e.g. '2014').

from django.shortcuts import render
from django.http import HttpResponse
from django.template import RequestContext
from django.shortcuts import render_to_response
from blog.models import Post
def year_archive(request,year):
    context = RequestContext(request)
    context_dict = {'year':year}
    posts = Post.objects.filter(Post.created.year==year)
    # This will be a template call once I get the post filtering working!
    return HttpResponse("This is the archive view for the year"+year)

When I attempt to access such a page on the development server (e.g. /blog/2010/) I get an AttributeError:

type object 'Post' has no attribute 'created'

The problem is that, at least as far as I understand how inheritance works in Django, 'Post' does (or at least should) have an attribute 'created'. The IDE I'm using (IDEA with the Python module installed) is quite happy that such an attribute exists (it even comes up in autocompletion), so I can't work out why the Django dev server is saying it does not.

1 Answers1

0

You should read the documentation on filters. The way you want to filter is like this:

posts = Post.objects.filter(created__year=year)

The Django ORM automatically converts these keyword arguments to the right lookups in the database.

Now as to why the Post class has no attribute created: Django models are quite complicated classes. The first time they are imported, a metaclass creates the actual class you use, created from the class definition you've written. Part of this is that all the Field subclasses defined in your class definition get removed, added to the _meta.fields attribute, and that the original attribute gets set to the actual value that the field describes.

That means the fields are no longer available on the class itself. If a field belongs to a superclass, you'll get the error you saw, but if it belonged to the Post class, you'd still get AttributeError: the 'created' attribute can only be accessed from Post instances. This way Django prevents you from setting/getting field values as class attributes.

Community
  • 1
  • 1
knbk
  • 52,111
  • 9
  • 124
  • 122