Home > front end >  Django field should not be shown in form but added by middleware at POST request
Django field should not be shown in form but added by middleware at POST request

Time:02-04

Let's say I've the following models:

from django.db import models

class TenantModelBase(models.Model):

    tenant = models.ForeignKey(to='accounts.TenantModel', on_delete=models.CASCADE)

    class Meta:
        abstract = True


class ModelFacade(models.Model):

    class Meta:
        abstract = True

    @entry_exit
    def save(self, force_insert=False, force_update=False, using=None, update_fields=None):
        return super().save(force_insert=force_insert, force_update=force_update, using=using, update_fields=update_fields)

    @entry_exit
    def get(self, *args, **kwargs):
        return super().objects.get(*args, **kwargs)

    @entry_exit
    def all(self):
        return super().objects.all()


class LocationModel(TenantModelBase, ModelFacade):

    city = models.CharField()
    country = models.CharField()
    building = models.CharField(blank=True)
    department = models.CharField(blank=True)
    contact_name = models.CharField(blank=True)
    email_address = models.EmailField(blank=True)
    phone_number = models.CharField(blank=True)

    class Meta(TenantModelBase.Meta):
        db_table = 'oam_locations'
        ordering = ['city']

The field "foo" should not be shown in the create form. Therefore the form is:

from django.forms import ModelForm

class LocationCreateForm(ModelForm):

    class Meta:
        model = LocationModel
        fields = ('city', 'country', 'building', 'department', 'contact_name', 'email_address', 'phone_number')

The field is NOT shown in the form. Excellent!

Now when POSTing the form, a middleware adds the 'TenantModelBase.tenant' field to the POST vars. The middleware looks like this:

    def __call__(self, request):
        if request.method == 'POST' and request.path not in ['/admin/login/']:
            user_profile = UserProfileModel.objects.get(user_id=request.user.id)
            _mutable = request.POST._mutable
            request.POST._mutable = True
            request.POST['tenant'] = str(user_profile.last_tenant_id)
            request.POST._mutable = _mutable

But when saving I get an "NOT NULL constraint failed: oam_locations.tenant_id" error. There seems to be some magic code aligning the POST vars (with "tenant" added by the middleware) to the form "fields" (w/o "tenant").

The stacktrace looks like this:

Environment:


Request Method: POST
Request URL: http://127.0.0.1:8000/oam/location/create

Django Version: 3.2.16
Python Version: 3.10.9
Installed Applications:
['django.contrib.admin',
 'django.contrib.auth',
 'django.contrib.contenttypes',
 'django.contrib.sessions',
 'django.contrib.messages',
 'django.contrib.staticfiles',
 'django.contrib.admindocs',
 'bootstrap5',
 'easyaudit',
 'main.apps.MainConfig',
 'accounts.apps.AccountsConfig',
 'oam.apps.OamConfig']
Installed Middleware:
['django.middleware.security.SecurityMiddleware',
 'django.contrib.sessions.middleware.SessionMiddleware',
 'django.middleware.locale.LocaleMiddleware',
 'django.middleware.common.CommonMiddleware',
 'django.middleware.csrf.CsrfViewMiddleware',
 'django.contrib.auth.middleware.AuthenticationMiddleware',
 'django.contrib.messages.middleware.MessageMiddleware',
 'django.middleware.clickjacking.XFrameOptionsMiddleware',
 'django.contrib.admindocs.middleware.XViewMiddleware',
 'easyaudit.middleware.easyaudit.EasyAuditMiddleware',
 'accounts.middleware.tenant_middleware.TenantMiddleware']



Traceback (most recent call last):
  File "C:\work\pro\vending\apollo\venv\lib\site-packages\django\db\backends\utils.py", line 84, in _execute
    return self.cursor.execute(sql, params)
  File "C:\work\pro\vending\apollo\venv\lib\site-packages\django\db\backends\sqlite3\base.py", line 423, in execute
    return Database.Cursor.execute(self, query, params)

