-1

Heavily edited in response to comment by @Todor.

[I use Django 1.7.6 and Python 3.4.1.]

So in my Django project I've defined an Item model with various specific subclassing models. I've also defined a Category model. A toy version of my models looks like:

models.py

from django.db import models

class Item(models.Model):
    name = models.CharField()

class CleeseItem(Item):
    cleese = models.URLField()

class GilliamItem(Item):
    gilliam = models.IntegerField()

class JonesItem(Item):
    jones = models.EmailField()

class Category(models.Model):
    title = models.CharField()
    item_types = ????  # List of model classes

Now, the ???? above is my question. To each Category instance, I'd like to associate a list of Item subclasses. Not individual Item instances, but Item subclasses.

Example: Say I create a particular Category instance <Category: terry>. Now I want to tell Django that the GilliamItem and JonesItem subclasses belong to the "terry" Category.

How will I use this? I'd like to write a view as follows:

views.py

from django.shortcuts import render_to_response, get_object_or_404
from monty.models import Category

def category_page(request, cat_name):
    c = get_object_or_404(Category, name=cat_name)
    item_dict = {}
    for it in c.item_types:  # Recall item_types is a list of classes
        item_dict.update( {it.verbose_name_plural: it.objects.all()} )
    return render_to_response('category_page.html', {'items': item_dict})

Namely, my view (1) retrieves a Category object; (2) constructs a dictionary in which the keys are the names of the models associated with that Category and the values are QuerySets containing all instances of those models; and (3) supplies that dictionary to the template.

Example: I visit http://domain.com/category/terry/. The view retrieves the Category object with name='terry' from the database. c.item_types in line 7 produces [GilliamItem, JonesItem], so the dictionary winds up looking like { 'gilliam items': GilliamItem.objects.all(), 'jones items': JonesItem.objects.all() }.

Finally, I'd like a site administrator to be able to rearrange arbitrarily the mapping between Category objects and Item types through the admin site. (Example: One day I might decide to edit the "Terry" Category to remove JonesItem from item_types, and perhaps add PratchettItem.)

thecommexokid
  • 303
  • 2
  • 13
  • How do you plan to "add subclasses" to a category instance? From the admin? And more important how/where do you plan to store that information? And finally, how do you plan to use this? If `c = `, what do you want to be able to do with `c`? E.g. you want `c.items.all()` to return a `queryset` of items only from `GilliamItem` and `JonesItem`? Or you need/want something more? If so what is it? – Todor Mar 18 '15 at 23:15
  • @Todor Thank you for this question — in attempting to answer it I clarified the problem a lot in my own head. I updated the question significantly to address your questions, but in short: Yes, I'd like to assign subclasses to category instances via the admin. And no, I don't want one big polymorphic QuerySet but a dict containing the appropriate individual QuerySets. – thecommexokid Mar 19 '15 at 01:26

2 Answers2

1

Look at django-polymorphic. It provides foreign-key and many-to-many relationships for inherited models.

catavaran
  • 44,703
  • 8
  • 98
  • 85
0

As I suspected, I'm making headway using the ContentTypes framework. In particular, if I edit my Category model to look like

from django.contrib.contenttypes.models import ContentType

class Category(models.Model):
    title = models.CharField()
    item_types = models.ManyToManyField(ContentType, null=True, blank=True)

I get almost exactly what I want. The only remaining problem is that this evokes all the model classes in my project, whereas I am interested only in the subclasses of Item. But I'm getting close!

thecommexokid
  • 303
  • 2
  • 13
  • 1
    Use the [`formfield_for_manytomany`](https://docs.djangoproject.com/en/1.7/ref/contrib/admin/#django.contrib.admin.ModelAdmin.formfield_for_manytomany) hook in the admin to filter the queryset. I guess the query set can look like that: `ContentType.objects.filter(model__endswith='Item')` – Todor Mar 19 '15 at 07:33