How to Dynamically Add More to a List

I am working on an insurance project. The admin of this project is expected to be able to add a new insurance type to a list. I know that using append in a list can do this in normal python code, but the problem I am having is how to add this functionality in the Django admin backend. The following code explains further what I am trying to achieve.

utils.py #this is the section that can be called from another model

insure_choice = [

    ('General', 'General'),

    ('Home', 'Home'),

    ('Car', 'Car'),

]

models.py #one of the models that needs insure_choice above

class FAQ(models.Model):

    STATUS = (

        ('True', 'True'),

        ('False', 'False'),

    )

    **insurance_type** = models.CharField(max_length=50, 
 choices=insure_choice, default='General')

    question = models.CharField(max_length=200)

    answer = HTMLField()


    status = models.CharField(

        max_length=10, choices=STATUS, help_text='only True contents will be shown')

    create_at = models.DateTimeField(auto_now_add=True)

    update_at = models.DateTimeField(auto_now=True)

    def __str__(self):

        return self.question

    class Meta:

        verbose_name = 'FAQ'

        verbose_name_plural = 'FAQs'

Please how can I dynamically add more insure_choice?

Make insure_choice a table and the insurance_type field a ForeignKey to that table.

1 Like

I have actually tried that before, but I noticed that it affects the end-user form creation, the form is supposed to show a dropdown where the user will choose the insurance type like so:

class InsuranceQuoteForm(forms.ModelForm):

    class Meta:

        model = InsuranceQuote #another model that inherits from the utils.py

        fields = ("insure_name", "employment_status")

        widgets = {

            'insure_name': ChoiceField(choices=insure_choice),

            'protection_leave': NumberInput(),

          }

But I couldn’t add that when I created the table. Please how can I fix this?

See the form docs on Fields which handle relationships

1 Like

Firstly, I appreciate you @KenWhitesell alot for your immense guide in this community, thank you so much sir, at least I have learned another way forms can be implemented. However, when I implemented that approach like so:

utils.py

class InsuranceType(models.Model):

    insurance_type = models.CharField(max_length=50,

                                      default='General', help_text='used to track the type of insurance')

and the forms.py as set below:

from services.utils import InsuranceType

class InsuranceQuoteForm(forms.ModelForm):

    class Meta:

        model = InsuranceQuote #another model that inherits from the utils.py

        fields = ("insure_name", "employment_status")

        widgets = {

            'insure_name': ModelChoiceField(queryset=InsuranceType.objects.all()),,

            'protection_leave': NumberInput(),

          }

I keep getting the error:

django.db.utils.OperationalError: no such table: services_insurancetype

Please what am I doing wrong?

Did you do a makemigrations / migrate after creating your new model? Did you add the necessary entries into that model? Also, it looks like you have that model in the wrong file - it should be in the models.py file.

1 Like

As you guided, I moved the InsuranceType into the models.py, and like before when I ran makemigrations/migrate I got the same error. When I also ran runserver I got the same error. I deleted the sqlite database after deleting all previous migrations, I still get the same error. What can I be missing here? Commenting only the single line on forms.py will make everything to start running properly.

Really no way to tell what’s causing this from the information presented here.

However:

Did you change this in addition to moving that file?

1 Like

Yes I changed it when I moved away from utils.py, like I said I have different tables that will refer to the InsuranceType, initially they were all calling it from services.utils, but when I moved the InsuranceType into models.py I had to fix everything before the server could start running again.

So everything’s working fine now?

1 Like

No, still showing the same error sir.

You’ve dropped and recreated the database? Deleted all migrations and recreated them?

If so, and the error still occurs, please post the complete traceback.

1 Like

@KenWhitesell Thank you sir, I slept off the previous time hence my late reply, here is the complete traceback.

Traceback (most recent call last):
  File "C:\webs\forweb\lib\site-packages\django\db\backends\utils.py", line 84, in _execute
    return self.cursor.execute(sql, params)
  File "C:\webs\forweb\lib\site-packages\django\db\backends\sqlite3\base.py", line 423, in execute
    return Database.Cursor.execute(self, query, params)
sqlite3.OperationalError: no such table: services_insurancetype    

The above exception was the direct cause of the following exception:

