Reputation: 511
I have 3 models "Configuration", "Process", and "ProcessConfiguration" as defined below:
class Configuration(models.Model):
name = models.CharField(max_length=MAX_CONFIGURATION_NAME_LEN,
unique=True, db_index=True)
description = models.TextField(blank=True)
validation = models.CharField(max_length=MAX_CONFIGURATION_VALIDATION_LEN,
blank=True)
entity = models.CharField(max_length=MAX_CONFIGURATION_ENTITY_LEN,
blank=False)
is_customer_visible = models.BooleanField(default=False, editable=True)
class ProcessConfiguration(models.Model):
process = models.ForeignKey(Process, on_delete=models.CASCADE, db_index=True)
configuration = models.ForeignKey(Configuration, on_delete=models.CASCADE, db_index=True)
value = models.TextField()
created = models.DateTimeField(editable=False, auto_now_add=True, db_index=True)
def __str__(self):
return self.process.name + ": " + self.configuration.name + " = " + self.value[:80]
class Meta:
unique_together = ('process', 'configuration')
class Process(models.Model):
name = models.CharField(max_length=MAX_PROCESS_NAME_LEN)
What I am trying to do is to add a new CharFeild to the Process admin form for each of the Configuration objects that have a particular entity flag set.
I thought I would be able to do this in a similar way to how I have added other fields to forms, but within a loop.
class ProcessCreateForm(forms.ModelForm):
test_above = forms.CharField()
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
extented_configurations =
Configuration.objects.filter(entity='proc',
is_customer_visible=True)
for config_item in extented_configurations:
kwargs = {
'label': "123",
'required': False
}
field_class = forms.CharField
self.fields[config_item.name] = field_class(**kwargs)
When I print out the fields at the end of the init, I can see that the new fields have been added, however when I load the page I can only see the "test_above" field.
In my admin.py module I have registered the model to an admin class that I have created in another module:
from X.models import Process
from X.model_admins import ProcessAdmin
admin.site.register(Process, ProcessAdmin)
Here is the ProcessAdmin snippet model_admin module:
class ProcessAdmin(admin.ModelAdmin):
list_display = ['name']
def get_form(self, request, obj=None, **kwargs):
from X.admin_forms import ProcessCreateForm
defaults = {}
defaults['form'] = ProcessCreateForm
defaults.update(kwargs)
return super().get_form(request, obj, **defaults)
The end goal of this is when an admin user is adding a new process, then they should be able to add new 'ProcessConfiguration' that are associated with the model that they are creating.
Is this the right way to approach this issue?
Upvotes: 1
Views: 1421
Reputation: 511
I managed to sort this out by using the admin.StackedInline
class:
class ProcessConfigurationInline(admin.StackedInline):
"""
Inline form for process configurations.
"""
model = ProcessConfiguration
config_formset = modelformset_factory(Configuration, fields=('__all__'))
extra = 1
def formfield_for_foreignkey(self, db_field, request=None, **kwargs):
"""
Limit the types of configuration items you can add.
"""
field = super(ProcessConfigurationInline, self). \
formfield_for_foreignkey(db_field, request, **kwargs)
if db_field.name == 'configuration':
field.queryset = field.queryset.filter(entity='process')
And then adding this as to the process admin class using this:
inlines = [ProcessConfigurationInline]
Upvotes: 2