many to many field in django is working in admin site but not in front end site form
Question:
In my code CreateNoticeForm is working fine and all data gets saved perfectly except
many to many field which is tags in my notice model.Although it is working on admin site and gets saved.
here is my code
models.py
from django.db import models
from django.contrib.auth.models import User
from wysihtml5.fields import Wysihtml5TextField
# Create your models here.
class Tag(models.Model):
# For notice tags
name = models.CharField(max_length=70, unique=True)
def __str__(self):
return self.name
class Notice(models.Model):
# Notice Store
headline = models.CharField(max_length=140)
description = Wysihtml5TextField()
file_name = models.FileField(upload_to='static/noticefiles/', blank=True)
created_by = models.ForeignKey(User)
fors = models.CharField(max_length=1, choices=(('F','Faculty'),('S','Student'),) )
last_date = models.DateField()
tags = models.ManyToManyField(Tag, blank=True)
post_time = models.DateTimeField(auto_now_add=True)
update_time = models.DateTimeField(auto_now=True)
def __str__(self):
return self.headline
forms,py
FORS_CHOICES = (('F','Faculty'),('S','Student'))
class CreateNoticeForm(ModelForm):
fors = forms.ChoiceField(label="Related To",
choices=FORS_CHOICES,
)
class Meta:
model = Notice
fields = ('headline', 'description',
'fors', 'last_date', 'tags','file_name')
widgets = {
'description': Wysihtml5BootstrapWidget(),
'last_date': SelectDateWidget()
}
def __init__(self, *args, **kwargs):
super(CreateNoticeForm, self).__init__(*args, **kwargs)
self.helper = FormHelper()
self.helper.form_id = 'create_notice_form_id'
self.helper.form_class = 'form-horizontal'
self.helper.form_method = 'post'
self.helper.label_class = 'col-lg-2'
self.helper.field_class = 'col-lg-8'
self.helper.layout = Layout(
Fieldset('Create Notice',
'headline',
'description',
Field('fors', label='Audience'),
MultiWidgetField('last_date',
attrs=(
{'style': 'width: 33.33%; display: inline-block;'}
)
),
'tags',
'file_name',
FormActions(
Submit('save', 'Create Notice',
css_class='btn-warning col-lg-offset-2'),
),
),
views.py
def create_notice(request):
context = RequestContext(request)
posted = False
if request.method=='POST':
create_notice_form = CreateNoticeForm(data=request.POST, files=request.FILES)
if create_notice_form.is_valid():
cnf = create_notice_form.save(commit=False)
cnf.created_by = request.user
cnf.save()
posted = True
else:
print(create_notice_form.errors)
else:
create_notice_form = CreateNoticeForm()
return render_to_response('notices/createnotice1.html',
{'create_notice_form': create_notice_form,
'posted': posted,},
context)
Answers:
You have to call save_m2m()
:
cnf = create_notice_form.save(commit=False)
cnf.created_by = request.user
cnf.save()
create_notice_form.save_m2m()
Excerpt from the documentation:
If your model has a many-to-many relation and you specify commit=False
when you save a form, Django cannot immediately save the form data for the many-to-many relation. This is because it isn’t possible to save many-to-many data for an instance until the instance exists in the database.
To work around this problem, every time you save a form using commit=False
, Django adds a save_m2m()
method to your ModelForm
subclass. After you’ve manually saved the instance produced by the form, you can invoke save_m2m()
to save the many-to-many form data.
You have to Call the following after validating the form:-
if create_notice_form.is_valid():
parent = create_notice_form.save(commit=False)
parent.save()
create_notice_form.save_m2m()
I hope this will help you
In my code CreateNoticeForm is working fine and all data gets saved perfectly except
many to many field which is tags in my notice model.Although it is working on admin site and gets saved.
here is my code
models.py
from django.db import models
from django.contrib.auth.models import User
from wysihtml5.fields import Wysihtml5TextField
# Create your models here.
class Tag(models.Model):
# For notice tags
name = models.CharField(max_length=70, unique=True)
def __str__(self):
return self.name
class Notice(models.Model):
# Notice Store
headline = models.CharField(max_length=140)
description = Wysihtml5TextField()
file_name = models.FileField(upload_to='static/noticefiles/', blank=True)
created_by = models.ForeignKey(User)
fors = models.CharField(max_length=1, choices=(('F','Faculty'),('S','Student'),) )
last_date = models.DateField()
tags = models.ManyToManyField(Tag, blank=True)
post_time = models.DateTimeField(auto_now_add=True)
update_time = models.DateTimeField(auto_now=True)
def __str__(self):
return self.headline
forms,py
FORS_CHOICES = (('F','Faculty'),('S','Student'))
class CreateNoticeForm(ModelForm):
fors = forms.ChoiceField(label="Related To",
choices=FORS_CHOICES,
)
class Meta:
model = Notice
fields = ('headline', 'description',
'fors', 'last_date', 'tags','file_name')
widgets = {
'description': Wysihtml5BootstrapWidget(),
'last_date': SelectDateWidget()
}
def __init__(self, *args, **kwargs):
super(CreateNoticeForm, self).__init__(*args, **kwargs)
self.helper = FormHelper()
self.helper.form_id = 'create_notice_form_id'
self.helper.form_class = 'form-horizontal'
self.helper.form_method = 'post'
self.helper.label_class = 'col-lg-2'
self.helper.field_class = 'col-lg-8'
self.helper.layout = Layout(
Fieldset('Create Notice',
'headline',
'description',
Field('fors', label='Audience'),
MultiWidgetField('last_date',
attrs=(
{'style': 'width: 33.33%; display: inline-block;'}
)
),
'tags',
'file_name',
FormActions(
Submit('save', 'Create Notice',
css_class='btn-warning col-lg-offset-2'),
),
),
views.py
def create_notice(request):
context = RequestContext(request)
posted = False
if request.method=='POST':
create_notice_form = CreateNoticeForm(data=request.POST, files=request.FILES)
if create_notice_form.is_valid():
cnf = create_notice_form.save(commit=False)
cnf.created_by = request.user
cnf.save()
posted = True
else:
print(create_notice_form.errors)
else:
create_notice_form = CreateNoticeForm()
return render_to_response('notices/createnotice1.html',
{'create_notice_form': create_notice_form,
'posted': posted,},
context)
You have to call save_m2m()
:
cnf = create_notice_form.save(commit=False)
cnf.created_by = request.user
cnf.save()
create_notice_form.save_m2m()
Excerpt from the documentation:
If your model has a many-to-many relation and you specify
commit=False
when you save a form, Django cannot immediately save the form data for the many-to-many relation. This is because it isn’t possible to save many-to-many data for an instance until the instance exists in the database.To work around this problem, every time you save a form using
commit=False
, Django adds asave_m2m()
method to yourModelForm
subclass. After you’ve manually saved the instance produced by the form, you can invokesave_m2m()
to save the many-to-many form data.
You have to Call the following after validating the form:-
if create_notice_form.is_valid():
parent = create_notice_form.save(commit=False)
parent.save()
create_notice_form.save_m2m()
I hope this will help you