Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

ValueError: Cannot assign must be an instance

Tags:

django

I have the following pre-existing database table which contains and id and a description. I have to load this prior to my User table in order to associate the ForeignKey correctly.

class QVDSSSecurityDimension(models.Model):

    coid = models.CharField(db_column='CM_Data_Restriction', serialize=False, max_length=10, primary_key = True)  # Field name made lowercase.
    coid_name = models.CharField(db_column='CM_Company_Name', max_length=50, blank=True, null=True)  # Field name made lowercase.

    class Meta:
        managed = False
        db_table = 'QV_DSS_Security_Dimension'

My custom user model is built on the following:

class User(AbstractBaseUser, PermissionsMixin):

    email = models.EmailField(unique=True)
    username = models.CharField(max_length=7, unique=True)
    formattedusername = models.CharField(max_length=11, unique=True, primary_key = True)
    first_name = models.CharField(max_length=40)
    last_name = models.CharField(max_length=140)
    date_joined = models.DateTimeField(default=timezone.now)
    is_active = models.BooleanField(default=True)
    is_staff = models.BooleanField(default=False)
    is_cfo = models.BooleanField(default=False)
    facility = models.CharField(max_length=140)
    officename = models.CharField(max_length=100)
    jobdescription = models.CharField(max_length=140)
    positioncode = models.CharField(max_length = 100)
    positiondescription = models.CharField(max_length=140)
    coid = models.ForeignKey(QVDSSSecurityDimension, null=True, blank = True, db_constraint=False)
    streetaddress = models.CharField(max_length=140)
    title = models.CharField(max_length=100)

    USERNAME_FIELD = 'username'

    class Meta:
        app_label = 'accounts'
        db_table = "user"

    def save(self, *args, **kwargs):
        self.formattedusername = '{domain}\{username}'.format(
            domain='HCA', username=self.username)
        super(User, self).save(*args, **kwargs);

    def get_short_name(self):
        return self.username

#    REQUIRED_FIELDS = "username"

    def __str__(self):
        return '%s - %s %s' % (self.username, self.first_name, self.last_name)

Everything works with the makemigrations and migrate, but if a User.coid doesn't exist in the database I get the following error while attempting to login:

ValueError: Cannot assign "'08732'": "User.coid" must be a "QVDSSSecurityDimension" instance.

I verified that coid does exists in the QVDSSSecurityDimension, but since there are no Users in the table with the coid it's throwing that error. How can I make my login still function properly if a user verifies with AD and their coid doesn't exist in the custom user table yet?

I've tried Null = True and Blank = True with db_constraint = True and nothing seems to work. The coid will exist after the user is stored to the database, but this error happens prior to that occurring.

Here is my profile view

def profile(request):
    owner = User.objects.get (formattedusername=request.user.formattedusername)
    reportdetail = QVReportAccess.objects.filter(ntname = owner.formattedusername, active = 1).values('report_name_sc')

    reportIds = QVReportAccess.objects.filter(ntname = owner.formattedusername).values_list('report_id', flat=True)
    reportaccess = QvReportList.objects.filter(report_id__in= reportIds).values_list('report_name_sc', flat = True).distinct()
    reportGroups = QVReportAccess.objects.filter(ntname = owner.formattedusername).values_list('report_group_id', flat=True)
    reportlist = QvReportList.objects.filter(~Q(report_id__in= reportIds)).exclude(active=0)

    allreports = 'All Reports'

    if allreports in reportaccess:
        bhreportgrouplist = None
        cereportgrouplist = None
        finreportgrouplist = None
        careportgrouplist = None
        pireportgrouplist = None
        screportgrouplist = None
        dssreportgrouplist = None
        psgreportgrouplist = None
        othreportgrouplist = None
        showbutton = None
    else:
        bhreportgrouplist = QvReportList.objects.filter(~Q(report_id__in= reportIds)).filter(report_group_id = 200)
        cereportgrouplist = QvReportList.objects.filter(~Q(report_id__in= reportIds)).filter(report_group_id = 500)
        finreportgrouplist = QvReportList.objects.filter(~Q(report_id__in= reportIds)).filter(report_group_id = 600)
        careportgrouplist = QvReportList.objects.filter(~Q(report_id__in= reportIds)).filter(report_group_id = 800)
        pireportgrouplist = QvReportList.objects.filter(~Q(report_id__in= reportIds)).filter(report_group_id = 1100)
        screportgrouplist = QvReportList.objects.filter(~Q(report_id__in= reportIds)).filter(report_group_id = 1200)
        dssreportgrouplist = QvReportList.objects.filter(~Q(report_id__in= reportIds)).filter(report_group_id = 1300)
        psgreportgrouplist = QvReportList.objects.filter(~Q(report_id__in= reportIds)).filter(report_group_id = 1400)
        othreportgrouplist = QvReportList.objects.filter(~Q(report_id__in= reportIds)).filter(report_group_id = 99999)
        showbutton = ""



    args = {'user':owner, 'applicationaccess':reportaccess, 'applicationlist':reportlist, 'bhgrouplist':bhreportgrouplist, 'cegrouplist':cereportgrouplist, 'fingrouplist':finreportgrouplist
          , 'cagrouplist':careportgrouplist, 'pigrouplist':pireportgrouplist, 'scgrouplist':screportgrouplist, 'dssgrouplist':dssreportgrouplist, 'psggrouplist':psgreportgrouplist
          , 'othgrouplist':othreportgrouplist, 'showbutton':showbutton}

    return render(request, 'accounts/profile.html', args)

