when creating a new recipe post, I use two formsets for ingredients and directions. however, the new post formsets are being populated by existing ingredient and direction objects when they should be empty. here is my view for the new post and the forms:
def post_new(request):
form = PostForm()
ingredient_form = IngredientFormSet(prefix='ingredient_form')
direction_form = DirectionFormSet(prefix='ingredient_form')
if request.method == "POST":
form = PostForm(request.POST, request.FILES)
ingredient_form = IngredientFormSet(request.POST, prefix='ingredient_form')
direction_form = DirectionFormSet(request.POST, prefix='direction_form')
if form.is_valid():
post = form.save(commit=False)
post.author = request.user
post.published_date = timezone.now()
post.save()
if ingredient_form.is_valid():
for i_form in ingredient_form:
if i_form.is_valid() and i_form.has_changed():
i_form.instance.recipe = post
i_form.save()
if direction_form.is_valid():
for d_form in direction_form:
if d_form.is_valid() and d_form.has_changed():
d_form.instance.recipe = post
d_form.save()
return redirect('post_detail', pk=post.pk)
return render(request, 'blog/post_edit.html', {'form': form, 'ingredient_form': ingredient_form, 'direction_form': direction_form})
class PostForm(forms.ModelForm):
class Meta:
model = Post
fields = ['title', 'image', 'text', 'prep_time', 'cook_time', 'servings_first', 'servings_second', 'tags']
IngredientFormSet = modelformset_factory(Ingredient, fields=['name',
'int_amount',
'float_amount',
'measurement'
], extra=15)
DirectionFormSet = modelformset_factory(Direction, fields=['text',
'order'
], extra=25)
Not sure why it is needed, but setting each formsets query to "None" solved the problem:
def post_new(request):
form = PostForm()
ingredient_form = IngredientFormSet(queryset=Ingredient.objects.none(), prefix='ingredient_form')
direction_form = DirectionFormSet(queryset=Direction.objects.none(), prefix='ingredient_form')
Related
I have the following view code
def edit_pal(request,pal_id):
pals=palabout.objects.get(id=pal_id)
form2=editpalForm(request.POST or None,instance=pals)
RecipeIngredientFormset = modelformset_factory(palabout, form=editspalForm,extra=0)
formset = RecipeIngredientFormset(request.POST or None,prefix=pals)
context={
"formset": formset,
"form2":form2,
"pals":pals
}
if request.method == 'POST':
if form2.is_valid() and formset.is_valid():
parent = form2.save(commit=False)
parent.save()
for form in formset:
child = form.save(commit=False)
child.recipe = parent
child.save()
context['message']='Data Saved'
return redirect('hod:manage_pal')
return render(request,"edit-pal.html",context)
I remove formset.is_validso it's working but it's not working when i added more for used formset.is_validso why isn't saving file or details show? Can anyone help this?
I think you need to only redirect if the forms are valid so try this view:
from django.shortcuts import get_object_or_404
def edit_pal(request,pal_id):
pals=get_object_or_404(palabout,id=pal_id)
if request.method == 'POST':
form2=editpalForm(request.POST,instance=pals)
RecipeIngredientFormset = modelformset_factory(palabout, form=editspalForm,extra=0)
formset = RecipeIngredientFormset(request.POST,prefix=pals)
if form2.is_valid() and formset.is_valid():
parent = form2.save(commit=False)
parent.save()
for form in formset:
child = form.save(commit=False)
child.recipe = parent
child.save()
context['message']='Data Saved'
return redirect('hod:manage_pal')
else: # if the form is not valid
return redirect("hod:some_error_page")
else: # GET request
RecipeIngredientFormset = modelformset_factory(palabout, form=editspalForm,extra=0)
formset = RecipeIngredientFormset(prefix=pals)
context={
"formset": formset,
"form2":editpalForm(instance=pals),
"pals":pals
}
return render(request,"edit-pal.html",context)
I'm creating an update view using django-form for updating one of my objects that have the following fields:
class Object(models.Model):
name = models.CharField(max_length=40)
logo = models.ImageField(upload_to='object_logo/')
text_1 = models.TextField()
text_2 = models.TextField()
So, i have created the following form in forms.py:
class ObjectForm(forms.ModelForm):
class Meta:
model = Object
fields = [
'name',
'logo',
'text_1',
'text_2',
]
labels = {
'name': 'Name',
'logo': 'Logo',
'text_1': 'Text 1',
'text_2': 'Text 2',
}
and defined the following view called update_object:
def update_object(request, value):
object = get_object_or_404(Object, pk=value)
if request.method == "POST":
form = ObjectForm(request.POST, request.FILES)
if form.is_valid():
object.name = form.cleaned_data['name']
object.logo = form.cleaned_data['logo']
object.text_1 = form.cleaned_data['text_1']
object.text_2 = form.cleaned_data['text_2']
object.save()
return HttpResponseRedirect(reverse('myApp:detail_object', args=(value, )))
else:
form = ObjectForm(
initial={
'name': object.name,
'logo': object.logo,
'text_1': object.text_1,
'text_2': object.text_2,
}
)
context = {'object': object, 'form': form}
return render(request, 'myApp/update_object.html', context)
My problem is: even with an "initial" value stetted up for logo, i have to select an image every time i will update my object (otherwise i receive the update_object page with the message "This field is required").
Is there a way to make the current object.logo as the pre-defined value of the input in my ObjectForm in the update_object view?
I've already tried to set blank = True in the logo model field (which was a bad idea). I also thought in make an alternative conditional code for form.is_valid() but i dont know how to do it.
Update your forms.py like so:
class ObjectForm(forms.ModelForm):
class Meta:
model = Object
fields = '__all__'
...and views.py:
def update_object(request, value):
object = get_object_or_404(Object, pk=value)
if request.method == "POST":
form = ObjectForm(request.POST, request.FILES, instance=object)
if form.is_valid():
form.save()
return HttpResponseRedirect(reverse('myApp:detail_object', args=(value, )))
else:
form = ObjectForm(instance=object)
context = {'object': object, 'form': form}
return render(request, 'myApp/update_object.html', context)
It can be done like this (more clean)
In case share your template code
I am trying to add data in a model using django forms but getting
Direct assignment to the forward side of a many-to-many set is prohibited. Use tag.set() instead.
Please help me solve this. I am using multiselect field to send data to views.py.
models.py
class Tags(models.Model):
tag = models.CharField(max_length=100)
def __str__(self):
return self.tag
class Meta:
verbose_name_plural = 'Tags'
class Post(models.Model):
...
author = models.ForeignKey(User, verbose_name='Author', on_delete=models.CASCADE)
feature_image = models.ImageField(upload_to='blog/', verbose_name='Add Feature Image')
tag = models.ManyToManyField(Tags, related_name='post_tags', verbose_name='Add Tags')
def __str__(self):
return self.title
forms.py
class PostForm(forms.ModelForm):
...
class Meta:
model = models.Post
fields = [...]
views
def adminNewPostView(request):
form = forms.PostForm()
if request.method == 'POST':
...
tags = request.POST.getlist('tagName')
form = forms.PostForm(request.POST, request.FILES)
if form.is_valid():
post = form.save(commit=False)
post.author = request.user
post.category = cat
if subcat:
post.sub_categories = subcat
if subfil:
post.filter_option = subfil
add_tags = models.Tags.objects.filter(tag__in=tags)
for tl in add_tags:
post.tag = tl # Getting Error here
post.save()
return HttpResponseRedirect(reverse('blog_app:index'))
Error
Direct assignment to the forward side of a many-to-many set is prohibited. Use tag.set() instead.
views.py
def adminNewPostView(request):
form = forms.PostForm()
if request.method == 'POST':
...
tags = request.POST.getlist('tagName')
form = forms.PostForm(request.POST, request.FILES)
if form.is_valid():
post = form.save(commit=False)
post.author = request.user
post.category = cat
if subcat:
post.sub_categories = subcat
if subfil:
post.filter_option = subfil
post.save()
add_tags = models.Tags.objects.filter(tag__in=tags)
for tl in add_tags:
post.tag.add(tl) # new
return HttpResponseRedirect(reverse('blog_app:index'))
to learn more about this please refer to https://docs.djangoproject.com/en/dev/ref/models/relations/ or here https://docs.djangoproject.com/en/2.2/topics/db/examples/many_to_many/#many-to-many-relationships
there is also an other way of doing it.like this
def adminNewPostView(request):
form = forms.PostForm()
if request.method == 'POST':
...
tags = request.POST.getlist('tagName')
form = forms.PostForm(request.POST, request.FILES)
if form.is_valid():
post = form.save(commit=False)
post.author = request.user
post.category = cat
if subcat:
post.sub_categories = subcat
if subfil:
post.filter_option = subfil
post.save()
add_tags = models.Tags.objects.filter(tag__in=tags)
post.tag.add(*add_tags) # new
return HttpResponseRedirect(reverse('blog_app:index'))
A Django form can handle ManyToManyFields itself, but can only do that with .save_m2m() or .save() without using commit=False: first it needs to save the Post object since it needs the primary key of that Post object to link the object to other items.
If your PostForm uses the tag field:
class PostForm(forms.ModelForm):
…
class Meta:
model = models.Post
# ↓ tag field
fields = ['tag', 'other', 'fields']
then we can let the form do the work for us:
from django.shortcuts import redirect
def adminNewPostView(request):
form = forms.PostForm()
if request.method == 'POST':
…
tags = request.POST.getlist('tagName')
form = forms.PostForm(request.POST, request.FILES)
if form.is_valid():
if subcat:
form.instance.sub_categories = subcat
if subfil:
form.instance.filter_option = subfil
form.instance.author = request.user
form.instance.category = cat
form.save()
return redirect('blog_app:index')
i have custom fields in ModelForm and there is no any values on save. im just confuse what to use in view.py to save with data
form.py
class AddCityForm(forms.ModelForm):
duration = forms.ChoiceField(widget=forms.RadioSelect(attrs={
'style': 'background-color: #FAF9F9', 'class': 'mb-3, form-check-inline'}), choices=DURATION_CHOICES)
country = forms.ChoiceField(widget=forms.RadioSelect(attrs={
'style': 'background-color: #FAF9F9', 'class': 'mb-3, form-check-inline'}), choices=CITY_CHOICE)
something = forms.CharField(widget=forms.TextInput(attrs={
'style': 'background-color: #FAF9F9', 'class': 'mb-3'}))
class Meta:
model = Cities
exclude = ['city', 'duration', 'something']
view.py
def add_city(request):
data = dict()
if request.method == 'POST':
form = AddCityForm(request.POST)
if form.is_valid():
form = form.save(commit=False)
form.city = request.POST.get('country')
form.duration = request.POST.get('dur')
form.something = request.POST.get('something')
form = form.save()
messages.success(request, f'Test for Added Successfully')
data['form_is_valid'] = True
else:
data['form_is_valid'] = False
else:
form = AddCityForm()
context = dict(form=form)
data['html_form'] = render_to_string('cites/modal_1.html', context, request=request)
return JsonResponse(data)
can any one help with this ?
Looks like the code is working, i have no idea why did not before i asked this question but i will keep this if any one look for similar question
I'm a Python/Django newbie and have been facing the following problem for several days now. I've got 2 ModelForms for a Model and the idea is that the data for one will help populate the multiplechoicefield of the second. The multiplechoice field for the second form populates ok but the problem is that the user's choices don't get saved. I've tried the save(commit=false) and save_m2m() but it hasn't fixed the issue.
models.py:
class Question(models.Model):
asker = models.ForeignKey(Student, related_name='asker+')
suggestedHelpers = models.ManyToManyField(Student, related_name='suggested')
chosenHelpers = models.ManyToManyField(Student, related_name='chosen')
class QuestionForm(ModelForm):
class Meta:
model = Question
exclude = ('chosenHelpers','suggestedHelpers', 'asker',)
class HelpersForm(ModelForm):
def suggesthelpers(self, question):
# populate chosenHelpers field according to data from QuestionForm
class Meta:
model = Question
exclude = ('suggestedHelpers', 'asker', 'questionSubj', 'Qtext',)
views.py
def askq_page(request):
question = Question(asker=Student.objects.get(user=request.user))
if request.method == 'POST':
form = QuestionForm(request.POST, instance=question)
if form.is_valid():
question = form.save()
# process data
question.save()
form2 = HelpersForm(instance=question)
form2.suggesthelpers(question)
variables = {'form':form2, 'qid':question.id}
return render_to_response('choosehelper.html', variables,context_instance=RequestContext(request))
else:
variables = RequestContext(request, {'form': QuestionForm()})
return render_to_response('askq.html', RequestContext(request, {'form': QuestionForm(instance=question)}))
def choosehelper_page(request, form='', qid=''):
question = Question.objects.get(id=qid)
if request.method == 'POST':
form2 = HelpersForm(request, instance=question)
# here lies the problem- the data gathered from form2 is not saved i.e. the multiple choices chosen by user are not returned
if form2.is_valid():
question = form2.save()
form2.save_m2m()
helpers = question.chosenHelpers.all()
for helper in helpers:
sentQ = ReceivedQ(question=question)
sentQ.student = helper
sentQ.save()
return render_to_response('questionsent.html', {'helpers': helpers, 'qid': question.id, 'qtext': q}, context_instance=RequestContext(request))
else:
form2 = HelpersForm(instance=question)
form2.suggesthelpers(question)
return render_to_response('choosehelper.html', RequestContext(request, {'form': form2, 'qid': qid}))