Traceback (most recent call last):
  File "manage.py", line 22, in <module>
    main()
  File "manage.py", line 18, in main
    execute_from_command_line(sys.argv)
  File "C:\webs\forweb\lib\site-packages\django\core\management\__init__.py", line 419, in execute_from_command_line
    utility.execute()
  File "C:\webs\forweb\lib\site-packages\django\core\management\__init__.py", line 413, in execute
    self.fetch_command(subcommand).run_from_argv(self.argv)        
  File "C:\webs\forweb\lib\site-packages\django\core\management\base.py", line 354, in run_from_argv
    self.execute(*args, **cmd_options)
  File "C:\webs\forweb\lib\site-packages\django\core\management\base.py", line 393, in execute
    self.check()
  File "C:\webs\forweb\lib\site-packages\django\core\management\base.py", line 423, in check
    databases=databases,
  File "C:\webs\forweb\lib\site-packages\django\core\checks\registry.py", line 76, in run_checks
    new_errors = check(app_configs=app_configs, databases=databases)
  File "C:\webs\forweb\lib\site-packages\django\core\checks\urls.py", line 13, in check_url_config
    return check_resolver(resolver)
  File "C:\webs\forweb\lib\site-packages\django\core\checks\urls.py", line 23, in check_resolver
    return check_method()
  File "C:\webs\forweb\lib\site-packages\django\urls\resolvers.py", line 412, in check
    for pattern in self.url_patterns:
  File "C:\webs\forweb\lib\site-packages\django\utils\functional.py", line 48, in __get__
    res = instance.__dict__[self.name] = self.func(instance)
  File "C:\webs\forweb\lib\site-packages\django\urls\resolvers.py", line 598, in url_patterns
    patterns = getattr(self.urlconf_module, "urlpatterns", self.urlconf_module)
  File "C:\webs\forweb\lib\site-packages\django\utils\functional.py", line 48, in __get__
    res = instance.__dict__[self.name] = self.func(instance)       
  File "C:\webs\forweb\lib\site-packages\django\urls\resolvers.py", line 591, in urlconf_module
    return import_module(self.urlconf_name)
  File "c:\users\omool\appdata\local\programs\python\python37\lib\importlib\__init__.py", line 127, in import_module
    return _bootstrap._gcd_import(name[level:], package, level)
  File "<frozen importlib._bootstrap>", line 1006, in _gcd_import  
  File "<frozen importlib._bootstrap>", line 983, in _find_and_load
  File "<frozen importlib._bootstrap>", line 967, in _find_and_load_unlocked
  File "<frozen importlib._bootstrap>", line 677, in _load_unlocked
  File "<frozen importlib._bootstrap_external>", line 728, in exec_module
  File "<frozen importlib._bootstrap>", line 219, in _call_with_frames_removed
  File "C:\webs\insurance\insurance\urls.py", line 6, in <module>  
    from .views import home
  File "C:\webs\insurance\insurance\views.py", line 8, in <module> 
    from insure.forms import InsuranceQuoteForm
  File "C:\webs\insurance\insure\forms.py", line 9, in <module>    
    class InsuranceQuoteForm(forms.ModelForm, NumberInput):
  File "C:\webs\forweb\lib\site-packages\django\forms\models.py", line 266, in __new__
    apply_limit_choices_to=False,
  File "C:\webs\forweb\lib\site-packages\django\forms\models.py", line 183, in fields_for_model
    formfield = f.formfield(**kwargs)
  File "C:\webs\forweb\lib\site-packages\django\db\models\fields\related.py", line 994, in formfield
    'blank': self.blank,
  File "C:\webs\forweb\lib\site-packages\django\db\models\fields\related.py", line 419, in formfield
    return super().formfield(**defaults)
  File "C:\webs\forweb\lib\site-packages\django\db\models\fields\__init__.py", line 948, in formfield
    return form_class(**defaults)
  File "C:\webs\forweb\lib\site-packages\django\forms\models.py", line 1215, in __init__
    self.queryset = queryset
  File "C:\webs\forweb\lib\site-packages\django\forms\models.py", line 1241, in _set_queryset
    self.widget.choices = self.choices
  File "C:\webs\forweb\lib\site-packages\django\forms\fields.py", line 790, in _set_choices
    value = list(value)
  File "C:\webs\forweb\lib\site-packages\django\forms\models.py", line 1176, in __len__
    return self.queryset.count() + (1 if self.field.empty_label is 
not None else 0)
  File "C:\webs\forweb\lib\site-packages\django\db\models\query.py", line 412, in count
    return self.query.get_count(using=self.db)
  File "C:\webs\forweb\lib\site-packages\django\db\models\sql\query.py", line 517, in get_count
    number = obj.get_aggregation(using, ['__count'])['__count']    
  File "C:\webs\forweb\lib\site-packages\django\db\models\sql\query.py", line 502, in get_aggregation
    result = compiler.execute_sql(SINGLE)
  File "C:\webs\forweb\lib\site-packages\django\db\models\sql\compiler.py", line 1175, in execute_sql
    cursor.execute(sql, params)
  File "C:\webs\forweb\lib\site-packages\django\db\backends\utils.py", line 98, in execute
    return super().execute(sql, params)
  File "C:\webs\forweb\lib\site-packages\django\db\backends\utils.py", line 66, in execute
    return self._execute_with_wrappers(sql, params, many=False, executor=self._execute)
  File "C:\webs\forweb\lib\site-packages\django\db\backends\utils.py", line 75, in _execute_with_wrappers
    return executor(sql, params, many, context)
  File "C:\webs\forweb\lib\site-packages\django\db\backends\utils.py", line 84, in _execute
    return self.cursor.execute(sql, params)
  File "C:\webs\forweb\lib\site-packages\django\db\utils.py", line 
