How do I insert a ForeignKey field into a model?

0

I do not know what I'm doing wrong look at my model.py I'm using a User extending AbstractBaseUser since I wanted to use the email field as an identifier and not the username that comes with the default in fact delete it. Using the admin works perfect but when I want to use forms to create a student type user gives me this error:

django.db.utils.IntegrityError: NOT NULL constraint failed: account_estudianteperfil.anno_id

Model.py

from django.db import models
from django.contrib.auth.models import (
    BaseUserManager, AbstractBaseUser
)


# Create your models here.



class UserManager(BaseUserManager):
    def create_user(self, email, password=None, **extra_fields):
        """
        Creates and saves a User with the given email and password.
        """
        if not email:
            raise ValueError('El usuario debe tener un email')

        user = self.model(
            email=self.normalize_email(email), **extra_fields
        )

        user.set_password(password)
        user.save(using=self._db)
        return user

    def create_staffuser(self, email, password):
        """
        Creates and saves a staff user with the given email and password.
        """
        user = self.create_user(
            email,
            password=password,
        )
        user.staff = True
        user.save(using=self._db)
        return user

    def create_superuser(self, email, password):
        """
        Creates and saves a superuser with the given email and password.
        """
        user = self.create_user(
            email,
            password=password,
        )
        user.staff = True
        user.admin = True
        user.save(using=self._db)
        return user


class User(AbstractBaseUser):
    email = models.EmailField(
        verbose_name='email address',
        max_length=255,
        unique=True,
    )
    active = models.BooleanField(default=True)
    staff = models.BooleanField(default=False)  # a admin user; non super-user
    admin = models.BooleanField(default=False)  # a superuser
    is_profesor = models.BooleanField(verbose_name='Profesor', default=False)
    is_estudiante = models.BooleanField(verbose_name='Estudiante', default=False)
    first_name = models.CharField(verbose_name='first name', max_length=30, blank=True)
    last_name = models.CharField(verbose_name='last name', max_length=30, blank=True)
    date_joined = models.DateTimeField(verbose_name='fecha de union', auto_now_add=True)

    # notice the absence of a "Password field", that's built in.

    USERNAME_FIELD = 'email'
    REQUIRED_FIELDS = []  # Email & Password are required by default.

    objects = UserManager()

    class Meta:
        db_table = 'auth_user'

    def get_full_name(self):
        # The user is identified by their email address
        return self.email

    def get_short_name(self):
        # The user is identified by their email address
        return self.email

    def __str__(self):  # __unicode__ on Python 2
        return self.email

    def has_perm(self, perm, obj=None):
        "Does the user have a specific permission?"
        # Simplest possible answer: Yes, always
        return True

    def has_module_perms(self, app_label):
        "Does the user have permissions to view the app 'app_label'?"
        # Simplest possible answer: Yes, always
        return True

    @property
    def is_staff(self):
        "Is the user a member of staff?"
        return self.staff

    @property
    def is_admin(self):
        "Is the user a admin member?"
        return self.admin

    @property
    def is_active(self):
        "Is the user active?"
        return self.active


class Carrera(models.Model):
    carrera = models.CharField(max_length=50, verbose_name='Carrera')


class Anno(models.Model):
    anno = models.CharField(max_length=50, verbose_name='Año')


class EstudiantePerfil(models.Model):
    user = models.OneToOneField(User, on_delete=models.CASCADE, primary_key=True)
    carrera = models.ForeignKey(Carrera, on_delete=models.CASCADE, related_name='estudiantes')
    anno = models.ForeignKey(Anno, on_delete=models.CASCADE, related_name='estudiantes')

Views.py

from django.contrib.auth import login
from django.shortcuts import redirect
from django.views.generic import CreateView

from ..forms import StudentSignUpForm
from ..models import User

class StudentSignUpView(CreateView):
    model = User
    form_class = StudentSignUpForm
    template_name = 'registro/signup_form.html'

    def get_context_data(self, **kwargs):
        kwargs['user_type'] = 'Estudiante'
        return super().get_context_data(**kwargs)

    def form_valid(self, form):
        user = form.save()
        login(self.request, user)
        return redirect('students:quiz_list')

Forms.py

from django import forms
from django.contrib.auth.forms import ReadOnlyPasswordHashField, UserCreationForm
from django.db import transaction

from .models import User, EstudiantePerfil, Carrera, Anno


class RegisterForm(forms.ModelForm):
    password = forms.CharField(widget=forms.PasswordInput)
    password2 = forms.CharField(label='Confirm password', widget=forms.PasswordInput)

    class Meta:
        model = User
        fields = ('email',)

    def clean_email(self):
        email = self.cleaned_data.get('email')
        qs = User.objects.filter(email=email)
        if qs.exists():
            raise forms.ValidationError("email is taken")
        return email

    def clean_password2(self):
        # Check that the two password entries match
        password1 = self.cleaned_data.get("password1")
        password2 = self.cleaned_data.get("password2")
        if password1 and password2 and password1 != password2:
            raise forms.ValidationError("Passwords don't match")
        return password2


class UserAdminCreationForm(forms.ModelForm):
    """A form for creating new users. Includes all the required
    fields, plus a repeated password."""
    password1 = forms.CharField(label='Password', widget=forms.PasswordInput)
    password2 = forms.CharField(label='Password confirmation', widget=forms.PasswordInput)

    class Meta:
        model = User
        fields = ('email', 'active', 'staff', 'is_estudiante', 'is_profesor')

    def clean_password2(self):
        # Check that the two password entries match
        password1 = self.cleaned_data.get("password1")
        password2 = self.cleaned_data.get("password2")
        if password1 and password2 and password1 != password2:
            raise forms.ValidationError("Passwords don't match")
        return password2

    def save(self, commit=True):
        # Save the provided password in hashed format
        user = super(UserAdminCreationForm, self).save(commit=False)
        user.set_password(self.cleaned_data["password1"])
        if commit:
            user.save()
        return user


class UserAdminChangeForm(forms.ModelForm):
    """A form for updating users. Includes all the fields on
    the user, but replaces the password field with admin's
    password hash display field.
    """
    password = ReadOnlyPasswordHashField()

    class Meta:
        model = User
        fields = ('email', 'password', 'active', 'admin')

    def clean_password(self):
        # Regardless of what the user provides, return the initial value.
        # This is done here, rather than on the field, because the
        # field does not have access to the initial value
        return self.initial["password"]





class StudentSignUpForm(RegisterForm):
    carrera=forms.ModelChoiceField(queryset=Carrera.objects.all())
    anno=forms.ModelChoiceField(queryset=Anno.objects.all())

    class Meta:
        model = User
        fields=('email',)

    @transaction.atomic
    def save(self):
        user = super().save(commit=False)
        user.is_estudiante = True
        user.save()
        estudiante = EstudiantePerfil.objects.create(user=user)
        estudiante.carrera = 'carrera'
        estudiante.anno = 'anno'
        estudiante.save()
        return user
    
asked by Pedro Diaz Labiste 29.01.2018 в 16:01
source

1 answer

1

The problem is that the model EstudiantePerfil has the field anno as non-nulleable ( null=False by default). Then, when estudiante = EstudiantePerfil.objects.create(user=user) is executed, that exception returns because the anno field is empty. You could make the anno field nulleable ( null=True ) or initialize the EstudiantePerfil object with a valid year.

    
answered by 29.01.2018 / 18:10
source