Sử dụng Django auth UserAdmin cho mô hình người dùng tùy chỉnh


79

Từ tài liệu Django.Contrib.Auth :

Mở rộng Người dùng mặc định của Django Nếu bạn hoàn toàn hài lòng với mô hình Người dùng của Django và bạn chỉ muốn thêm một số thông tin hồ sơ bổ sung, bạn có thể chỉ cần phân lớp django.contrib.auth.models.AbstractUservà thêm các trường hồ sơ tùy chỉnh của mình. Lớp này cung cấp sự triển khai đầy đủ của Người dùng mặc định như một mô hình trừu tượng.

Nói và xong. Tôi đã tạo một mô hình mới như dưới đây:

class MyUser(AbstractUser):
  some_extra_data = models.CharField(max_length=100, blank=True)

Điều này hiển thị trong quản trị gần giống như tiêu chuẩn của Django User. Tuy nhiên, sự khác biệt quan trọng nhất trong quản trị là trường đặt (lại) mật khẩu không xuất hiện, mà thay vào đó, một CharField bình thường được hiển thị. Tôi có thực sự phải ghi đè nội dung trong admin-config để điều này hoạt động không? Nếu vậy, làm thế nào tôi có thể làm điều đó theo cách hơi KHÔ (tức là không sao chép nội dung từ nguồn Django ... eww ...)?

Câu trả lời:


132

Sau khi tìm hiểu mã nguồn Django một lúc, tôi đã tìm thấy một linh hồn hoạt động. Tôi không hoàn toàn hài lòng với giải pháp này, nhưng nó có vẻ hiệu quả. Hãy đề xuất các giải pháp tốt hơn!


Django sử dụng UserAdminđể hiển thị giao diện quản trị viên đẹp mắt cho Usermô hình. Chỉ cần sử dụng cái này trong admin.py-tệp của chúng ta , chúng ta có thể có được giao diện tương tự cho mô hình của mình.

from django.contrib.auth.admin import UserAdmin
admin.site.register(MyUser, UserAdmin)

Tuy nhiên, điều này một mình có lẽ không phải là một giải pháp tốt, vì Django Admin sẽ không hiển thị bất kỳ trường đặc biệt nào của bạn. Có hai lý do cho việc này:

  • UserAdminsử dụng UserChangeFormlàm biểu mẫu được sử dụng khi sửa đổi đối tượng, đến lượt nó sẽ sử dụng Userlàm mô hình của nó.
  • UserAdminxác định một formsets-property, được sử dụng sau này UserChangeForm, không bao gồm các trường đặc biệt của bạn.

Vì vậy, tôi đã tạo một biểu mẫu thay đổi đặc biệt làm quá tải lớp bên trong Meta để biểu mẫu thay đổi sử dụng đúng mô hình. Tôi cũng đã phải quá tải UserAdminđể thêm các trường đặc biệt của mình vào tập trường, đó là phần của giải pháp này mà tôi không thích một chút, vì nó trông hơi xấu. Hãy đề xuất những cải tiến!

from django.contrib.auth.admin import UserAdmin
from django.contrib.auth.forms import UserChangeForm

class MyUserChangeForm(UserChangeForm):
    class Meta(UserChangeForm.Meta):
        model = MyUser

class MyUserAdmin(UserAdmin):
    form = MyUserChangeForm

    fieldsets = UserAdmin.fieldsets + (
            (None, {'fields': ('some_extra_data',)}),
    )


admin.site.register(MyUser, MyUserAdmin)

Tuyệt quá! Đó chính xác là những gì tôi đang tìm kiếm, tôi đang làm điều tương tự với mô hình người dùng tùy chỉnh của mình, sử dụng AbstractUser. Giải pháp này hoạt động tuyệt vời, một số tùy chỉnh (ẩn các trường, thêm 'some_extra_data' của bạn trong 'Thông tin cá nhân') cũng sẽ rất tuyệt nhưng bây giờ bạn đã làm cho ngày của tôi. Cảm ơn @nico
Dachmt

Quá tải các tập trường de UserAdmin xấu xí? Nó hoạt động. Cảm ơn.
allcaps:

6
Cũng lưu ý rằng bạn cần ghi đè biểu mẫu tạo người dùng, theo câu trả lời của @ kdh454.
Thane Brimhall,

Điều này là hoàn hảo, nó không lộn xộn chút nào. Tài liệu django trỏ đến bài viết này: docs.djangoproject.com/en/2.0/topics/auth/customizing/… ... nhưng tôi đã không thể làm cho nó hoạt động với điều đó, nó đã phàn nàn về một số ràng buộc khóa ngoại của Người dùng. Có thể chỉ liên quan đến dự án của tôi, tuy nhiên giải pháp của bạn hoạt động!
Vladimir Marton

56

Câu trả lời của nico đã cực kỳ hữu ích nhưng tôi thấy Django vẫn tham khảo mô hình Người dùng khi tạo người dùng mới.

số 19353 đề cập đến vấn đề này.

Để sửa chữa nó, tôi phải thực hiện thêm một số bổ sung cho admin.py

admin.py:

