I have declared 2 form like this.
class TripItemForm(Form):
.....
class ShiftMainform(Form):
trip_list = FieldList(FormField(TripItemForm),validators=[checking_time])
Now in django view class I have initialize this trip_list field like this
class DjangoView(View):
def get(self, request, id):
form = ShiftMainform()
form.trip_list = list_trips #here list_trips is the list of TripItemForm objects.
context = {
'form': form,
}
return render(request, 'example.html', context)
When the html file rendered it shows that form.trip_list is empty. Can anyone tell me why is this happen? What I've done wrong or what should be the right way to render FieldList field in django tempalte.
Thanks in advance.
Related
I am experimenting with Django class based views and for some reason this simple post view does not seem to be working. When looking at my terminal it gets stuck on the GET method / validation of the csrf token. It is either not being validated or not saving to the database and therefore not being redirected to the thank-you page. I am not sure how to solve this issue. It definitely is not being saved to the DB, but as far as I am aware everything is correct here. I also am using a class based form which is why I am simply just calling form.save() The code is as follows:
class ReviewView(View):
def get(self, request):
form = ReviewForm()
return render(request, 'reviews/review.html', {
'form': form
})
def post(self, request):
form = ReviewForm(request.POST)
if form.is_valid():
form.save()
return HttpResponseRedirect('/thank-you')
return render(request, 'reviews/review.html', {
'form': form
})
Any help or ideas is greatly appreciated!
I have found that when passing context and a title into my views it causes the page to only show its html source code instead of the actual frontend graphics. If i remove the title being passed in then it works again but i do want to have the title passed in so is there any way to have this work?
Views
def myPosts(request):
context = {
'products': Post.objects.all()
}
return render(request, 'create/my_posts.html', context, {'title_page': 'My Posts'})
class PostListView(ListView):
model = Post
template_name = 'my_posts.html'
context_object_name = 'products'
when you are passing context yo can do something like this
context = {
'products': Post.objects.all(),
'title_page': 'My Posts'
}
and finally pass
return render(request, 'create/my_posts.html', context)
In the front end, you can use it as context.title_page
I have multiple forms to be shown everywhere in my project and hence I read that having a context_processor was the best way to do it. So, I created one inside my app and it looks something like this:
def forms_processor(request):
name_form = NewNameForm()
work_form = NewWorkForm()
address_form = NewAddressForm()
context = {'name_form': name_form,
'work_form': work_form,
'address_form': work_form,
}
return context
This works great, I can just use {{name_form}} anywhere in my templates and that renders the form.
Now my question is, where do I validate the form? In my views.py or the context_processors.py? Right now my views for name_form looks something like this:
def user_profile(request):
if request.method == 'POST':
name_form = NewNameForm(request.POST)
if name_form.is_valid():
form.save()
else:
ctx = {'title': 'Profile', 'active_tab': 'Profile'}
return render (request, 'user_profile.html', ctx)
This isn't working actually, if I submit an invalid form, it just comes back to the same page and won't show a populated form.
If someone could guide me or redirect me to some docs on this topic, that'd be awesome! Thanks!
The problem is that your processor instantiates the form on each render. Each time you call render, your processor is called, which instantiates a new form and displays THAT form, not the form instance that you created in the view. Therefore, the form being rendered is a blank instance but the form that contains the input and errors was destroyed by garbage collection after finishing your view.
A way I would do this, is passing the form you create in the view back to context before rendering. Pass it in to a context key such as "name_form_filled". Then if that variable is present in the context, don't render "name_form", instead render "name_form_filled".
views.py
def user_profile(request):
ctx = {}
if request.method == 'POST':
name_form = NewNameForm(request.POST)
if name_form.is_valid():
name_form.save() # you named this named_form, not form.
# If you want to redirect to another view when the form is saved successfuly, do it here.
else:
ctx["name_form_filled"] = form
else:
ctx.update({'title': 'Profile', 'active_tab': 'Profile'})
return render (request, 'user_profile.html', ctx)
user_profile.html
<div id="form_container">
{% if name_form_filled %}
<!-- Render form that has input and errors from previous POST. -->
{{ name_form_filled }}
{% else %}
<!-- render empty initial form. User has not attempted to submit yet. -->
{{ name_form }}
{% endif %}
</div>
===========================================================================
Another way you could do this is turn this view into a class based view and inherit a base class based view. This base class will override the get_context_data method and add your three forms. Note that you won't be using the context processor with this methodology so you could get rid of it if wanted in this case.
All views that use your form will extend the base view class. Then, after evaluating your form, if it is invalid, overwrite your name_form context key with the invalid form instance, which will be in your context.
views.py
class BaseView(View):
def get_context_data(self, *args, **kwargs):
context = {
"name_form": NewNameForm(),
"work_form": NewWorkForm(),
"address_form": NewAddressForm()
}
return context
class UserProfileView(BaseView):
def get(self, request, *args, **kwargs):
# Do GET logic here.
ctx = self.get_context_data(*args, **kwargs) # BaseView.get_context_data will be called here unless you override it in this class.
ctx.update({'title': 'Profile', 'active_tab': 'Profile'})
return render (request, 'user_profile.html', ctx)
def post(self, request, *args, **kwargs):
# Do POST logic here.
ctx = self.get_context_data(*args, **kwargs) # BaseView.get_context_data will be called here unless you override it in this class.
name_form = NewNameForm(request.POST)
if name_form.is_valid():
name_form.save()
else:
ctx["name_form"] = name_form # will replace the empty form in context with the form instance created in name_form that has input and errors.
return render (request, 'user_profile.html', ctx)
user_profile.html
<div id="form_container">
<!-- Will render whatever is in name_form. If this is after the
user has submitted an invalid form, this form will be populated with input and errors because we overwrote it in the view. -->
{{ name_form }}
</div>
===========================================================================
I personally think that the first solution is the best but when you start getting more complex, you should probably switch over to the second solution as class based views make complex views way easier.
Direct answer: you validate the form in views.py with is_valid() method. What you need is to populate context with bound form if the form is invalid:
def user_profile(request):
ctx = {'title': 'Profile', 'active_tab': 'Profile'}
if request.method == 'POST':
name_form = NewNameForm(request.POST)
if name_form.is_valid():
form.save()
return redirect(YOUR_REDIRECT_URL) # Always redirect after successful POST
ctx['form'] = form # if form is invalid return it with context
return render (request, 'user_profile.html', ctx)
Read more in documentation.
I have tried following this suggestion to pass string parameters to a class based view but it does not seem to work.
the url:
url(r'^chart/(?P<chart_name>\w+)/$',
ChartView.as_view(chart_name='chart_name'), name="chart_url"),
the view:
class ChartView(View):
template_name = "chart.html"
chart_name = None
def post(self, request, *args, **kwargs):
form = DatesForm(request.POST)
context = {
'form': form
}
return render(request, self.template_name, context)
def get(self, request, *args, **kwargs):
print("test")
form = DatesForm()
# fetch plot data (default values used)
context = {
'form': form,
'chart_name': self.chart_name
}
return render(request, self.template_name, context)
the link that is supposed to be redirecting to the view:
Sometext
(namespace 'chartboard' given in the project's urlconf).
the error:
NoReverseMatch at /chart/lords/
Reverse for 'chart_url' with arguments '()' and keyword arguments '{}' not found. 1 pattern(s) tried: ['chart/(?P<chart_name>\\w+)/$']
For what its worth, "test" gets printed twice to the console output (why?)
Using django 1.8.11 and python 3.4.3 on Ubuntu 14.04.04
You should access the chart_name using kwargs:
# urls.py
url(r'^chart/(?P<chart_name>\w+)/$',
ChartView.as_view(), name="chart_url"),
# and then in the view
class ChartView(View):
template_name = "chart.html"
def get(self, request, *args, **kwargs):
form = DatesForm()
context = {
'form': form,
'chart_name': kwargs['chart_name'] # here you access the chart_name
}
return render(request, self.template_name, context)
The post you have considered for implementing this is for making sure that a variable is available in templates and that is taken care of by setting it up in context which is passed to the template render.
The problem you are facing here is to access a named group defined in the url pattern.
Here is more documentation on how django process a request when you try to access a URL.
I want to customize django admin.. For additing I did this :
class SomeAdmin(admin.ModelAdmin):
"""
Customized admin template and corresponding
views for adding media.
"""
add_form_template = "admin/add.html"
def add_view(self, request, form_url='', extra_context=None):
if request.method == "POST":
//YOur logic
return super(SomeAdmin,self).add_view(request)
Its working fine.. In the same way how can I get custom list view and custom change view ?
Any help ?
ModelAdmin has both the change_view() and changelist_view() methods so you can override them the same way.