2

i'm following a tutorial https://codingwithmitch.com/courses/building-a-website-django-python/ to build a user registration app with django 2.2. my site works just fine exept when I want to add a new user or modify one in the admin panel. this is the traceback that I get:

Environment:


Request Method: GET
Request URL: http://127.0.0.1:8000/admin/account/account/1/change/

Django Version: 2.2.2
Python Version: 3.7.5
Installed Applications:
['django.contrib.admin',
 'django.contrib.auth',
 'django.contrib.contenttypes',
 'django.contrib.sessions',
 'django.contrib.messages',
 'django.contrib.staticfiles',
 'phonenumber_field',
 'rest_framework',
 'account']
Installed Middleware:
['django.middleware.security.SecurityMiddleware',
 'django.contrib.sessions.middleware.SessionMiddleware',
 'django.middleware.common.CommonMiddleware',
 'django.middleware.csrf.CsrfViewMiddleware',
 'django.contrib.auth.middleware.AuthenticationMiddleware',
 'django.contrib.messages.middleware.MessageMiddleware',
 'django.middleware.clickjacking.XFrameOptionsMiddleware']



Traceback:

File "C:\Users\IR-Tech\Anaconda3\envs\ArianaSite\lib\site-packages\django\core\handlers\exception.py" in inner
  34.             response = get_response(request)

File "C:\Users\IR-Tech\Anaconda3\envs\ArianaSite\lib\site-packages\django\core\handlers\base.py" in _get_response
  115.                 response = self.process_exception_by_middleware(e, request)

File "C:\Users\IR-Tech\Anaconda3\envs\ArianaSite\lib\site-packages\django\core\handlers\base.py" in _get_response
  113.                 response = wrapped_callback(request, *callback_args, **callback_kwargs)

File "C:\Users\IR-Tech\Anaconda3\envs\ArianaSite\lib\site-packages\django\contrib\admin\options.py" in wrapper
  606.                 return self.admin_site.admin_view(view)(*args, **kwargs)

File "C:\Users\IR-Tech\Anaconda3\envs\ArianaSite\lib\site-packages\django\utils\decorators.py" in _wrapped_view
  142.                     response = view_func(request, *args, **kwargs)

File "C:\Users\IR-Tech\Anaconda3\envs\ArianaSite\lib\site-packages\django\views\decorators\cache.py" in _wrapped_view_func
  44.         response = view_func(request, *args, **kwargs)

File "C:\Users\IR-Tech\Anaconda3\envs\ArianaSite\lib\site-packages\django\contrib\admin\sites.py" in inner
  223.             return view(request, *args, **kwargs)

File "C:\Users\IR-Tech\Anaconda3\envs\ArianaSite\lib\site-packages\django\contrib\admin\options.py" in change_view
  1637.         return self.changeform_view(request, object_id, form_url, extra_context)

File "C:\Users\IR-Tech\Anaconda3\envs\ArianaSite\lib\site-packages\django\utils\decorators.py" in _wrapper
  45.         return bound_method(*args, **kwargs)

File "C:\Users\IR-Tech\Anaconda3\envs\ArianaSite\lib\site-packages\django\utils\decorators.py" in _wrapped_view
  142.                     response = view_func(request, *args, **kwargs)

File "C:\Users\IR-Tech\Anaconda3\envs\ArianaSite\lib\site-packages\django\contrib\admin\options.py" in changeform_view
  1522.             return self._changeform_view(request, object_id, form_url, extra_context)

File "C:\Users\IR-Tech\Anaconda3\envs\ArianaSite\lib\site-packages\django\contrib\admin\options.py" in _changeform_view
  1551.         ModelForm = self.get_form(request, obj, change=not add)

File "C:\Users\IR-Tech\Anaconda3\envs\ArianaSite\lib\site-packages\django\contrib\auth\admin.py" in get_form
  80.         return super().get_form(request, obj, **defaults)

File "C:\Users\IR-Tech\Anaconda3\envs\ArianaSite\lib\site-packages\django\contrib\admin\options.py" in get_form
  669.             fields = flatten_fieldsets(self.get_fieldsets(request, obj))

File "C:\Users\IR-Tech\Anaconda3\envs\ArianaSite\lib\site-packages\django\contrib\auth\admin.py" in get_fieldsets
  70.         return super().get_fieldsets(request, obj)

File "C:\Users\IR-Tech\Anaconda3\envs\ArianaSite\lib\site-packages\django\contrib\admin\options.py" in get_fieldsets
  330.         return [(None, {'fields': self.get_fields(request, obj)})]

File "C:\Users\IR-Tech\Anaconda3\envs\ArianaSite\lib\site-packages\django\contrib\admin\options.py" in get_fields
  321.         form = self._get_form_for_get_fields(request, obj)

