ok i am following the formset. Pretty much i understand that formset is for multiple form.
so this example i just want take four values same time but the ouput in html have only one form is showing.
Shall i want to make extra filed like this <input id="your_name" type="text" name="your_name"> or django will do the rest or any other way to do that.?
models.py
class Article(models.Model):
title = models.CharField(max_length=100)
pub_date = models.DateField(auto_now_add=True)
forms.py
class ArticleForm(forms.Form):
title = forms.CharField()
#pub_date = forms.DateField()
ArticleFormSet = formset_factory(ArticleForm, extra=4, validate_max=True)
views.py
def book(request):
if request.method == 'POST':
formset = ArticleForm(request.POST)
if formset.is_valid():
new = Article()
new.title = request.POST.get('title', None)
#new.pub_date = request.POST.get('pub_date', None)
new.save()
return HttpResponseRedirect(reverse('firstapp.views.book'))
else:
formset = ArticleForm()
return render_to_response('get.html',{'formset': formset}, context_instance = RequestContext(request))
And the html look like this
<form method="post" action="">
{% csrf_token %}
{{ formset.management_form }}
<table>
{% for form in formset %}
{{ form }}
{% endfor %}
</table>
<input type="submit"/>
</form>
In your view you are binding formset to an ArticleForm, not to an ArticleFormSet. Also you are only creating one single Article from it, and you're not even using the form properly (ie: you're getting the title directly from request.POST instead of getting it from your form's cleaned_data). Your view code should look something like this (caveat: untested and possibly buggy code, but at least you'll get the picture).
def book(request):
if request.method == 'POST':
formset = ArticleFormSet(request.POST)
if formset.is_valid():
for data in formset.cleaned_data:
Article.objects.create(title=data['title'])
return HttpResponseRedirect(reverse('firstapp.views.book'))
else:
formset = ArticleFormSet()
return render_to_response('get.html',{'formset': formset},
context_instance = RequestContext(request))
As a last point, I strongly suggest you have a look at ModelForms.
Related
I have a problem, the urls form works but I can't see the records in url/admin, can I ask for help, thank you :D
SOF wants me to add more details otherwise it doesn't transfer, I don't know what more I can add, generally temapals and urls work.
class Note(models.Model):
"""..."""
notes = models.CharField(max_length=100, unique=True)
description = models.TextField()
class Meta:
verbose_name = "Note"
verbose_name_plural = "Notes"
def __str__(self):
return self.notes
class NoteView(View):
def get(self, request):
if request.method == 'POST':
textN = Note.objects.all().order_by('notes')
form = NoteAddForm(request.POST)
if form.is_valid():
form.save()
return redirect('Files/menu')
else:
textN = NoteAddForm()
return render(request, 'Files/note.html', {'textN': textN})
class NoteAddForm(forms.ModelForm):
"""New note add form"""
class Meta:
model = Note
fields = '__all__'
{% extends 'Files/base.html' %}
{% block title %}Notatnik{% endblock %}
<h2>Notatnik Dietetyka/ Zalecenia ręczne </h2>
{% block content %}
<form action="/send/" method="post">
{% csrf_token %}
{{ textN }}
<label>
<input type="text" class="btn btn-second btn-lg">
<button>Wyślij formularz</button>
</label>
</form>
<button type="button" class="btn btn-primary btn-lg">Powrót</button>
{% endblock %}
Within your NoteView class in views.py file is where the issue is.
I see you have an if statement checking for if request.method == 'POST' within the class-based view get(). The get() is equivalent to if request.method == 'GET'. Therefore, what you might want to do is to override the post() on the class instead. For example:
class NoteView(View):
template_name = 'Files/note.html'
# Use the get method to pass the form to the template
def get(self, request, *arg, **kwargs):
textN = NoteAddForm()
return render(request, self.template_name, {'textN': textN})
# Use the post method to handle the form submission
def post(self, request, *arg, **kwargs):
# textN = Note.objects.all().order_by('notes') -> Not sure why you have this here...
form = NoteAddForm(request.POST)
if form.is_valid():
form.save()
# if the path is... i.e: path('success/', SucessView.as_view(), name='success')
return redirect('success') # Redirect upon submission
else:
print(form.errors) # To see the field(s) preventing the form from being submitted
# Passing back the form to the template in the name 'textN'
return render(request, self.template_name, {'textN': form})
Ideally, that should fix the issue you're having.
Updates
On the form, what I'd suggest having is...
# Assuming that this view handles both the get and post request
<form method="POST"> # Therefore, removing the action attribute from the form
{% csrf_token %}
{{ textN }}
# You need to set the type as "submit", this will create a submit button to submit the form
<input type="submit" class="btn btn-second btn-lg" value="Submit">
</form>
I'm using formsets to pass several modelforms with existing model instances to a template. I'd like to do something in the template for each form depending on the value of a model field (let's call it field_check) for that instance. Field_check is not intended for user input and a required field.
If I include field_check into my form without rendering it, I can easily access its value. But then after submitting the form Django complains that field_check is required.
What is the recommended way to access the value of field_check without including it as an input field or running into the required field problem?
Models.py
class MyModel(models.Model):
field_check = models.CharField(max_length=50)
user_input_field = models.CharField(max_length=50)
some_type = models.CharField(max_length=50)
Forms.py
class MyModelForm(forms.ModelForm):
class Meta:
model = MyModel
fields = [
'user_input_field',
'field_check', #having this field here creates problems, since it's not intended for user input
]
MyFormSet = forms.modelformset_factory(MyModel, form = MyModelForm, extra=0)
Views.py
def myview(request):
this_type = 1
formset = MyFormSet(request.POST or None, queryset = MyModel.objects.filter(some_type = this_type))
if request.method == 'POST':
if formset.is_valid():
formset.save()
return render(request, 'some_other_template.html')
context = {'formset':formset}
return render(request, 'mytemplate.html', context)
Template
<form method="post">
{{ formset.management_form }}
{% for form in formset %}
{{form.id}
# here is the part where I check for the value of field_check
{% if form.field_check == 'Some value' %}
Some text
{% else %}
Some other text
{% endif %}
{{form.user_input_field}}
{% endfor %}
<button type="submit">
</form>
Sorry the title isn't very descriptive. The context: I have an event full of participants. When the event is over I want to leave feedback for all of the other participants.
models.py
class Feedback(models.Model):
action = models.ForeignKey(Action)
feedback_by = models.ForeignKey(UserProfile, related_name='feedback_by')
feedback_for = models.ForeignKey(UserProfile, related_name='feedback_for')
comment = models.CharField(max_length=200)
no_show = models.BooleanField()
created = models.DateTimeField()
modified = models.DateTimeField()
forms.py
class FeedbackFormSet(BaseModelFormSet):
def add_fields(self, form, index):
super(FeedbackFormSet, self).add_fields(form, index)
form.fields['is_checked'] = forms.BooleanField(required=False)
class FeedbackForm(forms.ModelForm):
comment = forms.CharField(label=(u"Comment"), widget=forms.Textarea())
class Meta:
model = Feedback
fields = ['comment', 'no_show']
I want to create a feedback page, where there would be one instance of the FeedbackForm for each participant. After some searching it seems that to do that I want to be using a FormSet, but I'm not finding the documentation for it very helpful and I can't seem to find any good examples.
If a formset is the way to go, could you guys help me out with some (view/formset basically) starter code? If not, can you point me to what I should be doing? Thanks.
EDIT: I've added my view and template code below.
views.py
#login_required
def new_feedback(request, action_id):
action = get_object_or_404(Action, id=action_id)
profile = UserProfile.objects.get(user_id=request.user.id)
participants = all_info_many_profiles(action.participants.filter(~Q(id=profile.id)))
fbformset = modelformset_factory(Feedback, form=FeedbackForm, formset=FeedbackFormSet)
if request.method == 'POST':
formset = fbformset(request.POST, request.FILES, queryset=action.participants.filter(~Q(id=profile.id)))
if formset.is_valid():
formset.save()
else:
print formset.errors
else:
formset = fbformset(queryset=action.participants.filter(~Q(id=profile.id)))
return render(request, 'app/new_feedback.html',
{'action': action, 'participants': participants, 'formset': formset}
new_feedback.html
{% block body_block %}
<h1>Leave Feedback</h1>
{% for participant in participants %}
<li>{{ participant.username }}</li>
{% endfor %}
<form method="post" action="">
{% csrf_token %}
{{ formset.management_form }}
{% for form in formset %}
{{ form.as_p }} <br />
{% endfor %}
<input type="submit" name="submit" value="Submit Feedback" />
</form>
{% endblock %}
What I'm trying to achieve is to associate one form to each user in the list (or queryset) of participants. What I currently have shows one more form than I want (for example, when I list each user I'll see 3 names but 4 forms example) and I don't know if or how the users/forms are related.
The idea is that the feedback_for field will get its value automatically, ie in the view I would do:
if formset.is_valid():
for form in formset:
a = form.save(commit=false)
a.feedback = participant
a.save()
On top of that, I added an extra field "is_checked" which is intended to specify whether I'm leaving feedback for that user or not. Example of full functionality:
user1 [X] is_checked
... rest of form
user2 [] is_checked
... rest of form
user3 [X] is_checked
... rest of form
Then when I hit submit it will create two new entries in the Feedback table, one for user1 and one for user3
I am stuck with a problem - I want to add a simple form field to edit the objects that I am looping through in the template. Here's my model:
class Topic(BaseModel):
name = models.TextField()
Here's my model form:
class TopicForm(forms.ModelForm):
class Meta:
model = Topic
fields = ["name"]
And here's my views:
def App(request):
tname = Topic.objects.get(pk=1)
if request.method == "POST":
form = TopicForm(data = request.POST, instance=tname)
if form.is_valid():
form.save()
And my template is simple:
{% for lecture in lectures %}
<form action="/app/" method="POST">
{% csrf_token %}
{{ form }}
<input type="submit" value="Post">
</form>
{% endfor %}
The thing is that I want to have a form field to edit EACH model not just one that has a pk of 1... how do I do that ?
I think you need to do objects.all() instead of get(pk=1). Then loop over those objects, and save them to a list that you save to the context. Something like this:
tnames = Topic.objects.all()
lectures = []
for tname in tnames:
lectures.append(TopicForm(instance=tname))
context = {
'lectures' : lectures
}
More specifically, you probably want to look into Model formsets. See https://docs.djangoproject.com/en/1.6/topics/forms/modelforms/#changing-the-queryset. Then you can directly give a queryset as initial data.
I am getting this error when i visit my page:
Caught AttributeError while rendering: 'WSGIRequest' object has no attribute 'get'
The error kicks in on line "17" of my html, which is the line that outputs form.as_p
The html looks like this:
{% extends "base.htm" %}
{% block content %}
{% if story_list %}
{% for story in story_list %}
<div class="Story">
{{ story.title }}
</div>
{% endfor %}
{% else %}
<p>No stories are present - enter one below</p>
{% endif %}
<h3>Create a new story</h3>
<form action="/addStory" method="post">
{% csrf_token %}
{{ form.as_p }} ***THIS IS LINE 17***
<input type="submit" value="Submit"/>
</form>
{% endblock %}
The problem is i have a view that does two things, and from the django tutorials overrode the get_context_data method to add the second item to the django context. Because, um, that's what i'm meant to do, riiiiiiiiight?
#for showing of the stories!
class StoryShowView(ListView):
model = StoryForm
def get_queryset(self):
return getStoryItemsForUser(self.request)
def get_context_data(self, **kwargs):
context = super(StoryShowView,self).get_context_data(**kwargs)
context['form'] = createNewStoryForm(self.request)
return context
Where, well, the method createNewStoryForm just does this:
def createNewStoryForm(request):
return StoryForm(request)
and StoryForm is just this:
class StoryForm(ModelForm):
class Meta:
model = Story
ordering = ['create_date']
and the Story model is a normal model, that probably isn't part of the problem, but, hey, i am a cutting and a pasting, so here goes!
class Story(models.Model):
user = models.ForeignKey(User)
post = models.ForeignKey(Post)
title = models.CharField(max_length=100)
is_closed = models.BooleanField()
is_random = models.BooleanField() # for uncategorised stories. Only one of these.
result = models.CharField(max_length=20) #how did the relo work out?
create_date = models.DateTimeField('date created')
def __unicode__(self):
return self.title
Any ideas what i am doing wrong?
UPDATE:
ah, it was the line::
return StoryForm(request)
I take it i can either pass in a "request.POST" or nothing, is that it?
Probably you're right and you were passing request instead of request.POST, reqest.GET or request.REQUEST to the constructor of your form. See the doc on how to use forms:
def contact(request):
if request.method == 'POST': # If the form has been submitted...
form = ContactForm(request.POST) # A form bound to the POST data
if form.is_valid(): # All validation rules pass
# Process the data in form.cleaned_data
# ...
return HttpResponseRedirect('/thanks/') # Redirect after POST
else:
form = ContactForm() # An unbound form
return render_to_response('contact.html', {
'form': form,
})
Two problems that I can see. The easy one being that you can simply replace this line:
context['form'] = createNewStoryForm(self.request)
with
context['form'] = StoryForm(request.POST, request.FILES)
Finally shouldn't this:
class StoryShowView(ListView):
model = StoryForm
Be:
class StoryShowView(ListView):
model = Story