Repository: cookiecutter/cookiecutter-django

Issue:
Unknown field(s) (first_name, last_name) specified for User in admin
## What happened?
I created a new cookiecutter-django project and went through the steps [here](https://cookiecutter-django.readthedocs.io/en/latest/developing-locally.html) to get started.  Then I created a superuser and logged in, but when I click on the edit user link from the admin view I get the following error:

```
django.core.exceptions.FieldError: Unknown field(s) (first_name, last_name) specified for User. Check fields/fieldsets/exclude attributes of class UserAdmin.
```

<img width="1739" alt="image" src="https://user-images.githubusercontent.com/43428385/105708026-d474a980-5ee1-11eb-8da7-63b5c316ecf5.png">


## What should've happened instead?

Instead I should have gotten to the edit user admin page.

## Additional details

<!-- To assist you best, please include commands that you've run, options you've selected and any relevant logs -->

* Host system configuration: 
    * Version of cookiecutter CLI (get it with `cookiecutter --version`): `Cookiecutter 1.7.2 from /Users/leo/.virtualenvs/cryptoswap/lib/python3.9/site-packages (Python 3.9)`
    * OS: OSX
    * Python version: Python 3.9.1
    * Docker versions (if using Docker): not using docker
    * ...
* Options selected and/or [replay file](https://cookiecutter.readthedocs.io/en/latest/advanced/replay.html):
    ```json
		{
  "cookiecutter": {
    "project_name": "CryptoSwap",
    "project_slug": "cryptoswap",
    "description": "Bitcoin ATMs",
    "author_name": "Leo Policastro",
    "domain_name": "access.cryptoswap.com",
    "email": "leo-policastro@example.com",
    "version": "0.1.0",
    "open_source_license": "MIT",
    "timezone": "UTC",
    "windows": "n",
    "use_pycharm": "n",
    "use_docker": "n",
    "postgresql_version": "12.3",
    "js_task_runner": "Gulp",
    "cloud_provider": "AWS",
    "mail_service": "Mailgun",
    "use_async": "n",
    "use_drf": "y",
    "custom_bootstrap_compilation": "n",
    "use_compressor": "n",
    "use_celery": "n",
    "use_mailhog": "n",
    "use_sentry": "n",
    "use_whitenoise": "n",
    "use_heroku": "y",
    "ci_tool": "Github",
    "keep_local_envs_in_vcs": "n",
    "debug": "n",
    "_template": "gh:pydanny/cookiecutter-django"
  }
}
    ```
Am I doing something wrong?  I used cookiecutter for a different project last week and I did not have the same issue.



Discussion:
Probably caused by #2998

CC @Andrew-Chen-Wang 
Update: in the users.models file I edited

```python
first_name = None  # type: ignore
last_name = None  # type: ignore
```
to

```python
first_name = models.CharField(max_length=30, null=True, blank=True)
last_name = models.CharField(max_length=30, null=True, blank=True)
```
created and ran a migration and everything is working now.
These fields are not actually used in the project, so we should not create them in the DB. We probably missed a change in #2998 which means they are still referenced by a form somewhere.
oh shoot sorry. I would check UserChangeForm and the users/Admin.py
fieldsets. Will file PR soon.

On Mon, Jan 25, 2021 at 8:24 AM Bruno Alla <notifications@github.com> wrote:

> These fields are not actually used in the project, so we should not create
> them in the DB. We probably missed a change in #2998
> <https://github.com/pydanny/cookiecutter-django/pull/2998> which means
> they are still referenced by a form somewhere.
>
> —
> You are receiving this because you were mentioned.
> Reply to this email directly, view it on GitHub
> <https://github.com/pydanny/cookiecutter-django/issues/3016#issuecomment-766813386>,
> or unsubscribe
> <https://github.com/notifications/unsubscribe-auth/AOLG4VRD55W5XELTVZ7KI3DS3VWJZANCNFSM4WRWQGPQ>
> .
>

Sorry this is just a problem in admin.py and nothing with the forms. You shouldn't use the first_name and last_name field. What you need to do is copy the field sets from `user_admin.UserAdmin.fieldsets` and paste it to only use `name`. Same with some other places list `list_display`, `search_fields`, and `add_fieldsets`. Those three I only listed because I forgot if they include the attributes `first_name` and `last_name`. Just replace those two attributes everywhere with `name`

Resolving patch:
diff --git a/{{cookiecutter.project_slug}}/{{cookiecutter.project_slug}}/users/admin.py b/{{cookiecutter.project_slug}}/{{cookiecutter.project_slug}}/users/admin.py
--- a/{{cookiecutter.project_slug}}/{{cookiecutter.project_slug}}/users/admin.py
+++ b/{{cookiecutter.project_slug}}/{{cookiecutter.project_slug}}/users/admin.py
@@ -1,6 +1,7 @@
 from django.contrib import admin
 from django.contrib.auth import admin as auth_admin
 from django.contrib.auth import get_user_model
+from django.utils.translation import gettext_lazy as _
 
 from {{ cookiecutter.project_slug }}.users.forms import UserChangeForm, UserCreationForm
 
@@ -12,8 +13,22 @@ class UserAdmin(auth_admin.UserAdmin):
 
     form = UserChangeForm
     add_form = UserCreationForm
-    fieldsets = (("User", {"fields": ("name",)}),) + tuple(
-        auth_admin.UserAdmin.fieldsets
+    fieldsets = (
+        (None, {"fields": ("username", "password")}),
+        (_("Personal info"), {"fields": ("name", "email")}),
+        (
+            _("Permissions"),
+            {
+                "fields": (
+                    "is_active",
+                    "is_staff",
+                    "is_superuser",
+                    "groups",
+                    "user_permissions",
+                ),
+            },
+        ),
+        (_("Important dates"), {"fields": ("last_login", "date_joined")}),
     )
     list_display = ["username", "name", "is_superuser"]
     search_fields = ["name"]


Test patch:
diff --git a/{{cookiecutter.project_slug}}/{{cookiecutter.project_slug}}/users/tests/test_admin.py b/{{cookiecutter.project_slug}}/{{cookiecutter.project_slug}}/users/tests/test_admin.py
new file mode 100644
--- /dev/null
+++ b/{{cookiecutter.project_slug}}/{{cookiecutter.project_slug}}/users/tests/test_admin.py
@@ -0,0 +1,40 @@
+import pytest
+from django.urls import reverse
+
+from {{ cookiecutter.project_slug }}.users.models import User
+
+pytestmark = pytest.mark.django_db
+
+
+class TestUserAdmin:
+    def test_changelist(self, admin_client):
+        url = reverse("admin:users_user_changelist")
+        response = admin_client.get(url)
+        assert response.status_code == 200
+
+    def test_search(self, admin_client):
+        url = reverse("admin:users_user_changelist")
+        response = admin_client.get(url, data={"q": "test"})
+        assert response.status_code == 200
+
+    def test_add(self, admin_client):
+        url = reverse("admin:users_user_add")
+        response = admin_client.get(url)
+        assert response.status_code == 200
+
+        response = admin_client.post(
+            url,
+            data={
+                "username": "test",
+                "password1": "My_R@ndom-P@ssw0rd",
+                "password2": "My_R@ndom-P@ssw0rd",
+            },
+        )
+        assert response.status_code == 302
+        assert User.objects.filter(username="test").exists()
+
+    def test_view_user(self, admin_client):
+        user = User.objects.get(username="admin")
+        url = reverse("admin:users_user_change", kwargs={"object_id": user.pk})
+        response = admin_client.get(url)
+        assert response.status_code == 200