I'm able to get the coid from my formattedusername without the DSSSecurityDimension because it pulls it from AD, however i need the description from DSSSecurityDimension, which is why I pull in the coid on the profile template, but from User.coid not DSSSecurityDimension.coid.

Coid in my template is rendered with the following li

<li>Coid: {{ user.coid }}</li>

The line of code is in the python libraries and not my view, which tells me its an issue with my model:

Traceback (most recent call last):
  File "C:\Users\HFA9592\AppData\Local\Programs\Python\Python36\lib\site-packages\django\core\handlers\exception.py", line 41, in inner
    response = get_response(request)
  File "C:\Users\HFA9592\AppData\Local\Programs\Python\Python36\lib\site-packages\django\core\handlers\base.py", line 187, in _get_response
    response = self.process_exception_by_middleware(e, request)
  File "C:\Users\HFA9592\AppData\Local\Programs\Python\Python36\lib\site-packages\django\core\handlers\base.py", line 185, in _get_response
    response = wrapped_callback(request, *callback_args, **callback_kwargs)
  File "C:\Users\HFA9592\AppData\Local\Programs\Python\Python36\lib\site-packages\django\contrib\auth\views.py", line 54, in inner
    return func(*args, **kwargs)
  File "C:\Users\HFA9592\AppData\Local\Programs\Python\Python36\lib\site-packages\django\contrib\auth\views.py", line 150, in login
    )(request)
  File "C:\Users\HFA9592\AppData\Local\Programs\Python\Python36\lib\site-packages\django\views\generic\base.py", line 68, in view
    return self.dispatch(request, *args, **kwargs)
  File "C:\Users\HFA9592\AppData\Local\Programs\Python\Python36\lib\site-packages\django\utils\decorators.py", line 67, in _wrapper
    return bound_func(*args, **kwargs)
  File "C:\Users\HFA9592\AppData\Local\Programs\Python\Python36\lib\site-packages\django\views\decorators\debug.py", line 76, in sensitive_post_parameters_w
