Search code examples
django-formsforeign-keys

Auto filling a form's foreign key


So, i have been having problems filling in the user in a form. My strategy has been validating the form, creating an object, passing the foreign key and the other fields with .cleaned_data and saving the object. More specifically, I basically want to create a "workout" object in the database, adding a name and a description from the form and autofilling the created_by_user field.

views.py

@login_required(login_url='login')
def workouts(request, user_id):
    context = {}
    if request.method == 'POST':
        form = WorkoutForm(request.POST)
        if form.is_valid():
            name = form.cleaned_data['name']
            description = form.cleaned_data['description']

            Workout.objects.create(
            created_by_user=request.user, name=name, description=description)

            context = {'name': name, 'description': description}

        return render(request, 'Trainmate/fill_workout_with_sets.html', context)

    else:
        form = WorkoutForm()
        workout_programs = Workout.objects.all()
        user_workouts = workout_programs.filter(created_by_user=user_id)
        context = {'user_workouts': user_workouts, 'form': form}
        return render(request, 'Trainmate/workouts.html', context) 

models.py (I am just adding the workout model)

class Workout(models.Model):
    name = models.CharField(max_length=150, null=True)
    created_by_user = models.ForeignKey(User, null=True, on_delete=models.RESTRICT)
    description = models.TextField(max_length=1000, null=True)

    def __str__(self):
        return self.name 

forms.py

class WorkoutForm(forms.ModelForm):
    class Meta:
        model = Workout
        fields = ['name', 'description', 'created_by_user']

my template

{% extends 'Trainmate/main.html' %}

{% block content %}
<h1>My Workouts</h1>

<div>
    {% for workout in user_workouts %}
        {{ workout.name }}<br>
    {% endfor %}
</div>

<h1>Create new Workout</h1>
<form method="POST" action="">
    {% csrf_token %}
    {{ form.name }}
    {{ form.description }}
    <input type="submit" value="Create Workout">
</form>

Solution

  • You can remove 'created_by_user' from the fields list in your form as you do not need it to display or validating. Then render the form just with {{ form }}. You can use save() method since you use a ModelForm. Change your view accordignly:

    @login_required(login_url='login')
    def workouts(request, user_id):
        context = {}
        if request.method == 'POST':
            form = WorkoutForm(request.POST)
            if form.is_valid():
                workout = form.save(commit=False)
                workout.created_by_user = request.user
                workout.save()
            
                context = {'name': name, 'description': description}
            return render(request, 'Trainmate/fill_workout_with_sets.html', context)
    
        else:
            form = WorkoutForm()
            workout_programs = Workout.objects.all()
            user_workouts = workout_programs.filter(created_by_user=user_id)
            context = {'user_workouts': user_workouts, 'form': form}
            return render(request, 'Trainmate/workouts.html', context)