Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

ValueError: "needs to have a value for field "id" before this many-to-many relationship can be used"

Tags:

python

django

I have created an extended user model that I use on my sign-up page. The two custom models are "Cristin" and a many-to-many field named "Rolle" (the person's role in the organization).

After I added the many-to-many field, I get the following error message: ValueError at /accounts/signup/ –"Userextended: username_that_I_registered_with" needs to have a value for field "id" before this many-to-many relationship can be used.

I have googled for three hours now, and it seems that the solution is to use commit=False on the User ID before saving the model. However, I'm new to Django and Python and have trouble pinpointing where I should write the code and my attempts has so far been unsuccessful. If you can help me solving this problem, please provide the solution through code as well.

My models.py file:

class User(auth.models.User,auth.models.PermissionsMixin):
def __str__(self):
    return "@{}".format(self.username)

class Personrolle(models.Model):
    id = models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')
    persrolle = models.CharField(max_length = 30, verbose_name="Role")
    def __str__(self):
        return self.persrolle

class Userextended(models.Model):
    id = models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')
    user = models.OneToOneField(User, on_delete=models.CASCADE)
    cristin = models.IntegerField(blank=True, null=True)
    rolle = models.ManyToManyField(Personrolle)

    def __str__(self):
        return self.user.username

...

My forms.py file:

...

from django import forms
from django.contrib.auth.models import User
from accounts.models import Userextended
from accounts.models import Personrolle
from django.contrib.auth.forms import UserCreationForm
class UserCreateForm(UserCreationForm):

    cristin = forms.IntegerField(required=False)
    rolle = forms.ModelChoiceField(queryset=Personrolle.objects.all())

    class Meta():
        fields = ('first_name','last_name','username','email','password1','password2')
        model = User
        labels = {'username': 'Email',
                  'first_name': 'First name',
                  'last_name': 'Last name',
                  'email': 'Confirm email',
                  'password1': 'Password',
                  'password2': 'Confirm password',
                  'cristin': 'Cristin-ID',
                  'rolle': 'Rolle'}

    def save(self, commit=True):
        if not commit:
            raise NotImplementedError("Can't create User and Userextended without database save")
        user = super(UserCreateForm, self).save(commit=True)
        user_profile = Userextended(user=user,cristin=self.cleaned_data['cristin'],rolle=self.cleaned_data['rolle'])
        user_profile.save()
        return user

...

More detailed description of the error

  • Request Method: POST
  • Request URL: http://127.0.0.1:8000/accounts/signup/
  • Django Version: 1.11.2
  • Exception Type: ValueError
  • Exception Value: "Userextended: username_that_I_registered_with" needs to have a value for field "id" before this many-to-many relationship can be used.

  • Exception Location: .../anaconda/envs/myEnv/lib/python3.6/site-packages/django/db/models/fields/related_descriptors.py in init, line 830

  • Python Executable: .../anaconda/envs/myEnv/bin/python

  • Python Version: 3.6.1

My traceback:

File ".../anaconda/envs/myEnv/lib/python3.6/site-packages/django/core/handlers/exception.py" in inner
  41.             response = get_response(request)

File ".../anaconda/envs/myEnv/lib/python3.6/site-packages/django/core/handlers/base.py" in _get_response
  187.                 response = self.process_exception_by_middleware(e, request)

File ".../anaconda/envs/myEnv/lib/python3.6/site-packages/django/core/handlers/base.py" in _get_response
  185.                 response = wrapped_callback(request, *callback_args, **callback_kwargs)

File ".../anaconda/envs/myEnv/lib/python3.6/site-packages/django/views/generic/base.py" in view
  68.             return self.dispatch(request, *args, **kwargs)

File ".../anaconda/envs/myEnv/lib/python3.6/site-packages/django/views/generic/base.py" in dispatch
  88.         return handler(request, *args, **kwargs)

File ".../anaconda/envs/myEnv/lib/python3.6/site-packages/django/views/generic/edit.py" in post
  217.         return super(BaseCreateView, self).post(request, *args, **kwargs)

File ".../anaconda/envs/myEnv/lib/python3.6/site-packages/django/views/generic/edit.py" in post
  183.             return self.form_valid(form)

File ".../anaconda/envs/myEnv/lib/python3.6/site-packages/django/views/generic/edit.py" in form_valid
  162.         self.object = form.save()

File "…PROJECT/accounts/forms.py" in save
  57.         user_profile = Userextended(user=user,cristin=self.cleaned_data['cristin'],rolle=self.cleaned_data['rolle'])

File ".../anaconda/envs/myEnv/lib/python3.6/site-packages/django/db/models/base.py" in __init__
  566.                             _setattr(self, prop, kwargs[prop])

File ".../anaconda/envs/myEnv/lib/python3.6/site-packages/django/db/models/fields/related_descriptors.py" in __set__
  536.         manager = self.__get__(instance)

File ".../anaconda/envs/myEnv/lib/python3.6/site-packages/django/db/models/fields/related_descriptors.py" in __get__
  513.         return self.related_manager_cls(instance)

File ".../anaconda/envs/myEnv/lib/python3.6/site-packages/django/db/models/fields/related_descriptors.py" in __init__
  830.                                  (instance, self.pk_field_names[self.source_field_name]))

Exception Type: ValueError at /accounts/signup/
Exception Value: "<Userextended: [email protected]>" needs to have a value for field "id" before this many-to-many relationship can be used.
like image 782
Christian Avatar asked Jun 28 '17 13:06

Christian


2 Answers

You just need to edit your save method in your form,

def save(self, *args, **kwargs): 
    if not commit: 
        raise NotImplementedError("Can't create User and Userextended without database save") 
    user = super().save(*args, **kwargs)
    user_profile = Userextended(user=user, cristin=self.cleaned_data['cristin']) 
    user_profile.save() 
    user_profile.rolle.add(self.cleaned_data['rolle'])
    user_profile.save()
    return user

You need to save your UserExtended model first, then add the Rolle instances to the many to many relation.

like image 143
zaidfazil Avatar answered Nov 20 '22 22:11

zaidfazil


If you're using DRF you can use the validate method:

instead of this

    def create(self, validated_data):
        validated_data['slug'] = slugify(validated_data['name'])
        return budgets.models.BudgetCategory.objects.create(**validated_data)

    def update(self, instance, validated_data):
        instance.slug = slugify(validated_data['name'])
        instance.save()
        return instance

do this

def validate(self, data):
        data['slug'] = slugify(data['name'])
        return data
like image 25
Rio Weber Avatar answered Nov 20 '22 22:11

Rio Weber