1

I'm getting a Django/Pythonic error and I don't have any idea How I can solve it. I tried lot of things but the error still there up to now.

My error is :

hasattr(): attribute name must be string

This error comes from my Django's Form. When I click on validate form, I get this problem.

My models.py file looks like :

class Individu(models.Model):

    NumeroIdentification = models.CharField(max_length=30, null=True, verbose_name='Numéro Identification physique', unique=True)
    Civilite = models.CharField(max_length=12,choices=CHOIX_TITRE, verbose_name='Civilité')
    NomJeuneFille = models.CharField(max_length=30, verbose_name='Nom de jeune fille', blank=True)
    Nom = models.CharField(max_length=30, verbose_name='Nom de famille')
    Prenom = models.CharField(max_length=30, verbose_name='Prénom(s)')
    Sexe = models.CharField(max_length=30, choices=CHOIX_SEXE, verbose_name='Sexe')
    Statut = models.CharField(max_length=30, choices=CHOIX_STATUT, verbose_name="Statut civil")
    DateNaissance = models.DateField(verbose_name='Date de naissance')
    VilleNaissance = models.CharField(max_length=30, verbose_name='Ville de naissance')
    PaysNaissance = CountryField(blank_label='Sélectionner un pays', verbose_name='Pays de naissance')
    Nationalite1 = models.CharField(max_length=30, verbose_name='Nationalité 1')
    Nationalite2 = models.CharField(max_length=30, verbose_name='Nationalité 2', null=True, blank=True)
    Profession = models.CharField(max_length=30, verbose_name='Profession')
    Adresse = models.CharField(max_length=30, verbose_name='Adresse')
    Ville = models.CharField(max_length=30, verbose_name='Ville')
    Zip = models.IntegerField(verbose_name='Code Postal')
    Pays = CountryField(blank_label='Sélectionner un pays', verbose_name='Pays')
    Mail = models.CharField(max_length=30, verbose_name='Email', blank=True)
    Telephone = models.CharField(max_length=20, verbose_name='Téléphone', blank=True)
    Creation = models.DateTimeField(auto_now_add=True)
    InformationsInstitution = models.CharField(max_length=30, null=False, verbose_name='Informations Institution')
    Utilisateur = models.CharField(max_length=100, null=False, verbose_name="Utilisateur", default=" ")
    Etat = models.CharField(max_length=30, choices=CHOIX_ETAT, default=" ", null=False, verbose_name="Etat")

    def save(self, *args, **kwargs):
        for field_name in ['NomJeuneFille' ,'Nom', 'VilleNaissance', 'Nationalite1', 'Nationalite2', 'Ville', 'Profession']:
            val = getattr(self, field_name, False)
            if val:
                setattr(self, field_name, val.upper())

        for field_name in ['Prenom']:
            val = getattr(self, field_name, False)
            if val:
                new_val = []
                words = val.split()
                for x in words:
                    x = x.capitalize()
                    new_val.append(x)
                val = " ".join(new_val)
                setattr(self, field_name, val.capitalize())

        super(Individu, self).save(*args, **kwargs)


    def __unicode__(self):
        return '%s %s %s %s %s %s %s %s %s %s %s %s %s %s %s %s %s %s %s' % (self.id, self.NumeroIdentification, self.Civilite, self.NomJeuneFille ,self.Nom, self.Statut, self.Prenom, 
                                                                            self.Sexe, self.DateNaissance, self.VilleNaissance, self.PaysNaissance, self.Nationalite1, self.Nationalite2, 
                                                                            self.Profession, self.Adresse, self.Ville, self.Zip, self.Pays, self.Mail, self.Telephone, self.Etat, self.InformationsInstitution)

Then, I have my form.py file :

