Django自动设置表单提交用户为模型外键字段的报错与实现需求
Hey there! Let's fix that save() missing required positional argument 'self' error while automatically assigning the current user to your model's foreign key field. I'll walk you through a solid, working example step by step—no fancy tricks, just straightforward Django practices.
Let's start with a simple model that has a user foreign key (linked to Django's built-in User model) and some other fields. This is our base:
# models.py from django.db import models from django.contrib.auth.models import User class Post(models.Model): user = models.ForeignKey(User, on_delete=models.CASCADE) title = models.CharField(max_length=200) content = models.TextField() def __str__(self): return self.title
We don't want the user to manually select their own account, so we'll exclude the user field from our form. Django will handle setting it automatically:
# forms.py from django import forms from .models import Post class PostForm(forms.ModelForm): class Meta: model = Post fields = ['title', 'content'] # Only include fields users need to fill out
I'll show you two common, error-free ways to assign the user. Pick whichever fits your workflow better.
Approach 1: Set the User Directly in the View (Most Straightforward)
This method uses commit=False to create a model instance without saving it to the database first. We can then add the user before saving:
# views.py from django.shortcuts import render, redirect from .forms import PostForm from django.contrib.auth.decorators import login_required @login_required # Make sure only logged-in users can submit the form def create_post(request): if request.method == 'POST': form = PostForm(request.POST) if form.is_valid(): # Create the Post instance but don't save to DB yet post = form.save(commit=False) # Assign the current logged-in user post.user = request.user # Now save the complete instance to the database post.save() return redirect('post_list') # Replace with your desired redirect URL else: form = PostForm() return render(request, 'create_post.html', {'form': form})
Approach 2: Override the Form's Save Method
If you prefer to keep view logic clean, you can move the user assignment into the form itself by overriding the save() method:
First, update your form:
# forms.py (updated) from django import forms from .models import Post class PostForm(forms.ModelForm): class Meta: model = Post fields = ['title', 'content'] # Override save to accept a user parameter def save(self, user, commit=True): # Get the unsaved instance from the parent save method instance = super().save(commit=False) # Assign the user instance.user = user # Save to DB if commit is True if commit: instance.save() return instance
Then update your view to pass the user to the form's save method:
# views.py (updated for Approach 2) from django.shortcuts import render, redirect from .forms import PostForm from django.contrib.auth.decorators import login_required @login_required def create_post(request): if request.method == 'POST': form = PostForm(request.POST) if form.is_valid(): # Pass the current user to our custom save method form.save(user=request.user) return redirect('post_list') else: form = PostForm() return render(request, 'create_post.html', {'form': form})
Chances are you tried calling the save method directly on the model class instead of an instance. For example:
# ❌ Wrong! This will throw the error because save() is an instance method if form.is_valid(): Post.save(user=request.user)
You need to create an instance first (like we did with form.save(commit=False)) before calling save().
Here's a quick template to render the form (save this as create_post.html):
<form method="POST"> {% csrf_token %} {{ form.as_p }} <button type="submit">Submit Post</button> </form>
内容的提问来源于stack exchange,提问作者Derrick Sherrill