File "C:\Users\IR-Tech\Anaconda3\envs\ArianaSite\lib\site-packages\django\contrib\admin\options.py" in _get_form_for_get_fields
  659.         return self.get_form(request, obj, fields=None)

File "C:\Users\IR-Tech\Anaconda3\envs\ArianaSite\lib\site-packages\django\contrib\auth\admin.py" in get_form
  80.         return super().get_form(request, obj, **defaults)

File "C:\Users\IR-Tech\Anaconda3\envs\ArianaSite\lib\site-packages\django\contrib\admin\options.py" in get_form
  705.             return modelform_factory(self.model, **defaults)

File "C:\Users\IR-Tech\Anaconda3\envs\ArianaSite\lib\site-packages\django\forms\models.py" in modelform_factory
  551.     return type(form)(class_name, (form,), form_class_attrs)

File "C:\Users\IR-Tech\Anaconda3\envs\ArianaSite\lib\site-packages\django\forms\models.py" in __new__
  256.                 apply_limit_choices_to=False,

File "C:\Users\IR-Tech\Anaconda3\envs\ArianaSite\lib\site-packages\django\forms\models.py" in fields_for_model
  176.             formfield = formfield_callback(f, **kwargs)

File "C:\Users\IR-Tech\Anaconda3\envs\ArianaSite\lib\site-packages\django\contrib\admin\options.py" in formfield_for_dbfield
  185.                 return db_field.formfield(**kwargs)

File "C:\Users\IR-Tech\Anaconda3\envs\ArianaSite\lib\site-packages\phonenumber_field\modelfields.py" in formfield
  116.         return super().formfield(**defaults)

File "C:\Users\IR-Tech\Anaconda3\envs\ArianaSite\lib\site-packages\django\db\models\fields\__init__.py" in formfield
  1093.         return super().formfield(**defaults)

File "C:\Users\IR-Tech\Anaconda3\envs\ArianaSite\lib\site-packages\django\db\models\fields\__init__.py" in formfield
  891.         return form_class(**defaults)

File "C:\Users\IR-Tech\Anaconda3\envs\ArianaSite\lib\site-packages\django\forms\fields.py" in __init__
  214.         super().__init__(**kwargs)

Exception Type: TypeError at /admin/account/account/1/change/
Exception Value: __init__() got an unexpected keyword argument 'region'

this is my models.py:

from django.db import models
from phonenumber_field.modelfields import PhoneNumberField
from django.contrib.auth.models import AbstractBaseUser, BaseUserManager


class MyAccountManager(BaseUserManager):
    def create_user(self, username, email, first_name, last_name, password=None):
        if not username:
            return ValueError("وارد نمودن شماره تلفن همراه الزامیست")
        if not email:
            return ValueError("وارد نمودن ایمیل الزامیست")
        if not first_name:
            return ValueError("وارد نمودن نام الزامیست")
        if not last_name:
            return ValueError("وارد نمودن نام خانوادگی الزامیست")

        user = self.model(
            email=self.normalize_email(email),
            username=username,
            first_name=first_name,
            last_name=last_name,
        )

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

    def create_superuser(self, username, email, first_name, last_name, password):
        user = self.create_user(
            email=self.normalize_email(email),
            password=password,
            username=username,
            first_name=first_name,
            last_name=last_name,
        )
        user.is_admin = True
        user.is_staff = True
        user.is_superuser = True
        user.save(using=self._db)
        return user


class Account(AbstractBaseUser):
    username = PhoneNumberField(verbose_name='شماره تلفن همراه', max_length=15, blank=False, unique=True, region='IR')
    first_name = models.CharField(verbose_name='نام', max_length=15)
    last_name = models.CharField(verbose_name='نام خانوادگی', max_length=40)
    email = models.EmailField(verbose_name='ایمیل', max_length=60, unique=True)
    date_joined = models.DateTimeField(verbose_name='تاریخ ملحق شدن', auto_now_add=True)
    last_login = models.DateTimeField(verbose_name='آخرین بازدید', auto_now=True)
    is_admin = models.BooleanField(default=False)
    is_active = models.BooleanField(default=True)
    is_staff = models.BooleanField(default=False)
    is_superuser = models.BooleanField(default=False)

    USERNAME_FIELD = 'username'
    REQUIRED_FIELDS = ['email', 'first_name', 'last_name', ]

    objects = MyAccountManager()

    def __str__(self):
        return str(self.username) + ', ' + self.email

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

    def has_module_perms(self, app_label):
        return True

my admin.py:

from django.contrib import admin
from django.contrib.auth.admin import UserAdmin
from account.models import Account


class AccountAdmin(UserAdmin):
    list_display = ('username', 'email', 'date_joined', 'last_login', 'is_admin', 'is_staff')
    search_fields = ('username', 'email',)
    readonly_fields = ('date_joined', 'last_login')

    filter_horizontal = ()
    list_filter = ('is_staff',)
    fieldsets = ()