class IndividuFormulaire(forms.ModelForm) :

    InformationsInstitution = forms.CharField(widget=forms.HiddenInput(), initial=InformationsInstitution.objects.last().Ville.encode('utf-8'))
    Utilisateur = forms.CharField(widget=forms.HiddenInput())

    class Meta :
        model = Individu
        fields = [
                'Etat', 
                'Utilisateur', 
                'Civilite', 
                'NomJeuneFille',
                'Prenom', 
                'Nom', 
                'Statut', 
                'Sexe', 
                'DateNaissance', 
                'VilleNaissance', 
                'PaysNaissance', 
                'Nationalite1', 
                'Nationalite2',
                'Profession', 
                'Adresse', 
                'Ville', 
                'Zip', 
                'Pays', 
                'Mail', 
                'Telephone', 
                'InformationsInstitution',]

And my views.py function :

@login_required
def Identity_Individu_Form(request) :

    success = False

    if request.method == 'POST':

        form = IndividuFormulaire(request.POST or None)

        if form.is_valid() :  
            post = form.save()
            messages.success(request, 'Le formulaire a été enregistré !')
            return HttpResponseRedirect(reverse('IndividuResume', kwargs={'id': post.id}))

        else:
            messages.error(request, "Le formulaire est invalide !")

    else:
        form = IndividuFormulaire()
        form.fields['Utilisateur'].initial = request.user.last_name + " " + request.user.first_name
    return render(request, 'Identity_Individu_Form.html', {"form" : form})

There is a particularity about Database. I'm using Django routers because I need to save forms result in several databases as you can see in this picture. I have to save it in DS_CORE.Identity_individu and DS_PUBLIC.Identity_individu.

enter image description here

So I have in my GlobalRouter.py file :

class GlobalRouter(object):
    """
A router to control all database operations on models in the
auth application.
"""

    def db_for_read(self, model, **hints):
        """
        Attempts to read auth models go to auth.
        """
        app_list = ('Identity')

        if model._meta.app_label in app_list:
            return 'default'
        return None

    def db_for_write(self, model, **hints):
        """
        Attempts to write auth models go to auth.
        """
        app_list = ('Identity')
        if model._meta.app_label in app_list:
            return ('DS_Public','default')
        return None

    def allow_relation(self, obj1, obj2, **hints):
        """
        Allow relations if a model in the auth app is involved.
        """
        app_list = ('Identity')
        if obj1._meta.app_label in app_list and obj2._meta.app_label in app_list:
            return True
        return None

    def allow_migrate(self, db, app_label, model=None, **hints):
        """
        Make sure the auth app only appears in the 'auth'
        database.
        """
        app_list = ('Identity')

        if app_label in app_list:
            return db == ('DS_Public','default')
        return None

I don't find where the error is located. I'm joining the full Traceback :

Environment:


Request Method: POST
Request URL: http://localhost:8000/Identity/Formulaire/Individus

Django Version: 1.10.3
Python Version: 2.7.12
Installed Applications:
['Informations',
 'django.contrib.admin',
 'django.contrib.auth',
 'django.contrib.contenttypes',
 'django.contrib.sessions',
 'django.contrib.messages',
 'django.contrib.staticfiles',
 'bootstrapform',
 'django_countries',
 'debug_toolbar',
 'chartit',
 'Configurations',
 'Accueil',
 'log',
 'Identity']
Installed Middleware:
['django.contrib.sessions.middleware.SessionMiddleware',
 'django.middleware.locale.LocaleMiddleware',
 'django.middleware.common.CommonMiddleware',
 'django.middleware.csrf.CsrfViewMiddleware',
 'django.middleware.gzip.GZipMiddleware',
 'django.contrib.auth.middleware.AuthenticationMiddleware',
 'django.contrib.auth.middleware.SessionAuthenticationMiddleware',
 'django.contrib.messages.middleware.MessageMiddleware',
 'django.middleware.clickjacking.XFrameOptionsMiddleware',
 'django.middleware.security.SecurityMiddleware',
 'debug_toolbar.middleware.DebugToolbarMiddleware']



