1

Firstly, I extend AbstractUser like this:

class MyProfile(AbstractUser):
    first_name = models.CharField(max_length=100)
    last_name = models.CharField(max_length=100)
    full_name = models.CharField(max_length=255)
    id_number = models.CharField(max_length=14)

    def __str__(self):
        return self.full_name

    def save(self, *args, **kwargs):
        self.full_name = '{0} {1}'.format(self.first_name, self.last_name)
        super().save(*args, **kwargs)

And then reference to other model like this:

class MyModel(models.Model):
    member = models.OneToOneField(MyProfile, on_delete=models.CASCADE)
    description = models.CharField(max_length=255)

    def __str__(self):
        return self.member

And this the form:

class MyModelForm(forms.ModelForm):
    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)

    class Meta:
        model = MyModel
        fields = ('description')

    full_name = forms.CharField(required=False, label="", widget=forms.TextInput(attrs={'class': "form-control"}))
    id_number = forms.CharField(required=False, label="", widget=forms.TextInput(attrs={'class': "form-control"}))
    description = forms.CharField(required=False, label="", widget=forms.TextInput(attrs={'class': "form-control"}))

And this is the view:

def applicationdata(request):
   if request.method == 'POST':
      form = MyModelForm(request.POST or None) 
      if form.is_valid():
         form.save()
      return HttpResponseRedirect('/index/')
      else:
         print(form.errors)
   else:
      form = MyModelForm()

   context = {
      'form': form,
   }
   return render(request, 'index.html', context)

My question is:

  • How to show full_name's field & id_number's field instead of member's field on MyModelForm?

  • And how to save that fields via applicationdata's views into member's field in MyModel's model?

UPDATE

  1. I updated the AbstractUser model because I forget to add first_name & last_name and I forget to mention if I use allauth
  2. I updated the form with init
panjianom
  • 236
  • 4
  • 18

3 Answers3

2

Instead of using ModelForm it's better to use Form here because certain we don't particularly use the field of models. Your forms.py should like this

class MyModelForm(forms.Form):

    full_name = forms.CharField(required=False, label="", widget=forms.TextInput(attrs={'class': "form-control"}))
    id_number = forms.CharField(required=False, label="", widget=forms.TextInput(attrs={'class': "form-control"}))
    description = forms.CharField(required=False, label="", widget=forms.TextInput(attrs={'class': "form-control"}))

while our views method should need to be totally tailored according to fields and data need to be stored. Change your views.py method to this

def applicationdata(request):
   if request.method == 'POST':
      form = MyModelForm(request.POST or None) 
      if form.is_valid():
          profile = MyProfile.object.create(full_name=request.POST['full_name'], id_number=request.POST['id_number'])
          if profile is not None:
              MyModel.object.create(description=request.POST['description'], member=profile.pk)
              return HttpResponseRedirect('/index/')
          else:
              form.add_error('profile_out_of_bound', "please try to fill correct details!")

      print(form.errors)
   else:
      form = MyModelForm()

   context = {
      'form': form,
   }
   return render(request, 'index.html', context)

Correct me if this doesn't work.

Dhruv Agarwal
  • 558
  • 6
  • 15
  • Thank you for your answer. I update my question. Actually I use ModelForm because I need to get existing users and fill with an additional field (description) and then save it into the user (OneToOne). And I tried your answer but I got an error: django.db.utils.IntegrityError: duplicate key value violates unique constraint "myprofile_member_username_key" DETAIL: Key (username)=() already exists. – panjianom Apr 27 '20 at 08:57
1

first you can remove first_name and last_name field because you can get it from full_name

class MyProfile(AbstractUser):
    full_name = models.CharField(max_length=255)
    id_number = models.CharField(max_length=14)

    def __str__(self) -> str:
        return self.full_name

    @property
    def first_name(self) -> str:
        return self.full_name.split(' ')[0]

    @property
    def last_name(self) -> str:
        if self.full_name.split(' ') > 1:
            return self.full_name.split(' ')[1]
        return ''

class MyModelForm(forms.ModelForm):

    full_name = forms.CharField(required=False, label="", widget=forms.TextInput(attrs={'class': "form-control"}))
    id_number = forms.CharField(required=False, label="", widget=forms.TextInput(attrs={'class': "form-control"}))

    class Meta:
        model = MyModel
        fields = ('description')

    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        self.fields['description'].widget = forms.TextInput(attrs={'class': "form-control"})

    def save(self, *args, **kwargs):
        kwargs['commit'] = False
        my_model = super().save(*args, **kwargs)
        MyProfile.objects.update_or_create(
            full_name=self.cleaned_data['full_name'],
            id_number=self.cleaned_data['id_number'],
            mymodel=my_model
        )


if the MyProfile object already exists, you can use it to fill in the form fields automatically with __init__

    def __init__(self, my_profile: MyProfile, *args, **kwargs):
        kwargs.update(initial={
            # 'field': 'value'
            'full_name': my_profile.full_name,
            'id_number': my_profile.id_number
        })
        super().__init__(*args, **kwargs)
        self.fields['description'].widget = forms.TextInput(attrs={'class': "form-control"})
Havel
  • 31
  • 3
1

How to show full_name's field & id_number's field instead of member's field on MyModelForm?

if you mean to show it to change it afterwards you have to override the __init__ method to set the initial data on the two fields: maybe this answer can help

And how to save that fields via applicationdata's views into member's field in MyModel's model?

entity = form.save() # this gives you the updated MyModel instance

then save the data from the form to the related model, something like:

 entity.member.full_name = form.cleaned_data['full_name']

should work according to: this answer

bb4L
  • 899
  • 5
  • 16