2013-11-04 4 views
17

장고 영역에서는 새로운데 거기에는 많은 "마법"이 있습니다. 장고 REST 프레임 워크를 사용하고 있으며 무료 사용자 등록을 허용하는 앱을 만들고 있습니다. 내 사용자는 장고 사용자가 사용할 수없는 추가 필드가 필요합니다. 그래서 나는 사용자를 확장하기 위해 인터넷 검색을했습니다. 이이Django REST Framework 사용자 정의 사용자 만들기

class MyUser(models.Model): 
    user = models.ForeignKey(User, unique=True) 
    city = models.CharField(max_length=50, blank=True, default='') 

이 괜찮습니다하지만

class UserSerializer(serializers.ModelSerializer): 
    class Meta: 
     model = MyUser 
     fields = ('id', 'username', 'password', 'first_name', 'last_name', 'email', 'city') 

그래서이 시리얼을 가지고 뭔가를 만들어 수행해야한다는 생각이있다, 문제는이 시리얼 여기에 약간의 "마법"을 수행한다는 것입니다 . 그것은 어떤 필드가 모델해야하는지 알아 내려고합니다. 여기에 나열된 필드가있는 사용자를 갖고 싶습니다.이 필드는 User에 있고 'city'는 새로운 사용자 정의 필드입니다. Serializer는 사용자 모델 내부를 살펴 봐야하지 않습니다.

무엇이 여기에 있습니까? 사용자 내부에 일부 필드를 원한다는 것을이 serializer에 알려주는 방법은 무엇입니까? 나는 크레테 사용자도 할 수 있어야합니다.

+6

당신은 당신의 UserModel 관계가 아닌'ForeignKey'에 대한'OneToOneField'를 사용해야합니다. –

+0

