Home > OS >  Accessing field from OneToOne field in ModelForm using Class based Views
Accessing field from OneToOne field in ModelForm using Class based Views

Time:11-24

I have created a model Agent that is in a OneToOne relation with the User model. I managed to create a form where I can edit the Agent(user) details, but I would like to populate the form with the existing details of the model(Agent/user). Found something similar here but it is not using Class based views.

models.py ->

from django.contrib.auth.models import AbstractUser

class User(AbstractUser):
    is_organisor = models.BooleanField(default=True)
    is_agent = models.BooleanField(default=False)

class Agent(models.Model):
    user = models.OneToOneField(User, on_delete=models.CASCADE)   
    organisation = models.ForeignKey(UserProfile, on_delete=models.CASCADE)
    def __str__(self):
        return self.user.email

forms.py ->

from django import forms
from django.contrib.auth import get_user_model

User = get_user_model() 

class AgentModelForm(forms.ModelForm):
    class Meta:
        model = User
        fields = (
            'email',
            'username',
            'first_name',
            'last_name'
        )

views.py ->

class AgentUpdateView(OrganisorAndLoginRequiredMixin,generic.UpdateView):
    template_name = "agents/agent_update.html"
    form_class = AgentModelForm
    queryset = Agent.objects.all()
    def get_success_url(self):
        return reverse("agents:agent_list")

CodePudding user response:

I don't see any advantage in using a OneToOne field. In your case it's better to use a base class (with the User model):

models.py:

from django.contrib.auth.models import AbstractUser

class User(AbstractUser):
    is_organisor = models.BooleanField(default=True)
    is_agent = models.BooleanField(default=False)

class Agent(User): 
    organisation = models.ForeignKey(UserProfile, on_delete=models.CASCADE)
    def __str__(self):
        return self.email

So, now, 'email', 'username', 'first_name' and 'last_name' are fields of your Agent model.

forms.py

from django import forms
from .models import Agent

class AgentModelForm(forms.ModelForm):
    class Meta:
        model = Agent
        fields = (
            'email',
            'username',
            'first_name',
            'last_name'
        )

views.py

class AgentUpdateView(OrganisorAndLoginRequiredMixin,generic.UpdateView):
    template_name = "agents/agent_update.html"
    form_class = AgentModelForm
    queryset = Agent.objects.all()
    def get_success_url(self):
        return reverse("agents:agent_list")

This is call Multi-table inheritance. Each model (User and Agent) corresponds to its own database table and can be queried and created individually. The inheritance relationship introduces links between the child model (Agent) and its parent (User) (via an automatically-created OneToOneField).

More information: https://docs.djangoproject.com/en/dev/topics/db/models/#multi-table-inheritance

CodePudding user response:

There is some confusion in your setup.

The AgentModelForm updates the User model

class AgentModelForm(forms.ModelForm):
    class Meta:
        model = User

So when your Update view calls its queryset Agent.objects.all() it can't find the appropriate model in it. So it can't prepopulate the fields.

Despite the view name, if you update the queryset to User.objects.all you might have better luck.

That said, LaCharcaSoftware's answer is probably a less confusing approach that will serve you better going forward.

  • Related