2014-12-21 17 views
13

Tình hìnhbổ sung Serializer Fields trong Django REST của Khung 3

tôi đang tạo ra một thiết bị đầu cuối đơn giản mà cho phép việc tạo ra một người dùng. Tôi cần một trường không có trong mẫu người dùng của tôi (ví dụ: confirm_password). Tôi sẽ chạy xác nhận so sánh trường này và một trường khác nằm trong mô hình của tôi, và sau đó không bao giờ sử dụng lại trường bổ sung trong bộ nối tiếp.

Vấn đề

DRF phiên bản 3 đã thay đổi quá trình cho việc này, và tôi không hoàn toàn hiểu những gì các tài liệu được đề nghị tôi làm. Xem here để biết tài liệu.

Nỗ lực tại Giải pháp

tôi đã tạo ra một UserSerializer trông như thế này:

from django.contrib.auth import get_user_model 
from rest_framework import serializers 

class UserSerializer(serializers.ModelSerializer): 
    confirm_password = serializers.CharField(allow_blank=False) 

    def validate(self, data): 
     """ 
     Checks to be sure that the received password and confirm_password 
     fields are exactly the same 
     """ 
     if data['password'] != data.pop('confirm_password'): 
      raise serializers.ValidationError("Passwords do not match") 
     return data 

    def create(self, validated_data): 
     """ 
     Creates the user if validation succeeds 
     """ 
     password = validated_data.pop('password', None) 
     user = self.Meta.model(**validated_data) 
     user.set_password(password) 
     user.save() 
     return user 

    class Meta: 
     # returns the proper auth model 
     model = get_user_model() 
     # fields that will be deserialized 
     fields = ['password', 'confirm_password', 
        'username', 'first_name', 'last_name', 'email'] 
     # fields that will be serialized only 
     read_only_fields = ['is_staff', 'is_superuser'] 
     # fields that will be deserialized only 
     write_only_fields = ['password' 'confirm_password'] 

Tôi đã hy vọng rằng popping confirm_password trong validate sẽ chăm sóc của các vấn đề của tôi, nhưng tôi chỉ nhận được như sau:

KeyError khi cố gắng nhận giá trị cho trường confirm_password trên bộ nối tiếp UserSerializer. Các lĩnh vực serializer có thể được đặt tên không chính xác và không phù hợp với bất kỳ thuộc tính hoặc phím trên OrderedDict dụ

+0

Chỉ cần một người đứng đầu lên, nó phổ biến cho hầu hết mọi người để đưa Lớp 'Meta' ở đầu bộ nối tiếp, vì nó chứa phần lớn thông tin bạn thường tìm kiếm. –

+0

Ah, điều đó có ý nghĩa. Tôi đánh giá cao nó! – nmagerko

Trả lời

18

Bạn đang tìm kiếm một lĩnh vực chỉ ghi, như tôi giả sử bạn sẽ không muốn hiển thị thư xác nhận mật khẩu trong API. Khung công tác Django REST đã giới thiệu tham số write_only trong dòng thời gian 2.3.x để bổ sung tham số read_only, vì vậy việc xác thực thời gian duy nhất được chạy là khi cập nhật được thực hiện. Thuộc tính meta write_only_fields được thêm vào cùng một thời điểm, nhưng điều quan trọng là phải hiểu cách cả hai tính năng này hoạt động cùng nhau.

Thuộc tính meta write_only_fields sẽ tự động thêm thuộc tính write_only vào trường khi trường được tạo tự động, như trường password trên mô hình User. Nó sẽ không thực hiện việc này cho bất kỳ trường nào không có trên mô hình hoặc các trường đã được chỉ định rõ ràng trên bộ nối tiếp. Trong trường hợp của bạn, bạn đang xác định rõ ràng trường confirm_password trên bộ nối tiếp của bạn, đó là lý do tại sao nó không hoạt động.

KeyError khi cố gắng nhận giá trị cho trường confirm_password trên bộ nối tiếp UserSerializer. Các lĩnh vực serializer có thể được đặt tên không chính xác và không phù hợp với bất kỳ thuộc tính hoặc phím trên OrderedDict dụ

này được đưa ra trong việc tái serialization của người sử dụng tạo ra, khi nó đang cố gắng để serialize lĩnh vực confirm_password của bạn. Bởi vì nó không thể tìm thấy trường trên mô hình User, nó kích hoạt lỗi này cố giải thích vấn đề. Thật không may vì đây là một người dùng mới, ứng dụng này cho bạn biết đáng ngạc nhiên khi xem phiên bản OrderedDict thay vì phiên bản User.

class UserSerializer(serializers.ModelSerializer): 
    confirm_password = serializers.CharField(allow_blank=False, write_only=True) 

Nếu bạn chỉ định một cách rõ ràng write_only trên các lĩnh vực serializer, và loại bỏ các lĩnh vực từ write_only_fields của bạn, sau đó bạn sẽ thấy hành vi của bạn đang mong đợi.

Bạn có thể tìm tài liệu về vấn đề này về vấn đề này link

0

Cũng hữu ích cho các mô hình đại diện cho lồng nhau serializer thực hiện, khi model gốc không có trực tiếp tiếp cận với lĩnh vực bạn muốn sử dụng. Cảm ơn bạn @vyscond;) FYI đây là trường hợp của tôi:

models.py

class Company(models.Model): 
    permission_classes = (
     IsCompanyMember, 
    ) 

    name = models.CharField(
     unique=True, 
     max_length=100, 
     verbose_name='company name', 
     null=False 
    ) 
class Profile(models.Model): 

    company = models.ForeignKey(Company, on_delete=models.CASCADE, null=True) 
    user = models.OneToOneField(User, on_delete=models.CASCADE) 
    is_company_admin = models.BooleanField(default=False, null=False) 
    is_email_validated = models.BooleanField(default=False, null=False) 
    is_approved_by_company_admin = models.BooleanField(default=False, null=False) 

serializer.py

class CompanySerializer(serializers.ModelSerializer): 
    class Meta: 
     model = Company 
     fields = ('name',) 

class CustomUserRegistrationSerializer(serializers.ModelSerializer): 
    password = serializers.CharField(style={'input_type': 'password'}, 
           write_only=True, 
           validators=settings.get('PASSWORD_VALIDATORS')) 

    company = CompanySerializer(allow_null=False, required=True,write_only=True) 

    class Meta: 
     model = User 
     fields = ('username', 
        'email', 
        'password', 
        'company', 
        'first_name', 
        'last_name') 
Các vấn đề liên quan