The above exception (NOT NULL constraint failed: oam_locations.tenant_id) was the direct cause of the following exception:
  File "C:\work\pro\vending\apollo\venv\lib\site-packages\django\core\handlers\exception.py", line 47, in inner
    response = get_response(request)
  File "C:\work\pro\vending\apollo\venv\lib\site-packages\django\core\handlers\base.py", line 181, in _get_response
    response = wrapped_callback(request, *callback_args, **callback_kwargs)
  File "C:\work\pro\vending\apollo\venv\lib\site-packages\django\views\generic\base.py", line 70, in view
    return self.dispatch(request, *args, **kwargs)
  File "C:\work\pro\vending\apollo\venv\lib\site-packages\django\contrib\auth\mixins.py", line 71, in dispatch
    return super().dispatch(request, *args, **kwargs)
  File "C:\work\pro\vending\apollo\venv\lib\site-packages\django\views\generic\base.py", line 98, in dispatch
    return handler(request, *args, **kwargs)
  File "C:\work\pro\vending\apollo\venv\lib\site-packages\django\views\generic\edit.py", line 172, in post
    return super().post(request, *args, **kwargs)
  File "C:\work\pro\vending\apollo\venv\lib\site-packages\django\views\generic\edit.py", line 142, in post
    return self.form_valid(form)
  File "C:\work\pro\vending\apollo\venv\lib\site-packages\django\views\generic\edit.py", line 125, in form_valid
    self.object = form.save()
  File "C:\work\pro\vending\apollo\venv\lib\site-packages\django\forms\models.py", line 468, in save
    self.instance.save()
  File "C:\work\pro\vending\apollo\main\utils\decorators.py", line 22, in wrapper
    result = func(*args, **kwargs)
  File "C:\work\pro\vending\apollo\main\models\model_facade.py", line 15, in save
    return super().save(force_insert=force_insert, force_update=force_update, using=using, update_fields=update_fields)
  File "C:\work\pro\vending\apollo\venv\lib\site-packages\django\db\models\base.py", line 739, in save
    self.save_base(using=using, force_insert=force_insert,
  File "C:\work\pro\vending\apollo\venv\lib\site-packages\django\db\models\base.py", line 776, in save_base
    updated = self._save_table(
  File "C:\work\pro\vending\apollo\venv\lib\site-packages\django\db\models\base.py", line 881, in _save_table
    results = self._do_insert(cls._base_manager, using, fields, returning_fields, raw)
  File "C:\work\pro\vending\apollo\venv\lib\site-packages\django\db\models\base.py", line 919, in _do_insert
    return manager._insert(
  File "C:\work\pro\vending\apollo\venv\lib\site-packages\django\db\models\manager.py", line 85, in manager_method
    return getattr(self.get_queryset(), name)(*args, **kwargs)
  File "C:\work\pro\vending\apollo\venv\lib\site-packages\django\db\models\query.py", line 1270, in _insert
    return query.get_compiler(using=using).execute_sql(returning_fields)
  File "C:\work\pro\vending\apollo\venv\lib\site-packages\django\db\models\sql\compiler.py", line 1416, in execute_sql
    cursor.execute(sql, params)
  File "C:\work\pro\vending\apollo\venv\lib\site-packages\django\db\backends\utils.py", line 98, in execute
    return super().execute(sql, params)
  File "C:\work\pro\vending\apollo\venv\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:\work\pro\vending\apollo\venv\lib\site-packages\django\db\backends\utils.py", line 75, in _execute_with_wrappers
    return executor(sql, params, many, context)
  File "C:\work\pro\vending\apollo\venv\lib\site-packages\django\db\backends\utils.py", line 79, in _execute
    with self.db.wrap_database_errors:
  File "C:\work\pro\vending\apollo\venv\lib\site-packages\django\db\utils.py", line 90, in __exit__
    raise dj_exc_value.with_traceback(traceback) from exc_value
  File "C:\work\pro\vending\apollo\venv\lib\site-packages\django\db\backends\utils.py", line 84, in _execute
    return self.cursor.execute(sql, params)
  File "C:\work\pro\vending\apollo\venv\lib\site-packages\django\db\backends\sqlite3\base.py", line 423, in execute
    return Database.Cursor.execute(self, query, params)

Exception Type: IntegrityError at /oam/location/create
Exception Value: NOT NULL constraint failed: oam_locations.tenant_id

Any idea how to solve this?

CodePudding user response:

I think you need to add Meta class in Modelform

models.py

from django.db import models
class MyModel(models.Model):
    foo = models.CharField(max_length=120)
    bar = models.CharField(max_length=120)

form.py

from django.forms import ModelForm
class MyForm(ModelForm):
    class Meta:
        model = MyModel
        fields = ('bar',)

CodePudding user response:

You didn't specify whether the foo field can be null or not. I believe this is why it cannot create a MyModel object as it needs a foo value. Try adding null=True to your foo field.

Note: depending on what you want, you should consider looking whether blank=True is needed or not. Don't forget to migrate your changes to models.

  • Related