23๐
In case of using normal m2m relation (not through intermediary table) you could replace:
membership = Membership(member = HERE SELECTED ITEMS FROM FORM,classroom=new_obj)
membership.save()
with
form.save_m2m()
But in case of using intermediary tables you need to manually handle POST data and create Membership objects with all required fields (similar problem). The most basic solution is to change your view to something like:
def save_classroom(request):
if request.method == 'POST':
form = ClassroomForm(request.POST, request.FILES)
if form.is_valid():
new_obj = form.save(commit=False)
new_obj.user = request.user
new_obj.save()
for member_id in request.POST.getlist('members'):
membership = Membership.objects.create(member_id = int(member_id), classroom = new_obj)
return HttpResponseRedirect('/')
else:
form = ClassroomForm()
return render_to_response('save_classroom.html', locals())
Note how request.POST is manipulated (.getlist). This is because post and get are QueryDict objects which has some implications (request.POST[โmembersโ] will return always one object!).
You can modify this code to get it more reliable (error handling etc.), and more verbose, eg:
member = get_object_or_404(User, pk = member_id)
membership = Membership.objects.create(member = member , classroom = new_obj)
But note that you are performing some db queries in a loop which is not a good idea in general (in terms of performance).
5๐
Like what dzida did, but use form.cleaned_data instead of request.post:
def save_classroom(request):
if request.method == 'POST':
form = ClassroomForm(request.POST, request.FILES)
if form.is_valid():
new_obj = form.save(commit=False)
new_obj.user = request.user
new_obj.save()
for member in form.cleaned_data['members'].all():
Membership.objects.create(member = member, classroom = new_obj)
return HttpResponseRedirect('/')
else:
form = ClassroomForm()
return render_to_response('save_classroom.html', locals())
You also need to consider some memberships might be deleted, so:
def save_classroom(request):
if request.method == 'POST':
form = ClassroomForm(request.POST, request.FILES)
if form.is_valid():
new_obj = form.save(commit=False)
new_obj.user = request.user
new_obj.save()
final_members = form.cleaned_data['members'].all()
initial_members = form.initial['members'].all()
# create and save new members
for member in final_members:
if member not in initial_members:
Membership.objects.create(member = member, classroom = new_obj)
# delete old members that were removed from the form
for member in initial_members:
if member not in final_members:
Membership.objects.filter(member = member, classroom = new_obj).delete()
return HttpResponseRedirect('/')
else:
form = ClassroomForm()
return render_to_response('save_classroom.html', locals())
If you use model forms (like in a generic CBV: form_class=ClassroomForm
), override and put the saving logic above in the save
method, something like:
ClassroomForm(forms.ModelForm):
members = ModelMultipleChoiceField(
queryset=Classroom.objects.all(),
widget=SelectMultiple
)
def save(self, commit=True):
classroom = super().save(commit=False)
if commit:
classroom.save()
if 'members' in self.changed_data:
final_members = self.cleaned_data['members'].all()
initial_members = self.initial['members']
# create and save new members
for member in final_members:
if member not in initial_members:
Membership.objects.create(member = member, classroom = new_obj)
# delete old members that were removed from the form
for member in initial_members:
if member not in final_members:
Membership.objects.filter(member = member, classroom = new_obj).delete()
return classroom
- How to filter objects by ignoring upper and lower case letter django
- Django: Distinct foreign keys
- How can I compare two fields of a model in a query?
- Whole model as read-only
1๐
You also need to specify the classroom for the membership:
membership = Membership(member = request.user,
classroom=new_obj) #if new_obj if your classroom
membership.save()
I guess you should also remove User
in accept = models.BooleanField(User)
. It shouldnโt be necessary to set the date upon saving if you are using auto_now
! But maybe `auto_now_add is more likely what you need (http://docs.djangoproject.com/en/dev/ref/models/fields/#django.db.models.DateField)
0๐
This is how I did it in a generic UpdateForm class-based view (django 1.8) for a similar yet different application using the form_valid method.
def form_valid(self, form):
"""
If the form is valid, save the associated model.
"""
self.object.members.clear()
self.object = form.save(commit=False)
self.object.user = self.request.user
self.object.save()
list_of_members = form.cleaned_data['members']
ClassRoom.objects.bulk_create([
Membership(
Course=self.object,
member=member_person,
order=num)
for num, member_person in enumerate(list_of_members)
])
return super(ModelFormMixin, self).form_valid(form)
- Django admin inline many to many custom fields
- Django test database is not created with utf8
- Making Twitter, Tastypie, Django, XAuth and iOS work to Build Django-based Access Permissions
- How do I write a single-file Django application?