How to include address model in profile model.

I am struggling with how I should structure my application and some things are not working as expected.

What I am working on is a form that is supposed to let a user set a billing (possibly also a shipping) address. Unfortunately, if I include the option billing address in the profile form, it lets the user choose from all addresses in the database, also from other users.

If I omit this, the address that the user enters gets saved in the database, but it is not connected to the user, and every time the user updates the form it saves the address again.

What I want is:

  • Address gets saved in relation to the user
  • Addresses are not redundant
  • Users shouldn’t be able to see the address of another user

I will attach the snippets that I think are relevant below. I am not sure if and how to change the views function in order to save the input from the billing address in relation to my user or if I should change the models, which I would rather avoid because I want to keep them simple.

forms.py
...
class ProfileEditForm(forms.ModelForm):
    date_of_birth = forms.DateInput()

    class Meta:
        model = Profile
        fields = ('date_of_birth', 'biography', 'description')  


class AddressUSEditForm(forms.ModelForm):
    class Meta:
        model = AddressUS
        fields = ('name', 'address_one', 'address_two', 'city', 'state', 'zipcode')
models.py

... # includes import of AddressUS Model

class Profile(models.Model):
    user = models.OneToOneField(User, on_delete=models.CASCADE)
    date_of_birth = models.DateField(blank=True, null=True)
    address_billing = models.OneToOneField(AddressUS, null=True, blank=True,
                                           on_delete=models.CASCADE, related_name='billing')
    #  address_shipping = models.OneToOneField(AddressUS, null=True, blank=True,
    #                                        on_delete=models.CASCADE, related_name='shipping')
    biography = models.CharField(max_length=300, null=True, blank=True)
    description = models.CharField(max_length=2000, null=True, blank=True)

    def __str__(self):
        return f'{self.user.username} Profile'

    def save(self, *args, **kwargs):
        super().save()
someroute/models.py
...
class AddressUS(models.Model):
    name = models.CharField(max_length=400, null=True, blank=True)
    address_one = models.CharField(max_length=300)
    address_two = models.CharField(max_length=300)
    city = models.CharField(max_length=200)
    state = models.CharField(max_length=2)
    zipcode = models.IntegerField()

    def __str__(self):
        return self.address_one + ' ' + self.address_two + ' ' + self.city + ', ' + self.state

    def save(self, *args, **kwargs):
        super().save()
views.py
...
@login_required
def edit(request):
    if request.method == 'POST':
        user_form = UserEditForm(instance=request.user,
                                 data=request.POST)
        profile_form = ProfileEditForm(instance=request.user.profile,
                                       data=request.POST,
                                       files=request.FILES)
        address_form_billing = AddressUSEditForm(instance=request.user.profile.address_billing,
                                                 data=request.POST)
        if user_form.is_valid() and profile_form.is_valid() and address_form_billing.is_valid():
            user_form.save()
            profile_form.save()
            address_form_billing.save()
            messages.success(request, 'Profile updated successfully')
        else:
            messages.error(request, 'Error updating your profile')
    else:
        user_form = UserEditForm(instance=request.user)
        profile_form = ProfileEditForm(instance=request.user.profile)
        address_form_billing = AddressUSEditForm(instance=request.user.profile.address_billing)
    return render(request,
                  'users/edit.html',
                  {'user_form': user_form,
                   'profile_form': profile_form,
                   'address_form_billing': address_form_billing})

Any kind of help would be highly appreciated, I really need to get some order into this mess. If you need some more information to be able to answer the question I will gladly provide it.

Thanks!!!

You can construct the queryset allowing for the options to be selected to be limited to a particular set of options.

Again, this is something you can address within your view.

It really all comes down to how you want to handle this.

1 Like

Thank you so much for your reply.

I am a bit confused as to how I would save it in my views file. More particularly how would I go about saving the address that was entered in the form to the current user. So in my views file, I would like to do something like profile.address_billing = address_form_billing.

What I am not sure about is what address_form_billing actually contains and how I would access the profile.address_form property, so far I was only able to access it via profile_form, but for that I would have to include the property in the form and display all addresses again.

I’m not seeing where you confusion is coming from.

You have a defined relationship between Profile and AddressUS, which means that given either one you have direct access to the other.

Also, in your edit view you’re creating your forms using the instances through the relationships.

The only possible issue I see is that you’re using multiple forms on the same page without defining a prefix, but I also don’t see a problem there as things currently are without having one.