'OneToOneField'를 사용하고이 대답을 따라하면됩니다. [link] (http://stackoverflow.com/a/28733782/3294412) – musicformellons

답변

1

django 1.5 이상을 사용하는 경우 custom user model을 대신 사용하면 사용자 모델에 전용 테이블이 있으므로 serializer가 필드를 올바르게 선택합니다.

+0

정말 옵션이 아니라고 생각합니다. 아마도 1.4를 사용할 것입니다. . 이 일이 정말로 어렵다는 것을 나는 정말로 이해하지 못한다. 왜 그런가요? 내가해야 할 표준적인 일과 같은 솔기가 있는데, 왜 이렇게 복잡한가요? – bradojevic

1

Django Rest Framework를 사용할 때는 조심해야합니다. 모든 사용자 정의 사용자 모델은 내장 토큰 인증을 사용할 수 없습니다. 당신이 그것을 할 수있을 때까지, 나는 당신의 커스텀 모델에서 사용자와 함께 OneToOneField를 사용할 것을 제안 할 것이다. 맞춤 모델에 보관하려는 추가 입력란이 포함됩니다. 일대일로 사용자 지정 사용자의 사용자 및 사용자의 사용자 지정 사용자에게 액세스 할 수 있습니다.

+5

게시한지 거의 1 년이 지났습니다. DRF가 Django의 사용자 정의 사용자 모델을 아직 지원합니까? 아니면이 대답이 여전히 정확한지, 사용자와 함께 OneToOneFields가 여전히 가장 좋은 아이디어입니까? – ArtOfWarfare

12

좋아, 몇 가지. 사용자 모델 확장을 위해 OneToOneField을 만들고 싶습니다.

class MyUser(models.Model): 
    user = models.OneToOneField(User) 
    city = models.CharField(max_length=50, blank=True, default='') 

자, 장고 나머지 프레임 워크의 힘은 당신이 당신의 시리얼을 구축 할 수 있습니다 직렬화 할 때 이러한 모델 모두에서 데이터를 걸릴 것입니다.

class UserSerializer(serializers.ModelSerializer): 
    city = serializers.CharField(source='myuser.city') 
    class Meta: 
     model = User 
     fields = ('id', 'username', 'password', 'first_name', 'last_name', 'email', 'city') 

마지막으로, 우리는 당신이 사용자 정의 필드를 사용하고 있기 때문에, 당신은 입력 데이터에서 두 모델을 구축 자신의 restore_object()를 구현해야 사용자를 작성하고 있습니다.

또한 장고에 사용자를 생성하는 것은 약간 다르므로 create_user()으로 전화를 걸어 해시 된 암호를 제공해야합니다. 따라서 암호는 serializer의 필드를 저장하는 것처럼 간단하지 않습니다.

+0

답변을 확장하여'restore_object()'와'create_user()'의 예제 구현을 포함시킬 수 있습니까? 암호를 해싱하는 방법에 대해 확신하지 못합니다. (사실 당신은 우리 마음 속에 붉은 깃발을 올리라고 제안합니다. 장고 나 DRF가 이런 종류의 보안을 제공해서는 안됩니다. 상자?) – ArtOfWarfare

+0

이 답변을 주셔서 감사합니다! 그것까지 추가하면 id 속성'user_profile = serializers.CharField (source = 'userprofile.id')'로 갈 수 있습니다. – pasql

16

그래서 분명히 답변 아래에 의견을 게시 할만큼 충분한 평판이 없습니다. 당신이 모델 같은 경우 그러나, 케빈 스톤 설명 무엇에 정교한하려면 다음

class AppUserSerializer(serializers.ModelSerializer): 
    username = serializers.CharField(source='user.username') 
    email = serializers.CharField(source='user.email') 
    password = serializers.CharField(source='user.password') 
    ban_status = serializers.Field(source='ban_status') 

    class Meta: 
     model = AppUser 
     fields = ('id', 'username', 'email', 'password', 'ban_status') 

    def restore_object(self, attrs, instance=None): 
     """ 
     Given a dictionary of deserialized field values, either update 
     an existing model instance, or create a new model instance. 
     """ 
     if instance is not None: 
      instance.user.email = attrs.get('user.email', instance.user.email) 
      instance.ban_status = attrs.get('ban_status', instance.ban_status) 
      instance.user.password = attrs.get('user.password', instance.user.password) 
      return instance 

     user = User.objects.create_user(username=attrs.get('user.username'), email= attrs.get('user.email'), password=attrs.get('user.password')) 
     return AppUser(user=user) 
+4

restore_object()는 DRF 3.x와 호환되지 않으므로 대신 create() 및 update() 메소드를 사용해야합니다. 여기의 예 : http://www.django-rest-framework.org/topics/3.0-announcement/#serializers. – jarmod

0

그것은 것 :

class AppUser(models.Model): 
    user = models.OneToOneField(User) 
    ban_status = models.BooleanField(default=False) 

당신이 뭔가를 할 수있는 것은 사용자 정의 사용자와 장고 사용자를 모두 만들 수 있습니다 이 유스 케이스가 문서에서 더 쉽게 찾을 수 있다면 좋을 것이다. @jamod가 지적한 바와 같이, DRF 3, 당신은 그것을 here를 찾을 수 있습니다

class UserSerializer(serializers.ModelSerializer): 
    profile = ProfileSerializer() 

    class Meta: 
     model = User 
     fields = ('username', 'email', 'profile') 

    def create(self, validated_data): 
     profile_data = validated_data.pop('profile') 
     user = User.objects.create(**validated_data) 
     Profile.objects.create(user=user, **profile_data) 
     return user 
1

을 당신이 전화를 드릴 것입니다 무언가가 일어날 때 응용 프로그램에 신호를 보내는 장고 signals 모듈을 사용하는 것을 선호하고, 다른 것들 사이 다른 기능의 전후에 자신의 기능.내 대답은 스튜어트의 대답과 비슷하지만 새 확장 클래스와 관련된 모든 코드를 한 곳에서 유지합니다 (나중에 프로필을 삭제하거나 다른 곳에서 볼 필요가없는 이름을 변경하려는 경우).

다음 코드는 확장 클래스 모델 (이 경우 사용자 프로필)을 작성한 다음 사용자 모델을 만들 때 빈 인스턴스를 만든 다음 해당 인스턴스를 저장하여 새 정보 (인스턴스를 추가해야 함)를 저장합니다. 부모 사용자 인스턴스의 예 - user.save()

models.py

from django.db.models.signals import post_save 
from django.db import models 
from django.contrib.auth.models import User 

class Profile(models.Model): #This extends the user class to add profile information 
    user = models.OneToOneField(User, on_delete=models.CASCADE) 
    #add your extra traits here: is_nice, is_shwifty, address, etc. 
    is_nice = models.BooleanField(default=True, blank=True) 

# a user model was just created! This now creates your extended user (a profile): 
@receiver(post_save, sender=User) 
def create_user_profile(sender, instance, created, **kwargs): 
    if created: 
     # instance is the user model being saved. 
     Profile.objects.create(user=instance) 

# a user model was just saved! This now saves your extended user (a profile): 
@receiver(post_save, sender=User) 
def save_user_profile(sender, instance, **kwargs): 
     instance.profile.save() 

당신은 ProfileSerializer이없는 경우 : serializers.py

을 0
#use hyperlinkedmodelserializer for easy api browsing + clicking 
class ProfileSerializer(serializers.HyperlinkedModelSerializer): 
    user = UserSerializer() 
    class Meta: 
     model = Profile 
     fields = ('url', 'user', 'is_nice') 

사용자를 만들고 사용자를 저장하면 정보를 추가 할 빈 user.profile이 생깁니다. 예를 들어, python manage.py shell 시도를 실행 한 후 : 자신의 모든`User` 인스턴스에 대해 하나의`MyUser` 수 있기 때문에

from backend.models import User, Profile 
#create your user 
user=User(username="GravyBoat") 
user.save() 
#now update your user's profile 
user.profile.is_nice=False 
#that's one mean gravy boat 
user.save() 
user.profile.is_nice 
#False 
관련 문제