views:

311

answers:

3

I have a unique problem the way it should be handled in django admin.

I have following models structure...

class Product(models.Model):
    name    = models.CharField(max_length = 100)
    base_price = models.DecimalField(max_digits = 5, decimal_places = 2)


    def __unicode__(self):
        return self.name


class Country(models.Model):
    name = models.CharField(max_length = 2)
    base_price = models.DecimalField(max_digits = 5, decimal_places = 2)    

    def __unicode__(self):
        return self.name


class CountryProduct(models.Model):
    country = models.ForeignKey(Country)
    product = models.ForeignKey(Product)
    overriden_price = models.DecimalField(max_digits = 5, decimal_places = 2)

    class Meta:
        unique_together = (("country", "product"),)

As shown here there is many to many relationship between products and countries.... I want to provide admin interface for overriding base price for given country and product.

One option to have ui as follows, here dash (-) represents default price and value in number represents override price for given country and product.

countries -> | US  | UK 
products     |     |
---------------------------
Product1     |  -  |  10
Product2     |  5  |   7

But I don't know how to do that....

I am open to look at alternative approaches (including changes in model structure) as well as long as it meets the requirement... Your input of any sort will definitely be useful to me...

Thanks in Advance :)

A: 

There is no way built-in to the django admin to do what you need.

You could create your own custom view, and do it that way. You can add extra views to an admin.ModelAdmin class, that will do what you need.

Matthew Schinckel
A: 

This is -- potentially -- a terrible design. Your database table should contain the correct price.

Your application must now do two things. It must get a default price from somewhere else (not in this table) and it must also get an override price (from this table) and put the two pieces of information together.

You cannot trivially make SQL work with the kind of grid you are showing.

You cannot easily get the Django admin to work with a grid like you are showing. You can try to create a grid template, but it's unique to this many-to-many relationship, so you also have to customize the Django admin views to use your template for one many-to-many table, and use the ordinary default template for all other tables.

To create the grid you must fetch all of your countries and products. You must then create the appropriate list-of-lists. You can then write your own template to display this. After you have more than 12 or so countries, the grid will be so wide as to be nearly useless. But for the first few countries you can make this work.

You'll have to create your own template and your own view function to do this.

Edit

"I am open to look at alternative approaches (including changes in model structure) as well as long as it meets the requirement"

Which requirement? The poor design where it takes two queries to find the price? Is that required?

Or the very difficult grid layout? Is that required?

It's not clear what "the requirement" is, so it's not possible to propose any alternative. It's only possible to say

  1. A SQL design that queries base and overrides separately will be slower and more complex.

  2. A SQL design that has a single value which is loaded from a "dynamic default" and can be changed (or not) by the user is much, much simpler. This can be done with the initial argument. http://docs.djangoproject.com/en/dev/ref/forms/fields/#initial

  3. SQL can't easily turn multiple rows into a grid-like structure. This requires either sophisticated SQL (well outside the ORM's capability) or Python processing in a view function.

  4. The Django admin won't do grid-like structures at all.

S.Lott
This is not a complete design, just wanted to simplify the question and that's the reason represented in this way.... And you are right it is not a good idea to present grid in this way, but that was just one of the option I had...
Software Enthusiastic
Could you elaborate on item 2: Dynamic default? This question of "overrides" is something that I've run into myself and never felt comfortable implementing. Are there any articles that explore the issue ('sql overrides' is too general to letmegooglethatforyou).
Koobz
"Dynamic Default" is simply a default value which is not statically defined in the model but loaded dynamically based on the current data, the transaction state, or something else. It's just a default value which is loaded into the form at run-time, dynamically. Read this: http://docs.djangoproject.com/en/dev/ref/forms/fields/#initial
S.Lott
A: 

I got the solution, here is my answer to my question... Let me share it with you... I changed the model in following way....

class Product(models.Model):
    name    = models.CharField(max_length = 100)
    base_price = models.DecimalField(max_digits = 5, decimal_places = 2)


    def __unicode__(self):
        return self.name


class Country(models.Model):
    name = models.CharField(max_length = 2)
    base_price = models.DecimalField(max_digits = 5, decimal_places = 2)    
    products = models.ManyToManyField(Product, through = 'CountryProduct')

    def __unicode__(self):
        return self.name


class CountryProduct(models.Model):
    country = models.ForeignKey(Country)
    product = models.ForeignKey(Product)
    overriden_price = models.DecimalField(max_digits = 5, decimal_places = 2)

    class Meta:
        unique_together = (("country", "product"),)


class CountryProductInline(admin.TabularInline):
    model = CountryProduct

class CountryAdmin(admin.ModelAdmin):
    inlines = [CountryProductInline]

class ProductAdmin(admin.ModelAdmin):
    inlines = [CountryProductInline]

Though this is not the way I expected, this gives me even better solution....

Software Enthusiastic