Как я мог бы сохранить нескольких пользователей, используя флажок с отношением ManyToMany?

#python #django #django-forms

#python #django #django-forms

Вопрос:

В настоящее время у меня есть 4 записи в моей Role таблице, которые относятся к роли пользователя на веб-сайте. Эти роли можно выбрать в списке флажков с помощью, но я не могу сохранить данные, отправленные через форму. Я получаю следующую ошибку: 'RegisterForm' object has no attribute 'roles'** в forms.py .

чего мне здесь не хватает?

Вот код:

forms.py

 from django import forms
from django.contrib.auth.forms import UserCreationForm
from .models import User, Profile, Role


class RegisterForm(UserCreationForm):
    password1 = forms.CharField(min_length=4, widget=forms.PasswordInput(attrs={
        'placeholder': 'Password'
    }), label='password')
    password2 = forms.CharField(min_length=4, widget=forms.PasswordInput(attrs={
        'placeholder': 'Confirm Password'
    }), label='Confirm Password')

    class Meta:
        model = User
        fields = ['email', 'first_name', 'last_name', 'roles', 'password1']
        widgets = {
            'roles': forms.CheckboxSelectMultiple()
        }

    def clean_password2(self):
        password = self.cleaned_data['password1']
        password2 = self.cleaned_data['password2']
        if password and password2 and password != password2:
            raise forms.ValidationError("password and confirm password is not same")
        if len(password) < 4:
            raise forms.ValidationError('Password is very weak please enter 4 words at least')
        return password

    def save(self, commit=True):
        user = super().save(commit=False)
        if commit:
            user.staff = True
            user.set_password(self.cleaned_data['password1'])
            self.roles.add(self.cleaned_data['roles'])
            user.save()
        return user
 

models.py

 from django.db import models
from django.contrib.auth.models import AbstractBaseUser, PermissionsMixin
from .managers import UserManager
from django.db.models.signals import post_save


class Role(models.Model):
    MEMBER      = 1
    SECRETARY   = 2
    SUPERVISOR  = 3
    ADMIN       = 4

    ROLE_CHOICES = (
        (MEMBER, 'Member'),
        (SECRETARY, 'Secretary'),
        (SUPERVISOR, 'Supervisor'),
        (ADMIN, 'Admin'),
    )

    id = models.PositiveSmallIntegerField(choices=ROLE_CHOICES, primary_key=True)

    def __str__(self):
        return self.get_id_display()


class User(AbstractBaseUser, PermissionsMixin):
    roles = models.ManyToManyField(Role)
    email = models.EmailField(unique=True)
    first_name = models.CharField(max_length=15)
    last_name = models.CharField(max_length=15)
    date_joined = models.DateTimeField(auto_now_add=True)
    active = models.BooleanField(default=True)
    admin = models.BooleanField(default=False)
    staff = models.BooleanField(default=False)

    objects = UserManager()

    USERNAME_FIELD = 'email'
    REQUIRED_FIELDS = []

    def __str__(self):
        return self.email

    def get_full_name(self):
        return '{} {}'.format(self.first_name, self.last_name)

    def get_short_name(self):
        return self.email

    @property
    def is_staff(self):
        return self.staff

    @property
    def is_admin(self):
        return self.admin

    @property
    def is_active(self):
        return self.active

    def has_perm(self, perm, obj=None):
        return True


class Profile(models.Model):
    user = models.OneToOneField(User, on_delete=models.CASCADE)
    overview = models.TextField(max_length=2000, blank=True)


def create_profile(sender, **kwargs):
    if kwargs['created']:
        Profile.objects.create(user=kwargs['instance'])


post_save.connect(receiver=create_profile, sender=User)
 

Редактировать с новой трассировкой

 Traceback (most recent call last):
  File "/home/medo/.local/lib/python3.8/site-packages/django/db/backends/base/base.py", line 242, in _commit
    return self.connection.commit()

The above exception (FOREIGN KEY constraint failed) was the direct cause of the following exception:
  File "/home/medo/.local/lib/python3.8/site-packages/django/core/handlers/exception.py", line 47, in inner
    response = get_response(request)
  File "/home/medo/.local/lib/python3.8/site-packages/django/core/handlers/base.py", line 179, in _get_response
    response = wrapped_callback(request, *callback_args, **callback_kwargs)
  File "/media/medo/BE4C6BE74C6B98C3/Cources/Django/Infrastructure_django/UserApp/More than three users/project/app1/views.py", line 16, in register
    form.save()
  File "/media/medo/BE4C6BE74C6B98C3/Cources/Django/Infrastructure_django/UserApp/More than three users/project/app1/forms.py", line 36, in save
    user.roles.add(self.cleaned_data['roles'])
  File "/home/medo/.local/lib/python3.8/site-packages/django/db/models/fields/related_descriptors.py", line 957, in add
    self._add_items(
  File "/home/medo/.local/lib/python3.8/site-packages/django/db/transaction.py", line 232, in __exit__
    connection.commit()
  File "/home/medo/.local/lib/python3.8/site-packages/django/utils/asyncio.py", line 26, in inner
    return func(*args, **kwargs)
  File "/home/medo/.local/lib/python3.8/site-packages/django/db/backends/base/base.py", line 266, in commit
    self._commit()
  File "/home/medo/.local/lib/python3.8/site-packages/django/db/backends/base/base.py", line 242, in _commit
    return self.connection.commit()
  File "/home/medo/.local/lib/python3.8/site-packages/django/db/utils.py", line 90, in __exit__
    raise dj_exc_value.with_traceback(traceback) from exc_value
  File "/home/medo/.local/lib/python3.8/site-packages/django/db/backends/base/base.py", line 242, in _commit
    return self.connection.commit()

Exception Type: IntegrityError at /register/
Exception Value: FOREIGN KEY constraint failed
 

кроме того, может это может помочь

скриншот

Ответ №1:

Причина, по которой вы получаете 'RegisterForm' object has no attribute 'roles' ошибку, заключается в том, что self в

 self.roles.add(self.cleaned_data['roles'])
 

относится к форме, а не к вашему экземпляру пользователя.

Вместо этого вы хотите добавить к ролям пользователя вот так:

 user.roles.add(self.cleaned_data['roles'])
 

Однако имейте в виду, что при создании User экземпляра вам необходимо убедиться, что User объект уже создан / сохранен, прежде чем добавлять роли. Это необходимо, потому что для добавления внешнего ключа из ManyToMany отношения к User User экземпляру требуется id . Это id создается только после сохранения User экземпляра. Таким образом, в качестве конечного результата вы получите что-то вроде:

 user.save()
user.roles.add(self.cleaned_data['roles'])
 

Комментарии:

1. но когда я использую (user) Я получаю эту ошибку: «<Пользователь: sam@gmail.com >» должно быть значение для поля «id», прежде чем можно будет использовать это отношение «многие ко многим». когда я регистрируюсь

2. Это имеет смысл, поскольку ваш пользователь еще не создан в вашей базе данных. Перед добавлением ролей необходимо выполнить сохранение user.save() .

3. В своем ответе я добавил объяснение, зачем это нужно.

4. это исправлено, но у меня возникла другая проблема: сбой ограничения ВНЕШНЕГО КЛЮЧА

5. Таким образом, это не связано с исходной ошибкой и может означать несколько разных вещей. У вас есть дополнительная информация о том, какая строка выдает эту ошибку? Один из вариантов, который вы можете попробовать, — это добавление blank=True, null=True roles = models.ManyToManyField(Role, blank=True, null=True) . Другой — проверка содержимого self.cleaned_data['roles'] . Содержит ли он правильные идентификаторы ролей?