views:

500

answers:

3

Let's say I have this model:

class Foo(models.Model):
    bar = models.ForeignKey(Bar)
    currency = models.ForeignKey(Currency) # currency is just an example
    is_active = models.BooleanField()

Now suppose Foo is an Inline of Bar. And I would always want to indicate a value on each currency? If I could replace those currency drop down menus with a widget that just returns the name as text with a hidden field. So for example, on an add page, instead of having the inline show this:

 - currency drop down menu    is_active checkbox 
 - currency drop down menu    is_active checkbox 
 - currency drop down menu    is_active checkbox

have it show this:

 - currency name 1    is_active checkbox 
 - currency name 2    is_active checkbox 
 - currency name 3    is_active checkbox 
 - currency name 4    is_active checkbox 
 - currency name 5    is_active checkbox

What would be the right approach to accomplish that? I assume I would have to override some form class method. Thanks.

A: 

If you always want to use the same currency:

currency = models.ForeignKey(Currency, default = lambda: Currency.objects.get(...)

If you want to change the currency on the fly subclass the form and override init where you can do your magic on self.fields['currency'].

If you would like to hide the field, use widget = forms.HiddenInput() on that field in the form class.

I think that answers your question, but not your real problem. Use [django-currencies][1] for flexible handling of currencies.

[1]: http://code.google.com/p/django-currencies/ django-currencies

knutin
Thanks for your answer, but you seem to have misunderstood my question. I have modified my question so it's clearer.
orwellian
A: 

The first problem to solve here is pre-generation of the appropriate linked Foos for each Bar. You could do that in a custom save() method on Bar, or using signals, or in a Bar factory method on a BarManager...

Once that's done, I think your admin problem can be solved like this:

class FooInline(admin.TabularInline):
    formfield_overrides = {models.ModelChoiceField: {'widget': ReadOnlyWidget}}
    model = Foo
    extra = 0

Where you'd use a custom ReadOnlyWidget like the one here.

Carl Meyer
A: 

I solved it with javascript. Insert the below into the top of tabular or stacked template. It assumes the name column is named name.

{% with inline_admin_formset.opts as i %}
    {% if i.pre_filled %}
        <script language="JavaScript" type="text/javascript">
        jQuery(function($) {    
            var pre_values = [
            {% for name in i.pre_filled %}
                {% if forloop.last %}
                [{{ name.id }}, "{{ name.name }}"] 
                {% else %}
                [{{ name.id }}, "{{ name.name }}"],    
                {% endif %}
            {% endfor %}
            ];

            $.each( pre_values,
                function( i, value ){
                    $('div.inline-group div.tabular').each(function() {
                        $("#id_{{ i.verbose_name|lower|cut:" " }}_set-" + i + "-{{ i.pre_field }}").after(value[1]);
                        $("#id_{{ i.verbose_name|lower|cut:" " }}_set-" + i + "-{{ i.pre_field }}").val(value[0]).hide();
                        $("#lookup_id_{{ i.verbose_name|lower|cut:" " }}_set-" + i + "-{{ i.pre_field }}").hide();    
                        $("strong").hide();
                    });
                }
            );
        }); 
        </script>
    {% endif %}
{% endwith %}

And this goes in your inline.py:

class MyCustomInline(admin.TabularInline):
    pre_filled = []
    pre_field = ''

    def get_fieldsets(self, request, obj=None): 
        if not obj and self.pre_filled and self.pre_field:
            count = self.pre_filled.count()
            self.extra = count
            self.max_num = count
            if self.raw_id_fields:
                self.raw_id_fields.append(self.pre_field)
            else:
                self.raw_id_fields = [self.pre_field]

        return super(MyCustomInline, self).get_fieldsets(request, obj)

class FooInline(MyCustomInline):
    model = Foo
    pre_filled = Currency.objects.all()
    pre_field = 'currency'
orwellian