58

Từ Django.Contrib.Auth docs:Sử dụng Django auth UserAdmin cho một mô hình người dùng tùy chỉnh

Extending Django’s default User If you’re entirely happy with Django’s User model and you just want to add some additional profile information, you can simply subclass django.contrib.auth.models.AbstractUser and add your custom profile fields. This class provides the full implementation of the default User as an abstract model.

Said và thực hiện. Tôi đã tạo một mô hình mới như sau:

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ị viên là trường thiết lập mật khẩu (lại) không có mặt, nhưng một CharField bình thường được hiển thị thay thế. Tôi có thực sự phải ghi đè lên nội dung trong admin-config để làm việc này không? Nếu vậy, làm thế nào tôi có thể làm điều đó theo cách hơi DRY (tức là không sao chép nội dung từ nguồn Django ... eww ...)?

Trả lời

85

Sau khi đào xung quanh mã nguồn Django trong một thời gian, tôi đã tìm thấy một linh hồn làm việc. Tôi không hoàn toàn hài lòng với giải pháp này, nhưng có vẻ như nó hoạt động. 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 đẹp cho mô hình User. Chỉ cần sử dụng tính năng này trong admin.py -file của chúng tôi, chúng tôi có thể có giao diện tương tự cho mô hình của chúng tôi.

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

Tuy nhiên, điều này có thể không phải là 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:

  • UserAdmin sử dụng UserChangeForm là hình thức được sử dụng khi sửa đổi các đối tượng, do đó nó sử dụng User như mô hình của nó.
  • UserAdmin xác định formsets -property, sau này được sử dụng bởi 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 sao cho 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 tôi vào fieldset, đó là một phần của giải pháp này tôi không thích một chút, vì nó trông hơi xấu xí. Vui lòng đề xuất 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) 
+0

Tuyệt vời! Đó là chính xác những gì tôi đang tìm kiếm, tôi đang làm tương tự với mô hình người dùng tùy chỉnh của tôi, bằng cách 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 trường, thêm 'some_extra_data' của bạn trong 'Thông tin cá nhân') sẽ được tốt đẹp quá nhưng bây giờ bạn thực hiện ngày của tôi. Cảm ơn @nico – Dachmt

+0

Bạn được chào đón. Cảm thấy tự do để upvote nếu bạn đã không làm như vậy rồi. :) – nip3o

+0

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

44

Câu trả lời của nico vô cùng hữu ích nhưng tôi thấy Django vẫn tham chiếu Mô hình người dùng khi tạo người dùng mới.

#19353 tham chiếu vấn đề này.

Để sửa chữa nó tôi đã phải thực hiện một vài chi tiết bổ sung vào 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) 
+0

Giải pháp của bạn hoạt động hoàn hảo đối với 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 đến 'forms.ValidationError' có đối số thứ hai:' code = 'duplicate_username'': https://github.com/django/django/blob/1.6/django/contrib/auth/ forms.py # L101-L104 Ngoài ra, tôi đã thử điều này trên 1.6.5 và, vì một lý do nào đó, tôi không cần ghi đè 'UserChangeForm' chút nào và 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ì lớp 'UserChangeForm' có' model = User' hiện tại: https://github.com/django/django/blob/1.6.5/django/contrib/auth/forms. py # L138 – Nick

+0

Vé FYI [# 19353] (https://code.djangoproject.com/ticket/19353) hiện đã được sửa mà về cơ bản có nghĩa là giải pháp của bạn có thể không cần thiết. Nếu chúng ta chỉ sử dụng giải pháp của @ nip3o thì chúng ta nên làm tốt. – kstratis

28

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.

+0

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

+0

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

+0

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

1

Câu trả lời của Cesc không hoạt động đối 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 tìm thấy thêm các lĩnh vực cho cả hai lĩnh vực và add_fieldsets đã làm các trick.

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)