Reputation: 341
My app is project management tool where users can add, edit, and view Projects. Projects have titles, summaries, and authors (users). Users have ManyToMany relationships with Projects.
Adding new Projects was working fine until I added an edit project view. I can still create a new Project or edit an existing one, and the new title and summary get saved to the database, but the selected authors do not get saved. Note that I can still go into the shell and add authors to a project manually.
Here are the Project and User models:
class MyUser(AbstractBaseUser):
id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False)
bank_id = models.CharField("researcher's four-letter bank id", null=True, max_length=4, unique=True)
#division = models.CharField(max_length=30, blank = True)
department = models.CharField(max_length=3, choices=DEPARTMENTS)
job_title = models.CharField("job title", max_length=30, choices=JOB_TITLES)
citations = models.IntegerField(null=True, blank=True)
institution = models.CharField(max_length=30, choices=DEPARTMENTS, blank=True)
created_on = models.DateTimeField(auto_now_add=True)
updated_on = models.DateTimeField(auto_now=True)
#history = HistoricalRecords()
REQUIRED_FIELDS = ['email']
USERNAME_FIELD = 'username'
class Project(models.Model):
title = models.TextField('Title')
summary = models.TextField('Summary', default=DEFAULT_TEXT)
authors = models.ManyToManyField(MyUser)
internal_status = models.CharField('Internal Status', max_length = 20, choices = INTERNAL_STATUS,
default='wip')
external_status = models.CharField('External Status', max_length = 20, choices = EXTERNAL_STATUS,
blank=True)
mtp_goal = models.CharField(max_length = 50, choices = MTP_GOALS,
blank=True)
topics = ArrayField(models.CharField('Topics', max_length=30), size=4, null=True)
created_on = models.DateTimeField(auto_now_add=True, null=True)
updated_on = models.DateTimeField(auto_now=True, null=True)
history = HistoricalRecords()
views.py
def add_new(request):
if request.method == 'POST':
form = ProjectForm(request.POST)
if form.is_valid():
project = form.save(commit=False)
project.created_on = timezone.now()
project.save()
return redirect('project_profile', pk=project.pk)
else:
form = ProjectForm()
return render(request, 'add_new.html', {'form': form})
def edit_project(request, pk):
project = get_object_or_404(Project, pk=pk)
if request.method == 'POST':
form = ProjectForm(request.POST, instance=project)
if form.is_valid():
project = form.save(commit=False)
project.updated_on = timezone.now()
project.save()
return redirect('project_profile', pk=project.pk)
else:
form = ProjectForm(instance=project)
return render(request, 'edit_project.html', {'form': form})
forms.py:
from django import forms
from .models import Project, MyUser
class ProjectForm(forms.ModelForm):
class Meta:
model = Project
fields = ('title', 'authors', 'summary')
And finally, the add_project.html page (please excuse the horrific html):
<html>
<head>
<title>ResearchTracker</title>
</head>
<body>
<div>
<nav>
<a href="/about">About us</a>
<a href="/login">Login</a>
<a href="/admin">Admin</a>
</nav>
</div>
<h1>New project</h1><br>
<form method="POST" class="post-form">{% csrf_token %}
{{ form.as_p }}
<button type="submit" class="save btn btn-default">Save</button>
</form>
<a href="/">Go home</a>
</body>
</html>
Upvotes: 1
Views: 215
Reputation: 99620
Since you use commit=False
in save
, you need to explicitly call save_m2m
to save the many to many fields.
From the documentation:
Calling save_m2m() is only required if you use save(commit=False). When you use a simple save() on a form, all data – including many-to-many data – is saved without the need for any additional method calls. For example:
You would do
project.save()
project.save_m2m()
Upvotes: 4