如何在 Django 的创建视图中显示其他模型的字段?

How do I display fields of other models in a create view in Django?

我正在尝试在数据库中创建一些条目。我无法为地址模型输入任何内容。我希望能够添加 shipping_address 的各个字段。我怎样才能做到这一点?

序列化器

class UserSerializer(serializers.ModelSerializer):
    """Serializer for the users object"""

    class Meta:
        model = get_user_model()
        fields = ('email', 'password', 'first_name', 'last_name', 'mailing_address', 'shipping_address', 'phone', 'is_active', 'is_staff', 'is_approver')

    def create(self, validated_data):
        """Create a new user with encrypted password and return it"""
        return get_user_model().objects.create_user(**validated_data)

型号

   class Address(models.Model):
        first_address = models.CharField(max_length=255, blank=True, default='')
        second_address = models.CharField(max_length=255, blank=True, default='')
        city = models.CharField(max_length=255, blank=True, default='')
        state = models.CharField(max_length=255, blank=True, default='')
        zip = models.CharField(max_length=255, blank=True, default='')
    
    
    class Phone(models.Model):
        phone_number = PhoneField(blank=True, help_text='Contact phone number')
    
    
    class ShippingAddress(models.Model):
        first_address = models.CharField(max_length=255, blank=True, default='')
        second_address = models.CharField(max_length=255, blank=True, default='')
        city = models.CharField(max_length=255, blank=True, default='')
        state = models.CharField(max_length=255, blank=True, default='')
        zip = models.CharField(max_length=255, blank=True, default='')
    
    
    class User(AbstractBaseUser, PermissionsMixin):
        """Custom user model that suppors using email instead of username"""
        email = models.EmailField(max_length=255, unique=True)
        first_name = models.CharField(max_length=255, blank=True, default='')
        last_name = models.CharField(max_length=255, blank=True, default='')
        password = forms.CharField(widget=forms.PasswordInput)
        phone = models.ForeignKey(Phone, on_delete=models.CASCADE, null=True, blank=True)
        mailing_address = models.ForeignKey(Address, on_delete=models.CASCADE, null=True, blank=True)
        shipping_address = models.ForeignKey(ShippingAddress, on_delete=models.CASCADE, null=True, blank=True)
        is_active = models.BooleanField(default=True)
        is_staff = models.BooleanField(default=False)
        is_approver = models.BooleanField(default=False)
    
        objects = UserManager()
    
        USERNAME_FIELD = 'email'

How do I display fields of other models in a create view in Django?

这里要注意一件事:Django Rest Framework 提供了一个方便的 Web 界面来与您正在构建的 REST API 进行交互。然而,这不是与您的 API.

互动的唯一方式,甚至可能不是最常见的方式

事实上,您应用的用户不应该看到这个网络界面。相反,您应该构建自己的与 REST API 交互的界面。这使您可以灵活地在 HTML 中创建您想要的任何表单。

例如,您可以创建一个表单,其中包含所有用户字段以及送货地址字段和单独的帐单地址字段。然后你在前端编写 JavaScript 以创建 Address 对象,并向你的 API 请求 POST。 POST 请求将 return 新地址对象的 ID。然后,您使用 id 和所有其他用户字段发出另一个 POST 请求来创建用户。

附带说明一下,不需要 ShippingAddress 模型与您的 Address 模型具有完全相同的字段。只需对所有地址字段使用 Address

        mailing_address = models.ForeignKey(Address, on_delete=models.CASCADE, null=True, blank=True)
        shipping_address = models.ForeignKey(Address, on_delete=models.CASCADE, null=True, blank=True)

我认为你可以使用 DRF writable nested serializer

类似这些(尚未测试):

  • Address 模型添加序列化程序:

    class AddressSerializer(serializers.ModelSerializer):
        class Meta:
            model = Address
            fields = '__all__'
    
  • 并为User模型修改你当前的序列化器(就像@Code-Apprentice评论说的那样,你可以对两者使用相同的Address模型mailing_addressshipping_address):

    class UserSerializer(serializers.ModelSerializer):
        """Serializer for the users object"""
        mailing_address = AddressSerializer()
        shipping_address = AddressSerializer()
    
        class Meta:
            model = get_user_model()
            fields = ('email', 'password', 'first_name', 'last_name', 'mailing_address', 'shipping_address', 'phone', 'is_active', 'is_staff', 'is_approver')
    
        def create(self, validated_data):
            """Create a new user with encrypted password and return it""" 
            mailing_address = Address.objects.create(**validated_data.pop('mailing_address'))
            shipping_address = Address.objects.create(**validated_data.pop('shipping_address'))
            return get_user_model().objects.create_user(mailing_address=mailing_address, shipping_address=shipping_address, **validated_data)