90, in __exit__
    raise dj_exc_value.with_traceback(traceback) from exc_value    
  File "C:\webs\forweb\lib\site-packages\django\db\backends\utils.py", line 84, in _execute
    return self.cursor.execute(sql, params)
  File "C:\webs\forweb\lib\site-packages\django\db\backends\sqlite3\base.py", line 423, in execute
    return Database.Cursor.execute(self, query, params)
django.db.utils.OperationalError: no such table: services_insurancetype

This is the last non-Django file referenced in the traceback.

That class definition doesn’t strike me as being “right”.

If NumberInput is already a descendant class from ModelForm, then InsuranceQuoteForm doesn’t need to inherit from ModelForm.

If NumberInput is not a descendant class from ModelForm, then at a minimum you have these in the wrong order. (Mixins should be specified first in the class definitions.)

What is NumberInput? And why are you trying to inherit from it in your InsuranceQuoteForm?

(And there’s never any need to apologize for delays in responding. People post here from around the world from just about every time zone. You never know when someone is going to get a chance to see and respond to a message.)

1 Like

Thank you so much @KenWhitesell I really do appreciate your guide.

Ok, NumberInput is inherited from django.forms.widgets import NumberInput so that I can use it to get digits from the end-use form (since forms.ModelFrom doesn’t seem to have the right widget (at least from my own research) to achieve the same goal as NumberInput.
However, I tested the code by commenting the section on the which requires NumberInput and removing the inheritance from it, I still got the same error.

Ok, I understand what you’re trying to do - but that’s the wrong way to go about it.

A widget is not a form. A form does not inherit from a widget class.

See the docs for Overriding the default fields.

If you need further assistance, please post the complete forms.py file and the associated model, removing all the unnecessary blank lines. (We may also end up needing to see the complete view, too. You might want to post that as well.)

And, if you’re getting a different error, the full traceback for that. (If it’s still the same error, you don’t need to repost the traceback.)

1 Like

Thank you very much for your guide sir @KenWhitesell I have reviewed the link you gave me but couldn’t really understand how to use it to solve my task. As you requested, here are the model, form and also view. Thanks in anticipation.

table for insurance type #this is used to dynamically allow admin to add insurance type

class InsuranceType(models.Model):
    insurance_type = models.CharField(max_length=50,
                                      default='General', help_text='used to track the type of insurance')

table for InsuranceQuote

class InsuranceQuote(models.Model):

    insure_name = models.ForeignKey(InsuranceType, on_delete=models.CASCADE)

    protection_leave = models.PositiveIntegerField()

    employment_status = models.CharField(

        choices=employment_choice, max_length=50)

    age_range = models.CharField(choices=age_range, max_length=50)

    name = models.CharField(max_length=100)

    email = models.EmailField(max_length=254)

    phone = PhoneNumberField(region='NG', max_length=14)

    class Meta:

        verbose_name = 'Insurance Quote'

        verbose_name_plural = 'Insurance Quotes'

    def __str__(self):

        return self.insure_name

forms.py

from django import forms

from django.forms import ChoiceField, EmailInput, ModelChoiceField, TextInput

from django.forms.widgets import NumberInput

from .models import InsuranceQuote, age_range, employment_choice

from services.models import InsuranceType

class InsuranceQuoteForm(forms.ModelForm, NumberInput):

    class Meta:

        model = InsuranceQuote

        input_type = 'range'

        fields = ("insure_name", "protection_leave", "employment_status",

                  "age_range", "name", "email", "phone")

        widgets = {

            'insure_name': ModelChoiceField(queryset=InsuranceType.objects.all()),

            'protection_leave': NumberInput(),

            'employment_status': ChoiceField(choices=employment_choice),

            'age_range': ChoiceField(choices=age_range),

            'name': TextInput(attrs={'class': 'input', 'placeholder': 'name', 'name': '{{InsuranceQuote.name}}'}),

            'email': EmailInput(attrs={'class': 'input', 'placeholder': 'email address', 'name': '{{InsuranceQuote.email}}'}),

            'phone': TextInput(attrs={'class': 'input', 'placeholder': 'Phone Number', 'name': '{{InsuranceQuote.phone}}'}),

        }

view for the form


def quote_form(request):

    form = InsuranceQuoteForm()

    insurance = Insurance.objects.all()

    if request.method == 'POST':

        form = InsuranceQuoteForm(request.POST or None)

        if form.is_valid():

            insure_name = form.cleaned_data.get("insure_name")

            protection_leave = form.cleaned_data.get("protection_leave")

            employment_status = form.cleaned_data("employment_status")

            age_range = form.cleaned_data('age_range')

            name = form.cleaned_data('name')

            email = form.cleaned_data('email')

            phone = form.cleaned_data('phone')

            form.save()

            # redirect with the success message

            messages.success(request, 'Quote sent successfully',

                             extra_tags='success')

            return redirect(to='services:insure')

        else:

            messages.error(request, 'An unexpected error has occured.',

                           extra_tags='error')

    form = InsuranceQuoteForm()

    template = 'insure/quote.html'

    context = {

        'quote': form,

        'insurance': insurance,

    }

Thank you sir.

InsuranceQuote is the class being imported. Do not import individual fields.

As stated before, do not try to use NumberInput as a mixin class in the form. It doesn’t belong there.

These lines are all unnecessary. They can all be removed.

What is this “Insurance” model? I don’t see that anywhere in your post.

1 Like

Thank you for @KenWhitesell for your heavy support and guide sir, I initially made a mistake activating runserver of another project so I thought the issue was fixed, unfortunately, it wasn’t.

What is this “Insurance” model? I don’t see that anywhere in your post.

The Insurance table is shown below: *this is only needed to show some contents written by the admin (or content manager), it has nothing to do with the form*/.

class Insurance(models.Model):

    title = models.CharField()

    slug = models.SlugField()

    icon = models.CharField()

    background_image = models.ImageField()

    picture = models.ImageField()

    content = CKEditor5Field()

InsuranceQuote is the class being imported. Do not import individual fields.
age_range and employment_choice are both tuples, and they seems required when using ChoiceField()

They are shown below:

employment_choice = (

    ('Retired As ', (

        ('Director', 'Director'),

        ('Manager', 'Manager'),

    )

    ),

    ('Currently Working As ',

        (

            ('System analyst', 'System Analyst'),

            ('Accountant', 'Accountant'),)

     ),

)

age_range = (

    ('60+', '60+'),

    ('40-59', '40-59'),

    ('20-29', '20-39'),

    ('0-19', '0-19'),

)

I have removed the NumberInput() and used the form.IntegerField() instead this is still showing the same error.

class InsuranceQuoteForm(forms.ModelForm):

    class Meta:

        model = InsuranceQuote

        fields = ("insure_name", "protection_leave", "employment_status",

                  "age_range", "name", "email", "phone")

        widgets = {

            'insure_name': ModelChoiceField(queryset=InsuranceType.objects.all()),

            'protection_leave': forms.IntegerField(),

            'employment_status': ChoiceField(choices=employment_choice),

            'age_range': ChoiceField(choices=age_range),

            'name': TextInput(attrs={'class': 'input', 'placeholder': 'name', 'name': '{{InsuranceQuote.name}}'}),

            'email': EmailInput(attrs={'class': 'input', 'placeholder': 'email address', 'name': '{{InsuranceQuote.email}}'}),

            'phone': TextInput(attrs={'class': 'input', 'placeholder': 'Phone Number', 'name': '{{InsuranceQuote.phone}}'}),

        }

But I am still having exactly the same error.

One thing I noticed is that whenever I temporarily remove the first line of the form widget:
'insure_name':ModelChoice... the error will be completely gone.

Again I need to ask you to please remove the excess blank lines from the code in your posts. It’s making the code extremely difficult to read in this forum. Code should mostly be single-spaced, not double-spaced.

Please be more specific - if you’re not getting the exact same error as before, post the traceback from the error. (It’s an indication that one problem has been solved and you’re now looking at a different issue.

If it is the exact same error, something somewhere in a module, file, class, form, function, etc, is looking for a model named InsuranceType in your services app. You’ll need to find it.

1 Like