rapper
    return view(request, *args, **kwargs)
  File "C:\Users\HFA9592\AppData\Local\Programs\Python\Python36\lib\site-packages\django\utils\decorators.py", line 63, in bound_func
    return func.__get__(self, type(self))(*args2, **kwargs2)
  File "C:\Users\HFA9592\AppData\Local\Programs\Python\Python36\lib\site-packages\django\utils\decorators.py", line 67, in _wrapper
    return bound_func(*args, **kwargs)
  File "C:\Users\HFA9592\AppData\Local\Programs\Python\Python36\lib\site-packages\django\utils\decorators.py", line 149, in _wrapped_view
    response = view_func(request, *args, **kwargs)
  File "C:\Users\HFA9592\AppData\Local\Programs\Python\Python36\lib\site-packages\django\utils\decorators.py", line 63, in bound_func
    return func.__get__(self, type(self))(*args2, **kwargs2)
  File "C:\Users\HFA9592\AppData\Local\Programs\Python\Python36\lib\site-packages\django\utils\decorators.py", line 67, in _wrapper
    return bound_func(*args, **kwargs)
  File "C:\Users\HFA9592\AppData\Local\Programs\Python\Python36\lib\site-packages\django\views\decorators\cache.py", line 57, in _wrapped_view_func
    response = view_func(request, *args, **kwargs)
  File "C:\Users\HFA9592\AppData\Local\Programs\Python\Python36\lib\site-packages\django\utils\decorators.py", line 63, in bound_func
    return func.__get__(self, type(self))(*args2, **kwargs2)
  File "C:\Users\HFA9592\AppData\Local\Programs\Python\Python36\lib\site-packages\django\contrib\auth\views.py", line 90, in dispatch
    return super(LoginView, self).dispatch(request, *args, **kwargs)
  File "C:\Users\HFA9592\AppData\Local\Programs\Python\Python36\lib\site-packages\django\views\generic\base.py", line 88, in dispatch
    return handler(request, *args, **kwargs)
  File "C:\Users\HFA9592\AppData\Local\Programs\Python\Python36\lib\site-packages\django\views\generic\edit.py", line 182, in post
    if form.is_valid():
  File "C:\Users\HFA9592\AppData\Local\Programs\Python\Python36\lib\site-packages\django\forms\forms.py", line 183, in is_valid
    return self.is_bound and not self.errors
  File "C:\Users\HFA9592\AppData\Local\Programs\Python\Python36\lib\site-packages\django\forms\forms.py", line 175, in errors
    self.full_clean()
  File "C:\Users\HFA9592\AppData\Local\Programs\Python\Python36\lib\site-packages\django\forms\forms.py", line 385, in full_clean
    self._clean_form()
  File "C:\Users\HFA9592\AppData\Local\Programs\Python\Python36\lib\site-packages\django\forms\forms.py", line 412, in _clean_form
    cleaned_data = self.clean()
  File "C:\Users\HFA9592\AppData\Local\Programs\Python\Python36\lib\site-packages\django\contrib\auth\forms.py", line 187, in clean
    self.user_cache = authenticate(self.request, username=username, password=password)
  File "C:\Users\HFA9592\AppData\Local\Programs\Python\Python36\lib\site-packages\django\contrib\auth\__init__.py", line 70, in authenticate
    user = _authenticate_with_backend(backend, backend_path, request, credentials)
  File "C:\Users\HFA9592\AppData\Local\Programs\Python\Python36\lib\site-packages\django\contrib\auth\__init__.py", line 115, in _authenticate_with_backend
    return backend.authenticate(*args, **credentials)
  File "C:\Users\HFA9592\AppData\Local\Programs\Python\Python36\lib\site-packages\django_python3_ldap\auth.py", line 23, in authenticate
    return ldap.authenticate(*args, **kwargs)
  File "C:\Users\HFA9592\AppData\Local\Programs\Python\Python36\lib\site-packages\django_python3_ldap\ldap.py", line 205, in authenticate
    return c.get_user(**kwargs)
  File "C:\Users\HFA9592\AppData\Local\Programs\Python\Python36\lib\site-packages\django_python3_ldap\ldap.py", line 115, in get_user
    return self._get_or_create_user(self._connection.response[0])
  File "C:\Users\HFA9592\AppData\Local\Programs\Python\Python36\lib\site-packages\django_python3_ldap\ldap.py", line 67, in _get_or_create_user
    **user_lookup
  File "C:\Users\HFA9592\AppData\Local\Programs\Python\Python36\lib\site-packages\django\db\models\manager.py", line 85, in manager_method
    return getattr(self.get_queryset(), name)(*args, **kwargs)
  File "C:\Users\HFA9592\AppData\Local\Programs\Python\Python36\lib\site-packages\django\db\models\query.py", line 482, in update_or_create
    obj, created = self._create_object_from_params(lookup, params)
  File "C:\Users\HFA9592\AppData\Local\Programs\Python\Python36\lib\site-packages\django\db\models\query.py", line 498, in _create_object_from_params
    obj = self.create(**params)
  File "C:\Users\HFA9592\AppData\Local\Programs\Python\Python36\lib\site-packages\django\db\models\query.py", line 392, in create
    obj = self.model(**kwargs)
  File "C:\Users\HFA9592\AppData\Local\Programs\Python\Python36\lib\site-packages\django\contrib\auth\base_user.py", line 68, in __init__
    super(AbstractBaseUser, self).__init__(*args, **kwargs)
  File "C:\Users\HFA9592\AppData\Local\Programs\Python\Python36\lib\site-packages\django\db\models\base.py", line 554, in __init__
    _setattr(self, field.name, rel_obj)
  File "C:\Users\HFA9592\AppData\Local\Programs\Python\Python36\lib\site-packages\django\db\models\fields\related_descriptors.py", line 216, in __set__
    self.field.remote_field.model._meta.object_name,
ValueError: Cannot assign "'08732'": "User.coid" must be a "QVDSSSecurityDimension" instance.

The login is handled in my settings.py

with the following:

AUTHENTICATION_BACKENDS = (
    'django_python3_ldap.auth.LDAPBackend',
    'django.contrib.auth.backends.ModelBackend',
)

