views:

43

answers:

3

I'm trying to create a Django model that handles the following:

  • An Item can have several Names.
  • One of the Names for an Item is its primary Name, i.e. the Name displayed given an Item.

(The model names were changed to protect the innocent.)

The models.py I've got looks like:

class Item(models.Model):
    primaryName = models.OneToOneField("Name", verbose_name="Primary Name", 
        related_name="_unused")
    def __unicode__(self):
        return self.primaryName.name

class Name(models.Model):
    item = models.ForeignKey(Item)
    name = models.CharField(max_length=32, unique=True)
    def __unicode__(self):
        return self.name

class Meta: ordering = [ 'name' ]

The admin.py looks like:

class NameInline(admin.TabularInline):
    model = Name

class ItemAdmin(admin.ModelAdmin):
    inlines = [ NameInline ]

admin.site.register(Item, ItemAdmin)

It looks like the database schema is working fine, but I'm having trouble with the admin, so I'm not sure of anything at this point. My main questions are:

  • How do I explain to the admin that primaryName needs to be one of the Names of the item being edited?
  • Is there a way to automatically set primaryName to the first Name found, if primaryName is not set, since I'm using inline admin for the names?

EDIT: Dang, I forgot this was still open. Anyway, I wound up redoing the model, replacing primaryName with just name (a CharField) in Item and renaming Name to Alias. This can't do what I wanted to (just search one table for a name), but I couldn't make the primaryName work if it didn't have null=True, since Item gets saved before any Names were created, meaning that any attempt to auto-assign a Name would see an empty QuerySet and fail.

The only way I could see it working was to have Name's save routine auto-set itself as its parent's primaryName if primaryName was NULL, which just didn't sit well with me.

A: 
  • Is there a way to automatically set primaryName to the first Name found, if primaryName is not set, since I'm using inline admin for the names?

You could do this in your model's save method, something like:

class Item(models.Model):
    ...(snip)...
    def save(self,force_insert=False,force_update=False):
        if self.primaryName is None:
            self.primaryName = self.name_set.all()[0]
            # will want to handle the case that no names are set, etc
        super(Item,self).save(force_insert,force_update)
Wogan
but doesn't django save the outer model before the inlines? otherwise it would have no Item id to plug in for the foreign key fields on the Name objects.
Brandon H
Even if it saved the inlines before the outer model, what would it be setting the inlines' `item` to since the `Item` hasn't been saved yet, and thus does not yet have a key? Does this just not happen in the real world?
Mike DeSimone
+2  A: 

i think you will want to take a look here.

http://docs.djangoproject.com/en/dev/ref/contrib/admin/#adding-custom-validation-to-the-admin

define your own form to take care of any custom validation that might be required.

Brandon H
+1  A: 
  • How do I explain to the admin that primaryName needs to be one of the Names of the item being edited?

Check out formfield_for_foreignkey() in the ModelAdmin docs.

class ItemAdmin(admin.ModelAdmin):
    def formfield_for_foreignkey(self, db_field, request, **kwargs):
        if db_field.name == "primaryName":
            # tweak the filter to your liking.
            kwargs["queryset"] = Name.objects.filter(item=...)
            return db_field.formfield(**kwargs)
        return super(ItemAdmin, self).formfield_for_foreignkey(db_field, request, **kwargs)
istruble
While not an exact answer, this one is the closest, and proved useful elsewhere.
Mike DeSimone