Search code examples
pythondjangoformsfielduserform

Adding manager in django form


I want to create user from extended Profile model , its done using api request , but from form it is not working . In api request body I am passing three fields only name,email,and phone_number, so that password is making through random automatically.

class ProfileManager(model.Manager):

    def create(self, email,phone_number, **kwargs):
        password=str(random.random())[2:8]
        user = User(username=phone_number)
        user.set_password(password)
        user.save()

        profile = Profile(
            user=user,
            email=email,
            **kwargs
        )
        profile.save()

if am using form like

class CustomerCreateForm(forms.ModelForm):
    name =forms.CharField(label='Name', max_length=32)
    phone_number = forms.CharField(label='Name', max_length=32)

    class Meta:
        model=Profile
        fields=['email','name','phone_number']

this ,it making error like user (1048, "Column 'user_id' cannot be null") because my profile model look like

class Profile(models.model):
    user = models.OneToOneField(User, on_delete=models.CASCADE)
    name = models.CharField(max_length=50)
    email = models.CharField(max_length=50,null=True, blank=True)
    phone_number = models.CharField(max_length= 15, null=True, blank=True)

So from here i understood that ProfileManager is not dependent with form, so i need to make def validate(self,attrs) like function and differet manger for form , but i don't know how to do this due to newbie. Any help is appreciated


Solution

  • The solution would depend on how you are using your form... I see two solutions:

    Don't commit when saving form

    If you set the commit argument of the form save method to False, the model object will have its attribute updated according but not saved in the database. This allows you to further work on it before persisting the changes.

    For example, in a CreateView, you would override the form_valid method if your are using Class Based View:

    def form_valid(self, form):
        obj = form.save(commit=False)  # obj.save() not called by the form
        obj.user = self.request.user  # or other user source
        obj.save()  #  model instance saved in db with validated constraints
    
        return HttpResponseRedirect(self.get_success_url())
    

    If using function views, the idea is the same:

    def my_view(request):
        # Omitting HTTP method check for simplicity
        my_form = Form(data=request.Post)
    
        if my_form.is_valid():
            obj = form.save(commit=False)
            obj.user = self.request.user
            obj.save()
    
            return HttpResponseRedirect(self.get_success_url())
    
    # template stuff goes here
    

    Pass the missing values in the form

    This is not as clean as the first one... You override the constructor and save method of your form to add the missing fields value:

    class MyForm(forms.ModelForm): # Meta here

    def __init__(self, user, **kwargs):
        self.user = user
        super().__init__(**kwargs)
    
    def save(self, commit=True):
        # add missing fields
        self.instance.user = self.user
        # and proceed with normal form flow
        return super().save(commit)