AUTH_USER_MODEL = "accounts.User"

# The URL of the LDAP server.
LDAP_AUTH_URL = "ldap://ip of server"


# Initiate TLS on connection.
LDAP_AUTH_USE_TLS = False

# The LDAP search base for looking up users.
LDAP_AUTH_SEARCH_BASE = "DC=domainname,DC=corpad,DC=net"

LDAP_AUTH_OBJECT_CLASS = "user"

# User model fields mapped to the LDAP
# attributes that represent them.
LDAP_AUTH_USER_FIELDS = {
    "username": "sAMAccountName",
    "first_name": "givenName",
    "last_name": "sn",
    "email": "mail",
    "coid": "extensionAttribute10",
    "facility": "company",
    "officename":"physicalDeliveryOfficeName",
   "streetaddress": "streetAddress",
    "jobdescription":"corpadNet2001-CORPds-JobCodeDescription",
    "positioncode":"corpadNet2001-CORPds-PositionCode",
    "positiondescription":"corpadNet2001-CORPds-PositionCodeDescription",
    "title":"title",
}

# A tuple of django model fields used to uniquely identify a user.
LDAP_AUTH_USER_LOOKUP_FIELDS = ("username",)

# Path to a callable that takes a dict of {model_field_name: value},
# returning a dict of clean model data.
# Use this to customize how data loaded from LDAP is saved to the User model.
LDAP_AUTH_CLEAN_USER_DATA = "django_python3_ldap.utils.clean_user_data"

# Path to a callable that takes a user model and a dict of {ldap_field_name: [value]},
# and saves any additional user relationships based on the LDAP data.
# Use this to customize how data loaded from LDAP is saved to User model relations.
# For customizing non-related User model fields, use LDAP_AUTH_CLEAN_USER_DATA.
LDAP_AUTH_SYNC_USER_RELATIONS = "django_python3_ldap.utils.sync_user_relations"

# Path to a callable that takes a dict of {ldap_field_name: value},
# returning a list of [ldap_search_filter]. The search filters will then be AND'd
# together when creating the final search filter.
LDAP_AUTH_FORMAT_SEARCH_FILTERS = "django_python3_ldap.utils.format_search_filters"

# Path to a callable that takes a dict of {model_field_name: value}, and returns
# a string of the username to bind to the LDAP server.
# Use this to support different types of LDAP server.
LDAP_AUTH_FORMAT_USERNAME = "django_python3_ldap.utils.format_username_active_directory"
like image 773
student101 Avatar asked Mar 07 '23 07:03

student101


1 Answers

I think I see the problem. You expect User's coid field to contain the actual ID of the related QVDSSSecurityDimension object, but this is not how ForeignKey works by default.

The User's coid field is actually an attribute that exists only inside your Python logic. At database level, there's no coid column in the User table. This is because Django creates another field that is not explicitly declared in your model, called coid_id, to hold the related object's ID. That is the column and value that actually exists in the database.

In other words, if you list the attributes of a User object, you'll see it has two fields: coid and coid_id. coid will retrieve an instance of QVDSSSecurityDimension, while coid_id will hold the actual value you're trying to set.

Check Django's documentation regarding this. This post can also help you understand how coid and coid_id work.

This is what I think you're looking for:

class User(AbstractBaseUser, PermissionsMixin):
    ...
    co = models.ForeignKey(QVDSSSecurityDimension, null=True, blank=True)
    ...

I renamed coid to co to make it more intuitive, since it doesn't hold the actual ID. I also removed db_constraint=False, since the default db_constraint=True should work just fine.

And when you try to set the QVDSSSecurityDimension to your user, you can either do:

some_user = User.objects.first()
some_dimension = QVDSSSecurityDimension.objects.get(coid='08732')

some_user.co = some_dimension
some_user.save()

or:

some_user = User.objects.first()
some_dimension = QVDSSSecurityDimension.objects.get(coid='08732')

some_user.co_id = some_dimension.coid
some_user.save()

or:

some_user = User.objects.first()
some_dimension_id = '08732'

some_user.co_id = some_dimension_id
some_user.save()

See the difference? I hope this helps clear things up a bit. :)

EDIT

Specifically, the problem was in the settings variable LDAP_AUTH_USER_FIELDS, that was trying to map the ID inside extensionAttribute10 (data received from LDAP) to the User's coid field, which expected a QVDSSSecurityDimension instance. The solution was to change that key in the LDAP_AUTH_USER_FIELDS from coid to coid_id.

like image 160
Aylen Avatar answered Mar 09 '23 19:03

Aylen