MSepehr
MSepehr

Reputation: 970

dynamicly change part of form in django admin

I have a model with jsonField type like below

class Product(models.Model):
    name=models.CharField(max_length=255,null=False,blank=False)
    description=models.TextField(max_length=500,null=True,blank=True)
    category=models.ForeignKey(Category,null=False,on_delete=models.CASCADE)

    values = JSONField()

and category model which include JsonSchema needed for this json field as below:

class Category(models.Model):
    category_name=models.CharField(max_length=255,unique=True)
    type = models.ForeignKey(Type, on_delete=models.CASCADE)
    attributes_Schema_name = models.CharField(max_length=255)

    def __str__(self):
        return self.category_name

and i made admin form like below :

def Make_ProductJSONModelAdminForm(cat_id):
    class ProductJSONModelAdminForm(forms.ModelForm):
        class Meta:
            model = Product
            fields = "__all__"
            DATA_SCHEMA_name=Category.objects.values_list('attributes_Schema_name',flat=True).get(id=int(cat_id))
            with open("attSchemas/{0}".format(DATA_SCHEMA_name)) as jfile:
                DATA_SCHEMA=json.load(jfile)
            widgets = {
                'values': JSONEditorWidget(DATA_SCHEMA, collapsed=False),
            }
    return ProductJSONModelAdminForm


@admin.register(Product)
class ProductModelAdmin(admin.ModelAdmin):

    form = Make_ProductJSONModelAdminForm(cat_id=2)
    inlines = [productUnitInline, productImageInline]

the problem is : i need to pass cat_id=2 dynamicly when category is selected in admin. actually i need to get cat_id in below code dynamicly on category select in admin.

form = Make_ProductJSONModelAdminForm(cat_id=2)

i am wondering is it possible or not ?

Upvotes: 0

Views: 172

Answers (2)

MSepehr
MSepehr

Reputation: 970

@jrief, I changed my ProductModelAdmin based on your answer like below:

@admin.register(Product)
class ProductModelAdmin(admin.ModelAdmin):

    def get_form(self, request, obj=None, change=False, **kwargs):
        catid = request.GET.get('id', 1)

        DATA_SCHEMA_name = Category.objects.values_list('attributes_Schema_name', flat=True).get(id=int(catid))
        with open("attSchemas/{0}".format(DATA_SCHEMA_name)) as jfile:
            DATA_SCHEMA = json.load(jfile)
        form = super().get_form(request, obj,
                                widgets={
                                    'values': JSONEditorWidget(DATA_SCHEMA, collapsed=False),
                                }
                                , **kwargs)
        # kwargs['form'] = form
        return form

and i put below code on change_form.html to change form on catgory change selection :

{% extends "admin/change_form.html" %}

{% block extrahead %}
    {{ block.super }}
    <script src="https://ajax.googleapis.com/ajax/libs/jquery/3.2.1/jquery.min.js"></script>
    <script type="text/javascript" charset="utf-8">
        $(function(){
            // inspect html to check id of category select dropdown.
            $(document).on('change', "select#id_category", function(){
                $.get($(location).attr('href'),{id: $(this).val()});

             });
         });
    </script>
{% endblock %}

but the problem is when i change the category nothing wil change in the admin page. actually i think form do not reload .what is the problem?

Upvotes: 0

jrief
jrief

Reputation: 1695

In each Django ModelAdmin class, you can override the method to create the form using this signature:

@admin.register(Product)
class ProductModelAdmin(admin.ModelAdmin):
    ...

    get_form(self, request, obj=None, **kwargs):
        DATA_SCHEMA = ...
        widget = JSONEditorWidget(DATA_SCHEMA, collapsed=False)
        Form = modelform_factory(Product, widgets={'value': widget})
        return Form

There you can add all the business logic required to build the form, for instance an initial value for cat_id. The modelform factory is documented here.

From reading your code, you intend to configure a widget to render some form fields for a JSON model field. Alternatively you can use the django-entangled app, which does exactly that (Disclaimer: I'm the author of that library).

Upvotes: 1

Related Questions