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

Time:03-12

I'm trying to create some entries in the database. I am not able to input anything for the Address models. I would like to be able to add the individual fields of the shipping_address. How can I achieve this?

serializer

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)

models

   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'

enter image description here

CodePudding user response:

I think you can use DRF's writable nested serializer.

Something like these (haven't tested it yet):

  • Add a serializer for the Address model:

    class AddressSerializer(serializers.ModelSerializer):
        class Meta:
            model = Address
            fields = '__all__'
    
  • And modify your current serializer for the User model (just like @Code-Apprentice said the comment, you can use the same Address model for both mailing_address and shipping_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)
    

CodePudding user response:

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

One thing to be careful about here: Django Rest Framework provides a convenient Web interface to interact with the REST API you are building. However, this is not the only way, and probably not even the most common way, to interact with your API.

In fact, users of your app, SHOULD NOT SEE THIS WEB INTERFACE. Instead, you should build your own interface which interacts with your REST API. This gives you the flexibility to create whatever forms in HTML that you want.

For example, you can create a single form with all of the user fields along with fields for a shipping address and for a separate billing address. Then you write JavaScript in the front end to create the Address objects with POST requests to your API. The POST request will return an id of the new address object. Then you make another POST request to create a user, with that id and all of the other user fields.

On a side note, there is no need for a ShippingAddress model which has the exact same fields as your Address model. Just use Address for all address fields:

        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)
  • Related