from django.contrib import admin
from django.contrib.auth.admin import UserAdmin
from django.contrib.auth.forms import UserChangeForm, UserCreationForm
from main.models import MyUser
from django import forms


class MyUserChangeForm(UserChangeForm):
    class Meta(UserChangeForm.Meta):
        model = MyUser


class MyUserCreationForm(UserCreationForm):
    class Meta(UserCreationForm.Meta):
        model = MyUser

    def clean_username(self):
        username = self.cleaned_data['username']
        try:
            MyUser.objects.get(username=username)
        except MyUser.DoesNotExist:
            return username
        raise forms.ValidationError(self.error_messages['duplicate_username'])


class MyUserAdmin(UserAdmin):
    form = MyUserChangeForm
    add_form = MyUserCreationForm
    fieldsets = UserAdmin.fieldsets + (
        (None, {'fields': ('extra_field1', 'extra_field2',)}),
    )

admin.site.register(MyUser, MyUserAdmin)

Giải pháp của bạn làm việc hoàn hảo cho tôi. Cảm ơn rất nhiều!
guinunez

3
Lưu ý rằng bắt đầu từ 1.6, lệnh gọi tới forms.ValidationErrorcó đối số thứ hai code='duplicate_username':: github.com/django/django/blob/1.6/django/contrib/auth/… Ngoài ra, tôi đã thử điều này vào 1.6.5 và vì một số lý do, tôi hoàn toàn không cần ghi đè UserChangeFormvà biểu mẫu thay đổi hoạt động tốt với trường tùy chỉnh của tôi. Tôi không thể giải thích tại sao. Có vẻ như nó không nên hoạt động vìUserChangeForm lớp học có model = Usermặt: github.com/django/django/blob/1.6.5/django/contrib/auth/…
Nick

2
FYI ticket # 19353 hiện đã được sửa về cơ bản có nghĩa là giải pháp của bạn có thể bị thừa. Nếu chúng ta chỉ sử dụng giải pháp của @ nip3o, chúng ta sẽ tốt.
kstratis

49

Một giải pháp đơn giản hơn, admin.py:

from django.contrib.auth.admin import UserAdmin
from main.models import MyUser

class MyUserAdmin(UserAdmin):
    model = MyUser

    fieldsets = UserAdmin.fieldsets + (
            (None, {'fields': ('some_extra_data',)}),
    )

admin.site.register(MyUser, MyUserAdmin)

Django sẽ tham chiếu chính xác mô hình MyUser để tạo và sửa đổi. Tôi đang sử dụng Django 1.6.2.


Tôi không biết tại sao nhưng tôi liên tục nhận được "TypeError: (các) loại toán hạng không được hỗ trợ cho +: 'NoneType' và 'tuple'" khi thử điều này.
Chase Roberts

Tôi đề nghị bạn kiểm tra UserAdmin.fieldsets và xem nếu nó None
Romulo Collopy

1
đây là câu trả lời cập nhật nhất và phải là câu được chấp nhận
brillout

1
Thay vào đó hãy để None, bạn có thể nhập một chuỗi và nó sẽ được sử dụng làm tiêu đề của phần này theo hình thức quản trị
Guillaume Lebreton

Đồng ý với @brillout, nhận thấy đây là câu trả lời tốt nhất. Để thêm, bạn có thể gặp lỗi này, điều này có ý nghĩa (Python 3.8, Django 3):ERRORS: <class 'users.admin.CustomerUserAdmin'>: (admin.E005) Both 'fieldsets' and 'fields' are specified.
nicorellius

9

Câu trả lời của cesc không hiệu quả với tôi khi tôi cố gắng thêm trường tùy chỉnh vào biểu mẫu tạo. Có lẽ nó đã thay đổi kể từ 1.6.2? Dù bằng cách nào, tôi thấy việc thêm trường vào cả hai fieldets và add_fieldsets đã thực hiện một mẹo nhỏ.

ADDITIONAL_USER_FIELDS = (
    (None, {'fields': ('some_additional_field',)}),
)

class MyUserAdmin(UserAdmin):
    model = MyUser

    add_fieldsets = UserAdmin.add_fieldsets + ADDITIONAL_USER_FIELDS
    fieldsets = UserAdmin.fieldsets + ADDITIONAL_USER_FIELDS

admin.site.register(MyUser, MyUserAdmin)

2

Một giải pháp tương tự khác ( Bắt đầu từ đây ):

from __future__ import unicode_literals

from django.contrib import admin
from django.contrib.auth.admin import UserAdmin
from django.contrib.auth.models import AbstractUser
from django.utils.translation import ugettext_lazy as _

from .models import User


class UserAdminWithExtraFields(UserAdmin):

    def __init__(self, *args, **kwargs):
        super(UserAdminWithExtraFields, self).__init__(*args, **kwargs)

        abstract_fields = [field.name for field in AbstractUser._meta.fields]
        user_fields = [field.name for field in self.model._meta.fields]

        self.fieldsets += (
            (_('Extra fields'), {
                'fields': [
                    f for f in user_fields if (
                        f not in abstract_fields and
                        f != self.model._meta.pk.name
                    )
                ],
            }),
        )


admin.site.register(User, UserAdminWithExtraFields)
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.