admin.site.register(Account, AccountAdmin)

my forms.py:

from django import forms
from django.contrib.auth.forms import UserCreationForm
from django.contrib.auth import authenticate
from phonenumber_field.formfields import PhoneNumberField
from phonenumber_field.widgets import PhoneNumberInternationalFallbackWidget

from account.models import Account


class RegistrationForm(UserCreationForm):
    username = PhoneNumberField(help_text='این بخش الزامیست. لطفا شماره تلفن همراهتان را وارر نمایید',
                                label='شماره تلفن همراه', region='IR')
    email = forms.EmailField(max_length=60, help_text='این بخش الزامیست. لطفا ایمیاتان را وارر نمایید', label='ایمیل')

    class Meta:
        model = Account
        fields = ('username', 'email', 'first_name', 'last_name', 'password1', 'password2')


class AccountAuthenticationForm(forms.ModelForm):
    username = PhoneNumberField(label='شماره تلفن همراه', widget=PhoneNumberInternationalFallbackWidget, region='IR')
    password = forms.CharField(label='گذرواؤه', widget=forms.PasswordInput)

    class Meta:
        model = Account
        fields = ('username', 'password')

    def clean(self):
        username = self.cleaned_data['username']
        password = self.cleaned_data['password']
        if not authenticate(username=username, password=password):
            raise forms.ValidationError('اطلاعات وارد شده صحیح نمیباشد')

when i change the admin.py to:

from django.contrib import admin
from account.models import Account


admin.site.register(Account)

it works just fine but when i change it back to what it is it gives me that error. Is the problem in my admin or model?

Amir Skeb
  • 21
  • 4
  • What is this argument region='IR' in your forms supposed to do? It's not a valid argument. – Borut Dec 27 '19 at 17:37
  • @Borut I just added it when I was trying to fix the bug I've forgotten to remove it. I'll remove it right away. the bug was still there before I add it. – Amir Skeb Dec 27 '19 at 18:16
  • @AmirSkeb pls remove all the 'region' params from `both` your `forms` and your `model` and see what you would get. I really don't think that the error will repeat. – Nikita Tonkoskur Dec 27 '19 at 19:24
  • @NikitaTonkoskur I removed it after I posted my question but as I said in my last comment I did it after the error occurred when I was trying to fix the bug. I have a (PHONENUMBER_DEFAULT_REGION = "IR") in my settings.py which is needed for (PHONENUMBER_DB_FORMAT = 'NATIONAL'). – Amir Skeb Dec 27 '19 at 19:37

2 Answers2

0

I had to upgrade to django-phonenumber-field==3.0.1 to fix it.

patroqueeet
  • 764
  • 1
  • 8
  • 19
0

I know it is too late to answer this, but in case someone might face the same issue later.

I encountered the same problem when I was trying to use PhoneNumberField as the default username.

In admin.py, the AccountAdmin class is inheriting properties from UserAdmin.

When you run http://127.0.0.1:8000/admin/account/account/1/change/, the UserAdmin class implements a form django.contrib.auth.forms.UserChangeForm.

This form contains an inbuilt custom-model field UsernameField. It would be best to just replace this field with phonenumber_field.formfields.PhoneNumberField in UserChangeForm.

Similarly, the UserCreationForm also has the UsernameField in it. You need to replace that as well.

To do that, you must implement your custom UsernameField.

Replace your admin.py with the code below:

from django.contrib import admin
from django.contrib.auth.admin import UserAdmin
from account.models import Account

import phonenumber_field
from django.contrib.auth.forms import UserChangeForm, UserCreationForm
from django.contrib.auth.admin import UserAdmin

# Overriding inbuilt forms.UsernameField with formfields.PhoneNumberField
class UsernameField(phonenumber_field.formfields.PhoneNumberField):
    def widget_attrs(self, widget):
        return {
            **super().widget_attrs(widget),
            "autocapitalize": "none",
            "autocomplete": "username",
        }




class AccountAdmin(UserAdmin):

    form = UserChangeForm
    # Overriding UsernameField with Custom field
    form.Meta.field_classes['username'] = UsernameField
    add_form = UserCreationForm
    # Overriding UsernameField with Custom field
    add_form.Meta.field_classes['username'] = UsernameField
    list_display = ('username', 'email', 'date_joined', 'last_login', 'is_admin', 'is_staff')
    search_fields = ('username', 'email',)
    readonly_fields = ('date_joined', 'last_login')

    filter_horizontal = ()
    list_filter = ('is_staff',)
    fieldsets = ()


admin.site.register(Account, AccountAdmin)

Now it will work just fine.

Jithendra
  • 1
  • 2