views:

92

answers:

4

I'm working on a CMSy app for which I've implemented a set of models which allow for creation of custom Template instances, made up of a number of Fields and tied to a specific Customer. The end-goal is that one or more templates with a set of custom fields can be defined through the Admin interface and associated to a customer, so that customer can then create content objects in the format prescribed by the template.

I seem to have gotten this hooked up such that I can create any number of Template objects, but I'm struggling with how to create instances - actual content objects - in those templates. For example, I can define a template "Basic Page" for customer "Acme" which has the fields "Title" and "Body", but I haven't figured out how to create Basic Page instances where these fields can be filled in.

Here are my (somewhat elided) models...

class Customer(models.Model):
    ...

class Field(models.Model):
    label = models.CharField(max_length=255)
    component = models.ForeignKey(ContentType, 
            limit_choices_to={'id__in': component_choices}
            )
    fields = models.Manager()

class Template(models.Model):
    label = models.CharField(max_length=255)
    clients = models.ManyToManyField(Customer, blank=True)
    fields = models.ManyToManyField(Field, blank=True)

class ContentObject(models.Model):
    label = models.CharField(max_length=255)
    template = models.ForeignKey(Template)
    author = models.ForeignKey(User)
    customer = models.ForeignKey(Customer)
    mod_date = models.DateTimeField('Modified Date', editable=False)
    def __unicode__(self):
        return '%s (%s)' % (self.label, self.template)
    def save(self):
        self.mod_date = datetime.datetime.now()
        super(ContentObject, self).save()

Thanks in advance for any advice!

A: 

It would just be:

my_customer.templates.add(my_template)

where my_customer and my_template are instances of Customer and Template respectively.

See the documentation for related objects

Daniel Roseman
A: 

Sorry if I wasn't clear. The problem is how to create instances based on a template, not how to create the templates.

My Template class is used to define what Fields a given template contains and what Customers can use it. My ContentObject class is intended to define a content record based on a Template.

Thanks again!

sevennineteen
This answer is really just a point of clarification for the question. You should probably delete this answer and update your question instead.
istruble
+1  A: 

If you want to stick with this model architecture, you need to add another field to the ContentObject class that will serve to store the actual content. It could be something like:

ContentObject(models.Model):
    ...
    fields_content = models.ManyToManyField(Field, through=FieldContent)
    ...

and then:

class FieldContent(models.Model):
    field = ForeignKey(Field)
    content_object = ForeignKey(ContentObject)
    content = CharField

Then you should obviously make sure, probably using the pre_save signal, that for a given ContentObject instance only fields that are in the instance's template can go to the FieldContent table.

And then you can create the actual content by something like:

FieldContent.objects.create(field=your_field, content_object=your_content_object, content=content_given_by_the_customer)
pawartur
Thanks, pawartur. This seems to be on the right track; however I already have model to store the actual content, and this content can be a complex objects with multiple attributes rather than a single field. I've shown more of the Field class if that helps; the basic content model for a given field is indicated in as 'component'.It's clear that there needs to be something linking each field and its content to the content object... Taking your example, is there a way to dynamically determine the correct instance type for a given field?
sevennineteen
A: 

To expand on pawartur's answer there are a couple of ways you can handle multiple (possibly complex) data types for the fields. One way you could try is to use model inheritance, maybe something like this:

class FieldContent(models.Model):
    field = models.ForeignKey(Field)
    content_object = models.ForeignKeyKey(ContentObject)
    def get_component(self):
        """Return the specific component instance for this field."""
        return self.field.get_object_for_this_type(pk=self.pk)

Then you inherit from this base Model for each field type component, for example:

class SomeComponent(FieldContent):
    # specific fields for the component here

You can then do things like: somecontentobject.get(id=whatever).fieldcontent_set.get(whatever).get_component().specific_component_field

To create new field instances you might want to add a helper method to your Field model, something like:

    def create_content(self, content_object):
        return self.component.get_class().objects.create(
          content_object=content_object, field=self)

One thing to watch out for is that all this kind of stuff does tend to have you fighting against the framework, places where Django used to do everything for you (forms, admin etc) suddenly become a bit of work to sort out. It might be worth looking in to how some real life projects handle it, Django-cms (django-cms.org) is a probably a good start.

Just a warning: I haven't tested any of the code in this post as I'm not at a computer with anything useful installed, but it should be generally ok.

Thomas Parslow