8

I'm having a bit of trouble grasping how to do this. I've put my best effort into searching Google without any luck.

I'll start with a bit of code and explain what I'm trying to do as I go:

models.py

class Action(models.Model):
    title = models.CharField(max_length=200)
    owner = models.ForeignKey(User, related_name='actions')
    created_by = models.ForeignKey(User, related_name='+', editable=False)
    modified_by = models.ForeignKey(User, related_name='+', editable=False)

class ActionForm(ModelForm):
    class Meta:
        model = Action

views.py

By default, there is a dropdown field for owner. I have an icon that allows the user to enter a new username in a text field instead for owner. I check to see if owner_new was submitted and if so, create that user. I then need to set the owner field to that value so that form.is_valid() will be true.

def action_create(request):
    if request.method == 'POST':
        form = ActionForm(request.POST)
        # check if new user should be created
        if 'owner_new' in request.POST:
            # check if user already exists
            user = User.objects.get(username=request.POST.get('owner_new'))
            if not user:
                user = User.objects.create_user(request.POST.get('owner_new'))
            # HERE IS WHERE I'M STUMPED
            form.owner = user.id
        if form.is_valid(): # THIS FAILS BECAUSE form.owner ISN'T SET
            action = form.save(commit=False)
            action.created_by = request.user
            action.modified_by = request.user
            action.save()
            return redirect('action_register:index')
    else:
        form = ActionForm()
    return render(request, 'actions/create.html', {'form': form})
Jared
  • 4,567
  • 2
  • 26
  • 30
  • May be worth a look at the accepted answer to [https://stackoverflow.com/questions/4517366](https://stackoverflow.com/questions/4517366/change-form-values-after-submit-button-pressed) – Martin CR Oct 08 '19 at 19:16

2 Answers2

7

You can try this:

def action_create(request):
    if request.method == 'POST':
        form = ActionForm(request.POST)
        # check if new user should be created
        if 'owner_new' in request.POST:
            # check if user already exists
            user, _ = User.objects.get_or_create(username=request.POST.get('owner_new'))                

            updated_data = request.POST.copy()
            updated_data.update({'owner': user}) 
            form = MyForm(data=updated_data) 

        if form.is_valid(): # THIS FAILS BECAUSE form.owner ISN'T SET
            action = form.save(commit=False)
            action.created_by = request.user
            action.modified_by = request.user
            action.save()
            return redirect('action_register:index')
    else:
        form = ActionForm()
    return render(request, 'actions/create.html', {'form': form})

A cleaner way of doing this is:

add required=False to the owner field. Now,

if form.is_valid(): # THIS DOES NOT FAIL EVEN IF form.owner ISN'T SET
    action = form.save(commit=False)
    if 'owner_new' in request.POST:
        user, _ = User.objects.get_or_create(username=request.POST.get('owner_new'))                
        action.owner = user
    action.created_by = request.user
    action.modified_by = request.user
    action.save()
    return redirect('action_register:index')
Anupam
  • 14,950
  • 19
  • 67
  • 94
karthikr
  • 97,368
  • 26
  • 197
  • 188
  • First, thanks for showing the `get_or_create()` function. I didn't know that existed. Second, I get an the error `This QueryDict instance is immutable` for `form.data['owner'] = user`, which is the problem I've been running into this whole time. Django just really doesn't want me messing with the values. – Jared Jun 25 '13 at 18:13
  • Yes it was, thank you very much for your help. One minor change is that `updated_data.update('owner', 'user')` must be called as `updated_data.update(owner=user)`. – Jared Jun 26 '13 at 13:50
1

I came into a similar situation and couldn't figure out how to do it the way I wanted. What I ended up with was putting a link to a UserForm which allows a user to create a new owner, and then redirect back to the ActionForm with the argument initial={owner: new_owner} included when instantiating the form.

Daniel Rosenthal
  • 1,386
  • 4
  • 15
  • 32