Traceback:

File "/usr/local/lib/python2.7/site-packages/django/core/handlers/exception.py" in inner
  39.             response = get_response(request)

File "/usr/local/lib/python2.7/site-packages/django/core/handlers/base.py" in _legacy_get_response
  249.             response = self._get_response(request)

File "/usr/local/lib/python2.7/site-packages/django/core/handlers/base.py" in _get_response
  187.                 response = self.process_exception_by_middleware(e, request)

File "/usr/local/lib/python2.7/site-packages/django/core/handlers/base.py" in _get_response
  185.                 response = wrapped_callback(request, *callback_args, **callback_kwargs)

File "/usr/local/lib/python2.7/site-packages/django/contrib/auth/decorators.py" in _wrapped_view
  23.                 return view_func(request, *args, **kwargs)

File "/Users/valentinjungbluth/Desktop/Django/DatasystemsCORE/DatasystemsCORE/Identity/views.py" in Identity_Individu_Form
  140.             post = form.save()

File "/usr/local/lib/python2.7/site-packages/django/forms/models.py" in save
  453.             self.instance.save()

File "/Users/valentinjungbluth/Desktop/Django/DatasystemsCORE/DatasystemsCORE/Identity/models.py" in save
  116.         super(Individu, self).save(*args, **kwargs)

File "/usr/local/lib/python2.7/site-packages/django/db/models/base.py" in save
  796.                        force_update=force_update, update_fields=update_fields)

File "/usr/local/lib/python2.7/site-packages/django/db/models/base.py" in save_base
  821.         with transaction.atomic(using=using, savepoint=False):

File "/usr/local/lib/python2.7/site-packages/django/db/transaction.py" in __enter__
  152.         connection = get_connection(self.using)

File "/usr/local/lib/python2.7/site-packages/django/db/transaction.py" in get_connection
  21.     return connections[using]

File "/usr/local/lib/python2.7/site-packages/django/db/utils.py" in __getitem__
  205.         if hasattr(self._connections, alias):

Exception Type: TypeError at /Identity/Formulaire/Individus
Exception Value: hasattr(): attribute name must be string
4
  • 3
    Please try to reduce the code to a minimum example that shows your problem Commented Jun 21, 2017 at 15:05
  • 1
    You can't just return a tuple from a database router and expect Django to save in two separate databases. You'll need to write your views to save in each one manually, with the using argument. Although, you should really consider why you need to save in two dbs. Commented Jun 21, 2017 at 15:07
  • I would like to do that, but to understand my problem, I need to show you all elements right. Else I will have to edit my question because models or something else is missing :/ Commented Jun 21, 2017 at 15:07
  • @DanielRoseman You're right, but initially I would like to get Cross Relation Database. Pick up primary key from DB1 into DB2 as Foreign Key. But Django can't do that. So I'm trying to search another way because I have different Django project and each one needs to get a common database. Hard to explain this there .. Commented Jun 21, 2017 at 15:09

2 Answers 2

5

db_for_write and db_for_read should return a string corresponding to the connection alias. In your case, db_for_write sometimes returns a tuple

Sign up to request clarification or add additional context in comments.

3 Comments

So How I can say to GlobalRouter, especially db_for_write to save my form in DS_Core and DS_Public if I can't write a tuple ?
I don't think it is the responsability of the router, you'd need to duplicate the query and run it on another database, you may want to do that in the save() method of your model
Yes, I did this trick yesterday. I created a list as : BDD = ('default', 'DS_Public') in settings.py file and in my view, I wrote for element in settings.BDD : post.save(using=element, force_insert=True). It seems to work but it's pretty ugly to my mind ...
1

It looks like your GlobalRouter methods are returning None.

The bug I can see is that you've defined app_list as a string rather than a tuple.

This code ends up with app_list being a string:

app_list = ('Identity')

This code is what you want, which is a tuple:

app_list = ('Identity',)

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.