in views.py
class ProcessMessage(TemplateView):
template_name = 'chat/chat.html'
def get_object(self):
id=self.kwargs.get('pk')
obj=None
if id is not None:
obj= User.objects.get(pk=id)
return obj
def get(self, request, pk=None,*args, **kwargs):
obj=self.get_object()
print(obj,pk)
super(ProcessMessage, self).get(request, *args, **kwargs)
return render(request, self.template_name, {'form': ChatForm()})
def post(self, request, pk=None,*args, **kwargs):
obj=self.get_object()
pk=pk
print(pk)
print('obj is',obj)
form = ChatForm(data=request.POST)
# log = logging.basicConfig(level=logging.DEBUG)
# print('post from index')
if form.is_valid():
//////something////
in urls.py
app_name = 'chatbot'
urlpatterns = [
path('demo', views.ProcessMessage.as_view(), name='index'),
path('<uuid:pk>/demo', views.ProcessMessage.as_view(), name='index'),
]
I am getting the value of obj and pk inside get method but I want those value inside post method also(getting value None currently)
I need id/pk from URL in def Post method to get user information(no I don't want to use request.user)
Your template shows that you are submitting the form to a URL without a pk:
{% url 'chat:index' %}
You should include the pk when reversing the URL, e.g.
{% url 'chat:index' pk %}
You'll need to include the pk in the template context, e.g.
return render(request, self.template_name, {'form': ChatForm(), 'pk': pk})
I see that you are using the same view ProcessMessage for /demo/ and /<pk>/demo/. I would recommend using a different view for both URLs, I think it would help avoid issues like this.
Related
I would like to get your help in order to use context from a Django CBV in another CBV through get_context_data().
Objective:
Basically, I have a django ListView() with pagination. I pick up the current page in get_context_data(). Then, I would like to edit an object, so I'm going to UpdateView().
When I post the edit, it should return to the previous pagination. For example, if the object was on page 32, after the POST request, I need to be redirected to page 32.
My code:
class DocumentListView(AdminMixin, CustomListSearchView):
""" Render the list of document """
def get_context_data(self, **kwargs):
context = super(DocumentListView, self).get_context_data(**kwargs)
actual_page = self.request.GET.get('page', 1)
if actual_page:
context['actual_page'] = actual_page
return context
class DocumentFormView(CustomPermissionRequiredMixin, DocumentListView, UpdateView):
def get_current_page(self, **kwargs):
context = super(DocumentListView, self).get_context_data(**kwargs)
actual_page = context['actual_page']
return actual_page
def get_context_data(self, **kwargs):
context = super(DocumentFormView, self).get_context_data(**kwargs)
print(self.get_current_page())
...
return context
def post(self, request, pk=None):
...
return render(request, 'app/manage_document_form.html', context)
Issue:
I don't overcome to get the actual_page in my class DocumentFormView.
I got this issue :
AttributeError: 'DocumentFormView' object has no attribute 'object'
I tried to add in my post() function :
self.object = self.get_object()
But it doesn't solve the issue.
Do you have any idea ?
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.
trying to use django braces login mixin required in views
i dont have a databases to store session i 'am using
SESSION_ENGINE = "django.contrib.sessions.backends.cache"
without login when i type a url (eg: 8000/dashboard it direct me to login)
but when i trying to login in it is not redirecting me to my dashboard page
please help
class Login(CsrfExemptMixin, View):
template_name = 'login.html'
def get(self, request, *args, **kwargs):
try:
if request.session['access_token']:
if request.session['path_previous']:
return HttpResponseRedirect(request.session['path_previous'])
else:
return HttpResponseRedirect('/dashboard/')
except:
return render_to_response( self.template_name, context_instance=RequestContext(request))
def post(self, request, *args, **kwargs):
username = request.POST.get('uName','')
password = request.POST.get('pwd','')
login_obj = LoginDataView()
login_response = login_obj.get(request,username,password)
if login_response.status_code == 200:
request.session['access_token'] = login_response.json()['access_token']
request.session.set_expiry(10000)
print "hihihihihi"
return HttpResponseRedirect('/dashboard/')
else:
context = {
'bad_string' : "Please provide correct login credentials",
}
return render_to_response( self.template_name, context, context_instance=RequestContext(request))
class GetDashboardView(LoginRequiredMixin,CsrfExemptMixin, View):
login_url = '/login/'
#redirect_field_name = "hollaback"
raise_exception = False
template_name = 'index.html'
def get(self, request, *args, **kwargs):
tpl = tpl_lookup.get_template(self.template_name)
#return render_to_response( self.template_name, context_instance=RequestContext(request))
return HttpResponse(tpl.render())
Just try to use django-registration or so. If you will use it add to your urls.py:
url(r'^accounts/register$', RegistrationView.as_view(form_class=
RegistrationFormUniqueEmail), name='registration_register'),
url(r'^accounts/', include('registration.backends.default.urls')),
url(r'^accounts/', include('django.contrib.auth.urls')),
registration.backends.default.urls contains broken names, so including django.contrib.auth.urls fix it.
If you will use gjango-social-auth, add line below in urls.py
url(r'^accounts/', include('social_auth.urls')),
and fix datatime JSON serialization by adding following line in settings.py
SESSION_SERIALIZER = 'django.contrib.sessions.serializers.PickleSerializer'
It is not full tutorial or so on, it is just some of ways out.
i'm new in development using django, and i'm trying modify an Openstack Horizon Dashboard aplication (based on django aplication).
I implements one function and now, i'm trying to do a form, but i'm having some problems with the request.
In my code i'm using the method POST
Firstly, i'm want to show in the same view what is on the form, and i'm doing like this.
from django import http
from django.utils.translation import ugettext_lazy as _
from django.views.generic import TemplateView
from django import forms
class TesteForm(forms.Form):
name = forms.CharField()
class IndexView(TemplateView):
template_name = 'visualizations/validar/index.html'
def get_context_data(request):
if request.POST:
form = TesteForm(request.POST)
if form.is_valid():
instance = form.save()
else :
form = TesteForm()
return {'form':form}
class IndexView2(TemplateView):
template_name = 'visualizations/validar/index.html'
def get_context_data(request):
text = None
if request.POST:
form = TesteForm(request.POST)
if form.is_valid():
text = form.cleaned_data['name']
else:
form = TesteForm()
return {'text':text,'form':form}
My urls.py file is like this
from django.conf.urls.defaults import patterns, url
from .views import IndexView
from .views import IndexView2
urlpatterns = patterns('',
url(r'^$',IndexView.as_view(), name='index'),
url(r'teste/',IndexView2.as_view()),
)
and my template is like this
{% block main %}
<form action="teste/" method="POST">{% csrf_token %}{{ form.as_p }}
<input type="submit" name="OK"/>
</form>
<p>{{ texto }}</p>
{% endblock %}
I search about this on django's docs, but the django's examples aren't clear and the django's aplication just use methods, the Horizon Dashboard use class (how is in my code above)
When i execute this, an error message appears.
this message says:
AttributeError at /visualizations/validar/
'IndexView' object has no attribute 'POST'
Request Method: GET
Request URL: http://127.0.0.1:8000/visualizations/validar/
Django Version: 1.4.5
Exception Type: AttributeError
Exception Value:'IndexView' object has no attribute 'POST'
Exception Location:
/home/labsc/Documentos/horizon/openstack_dashboard/dashboards/visualizations/validar/views.py in get_context_data, line 14
Python Executable: /home/labsc/Documentos/horizon/.venv/bin/python
Python Version: 2.7.3
i search about this error, but not found nothing.
if someone can help me, i'm thankful
Your signature is wrong:
def get_context_data(request)
should be
def get_context_data(self, **kwargs):
request = self.request
Check the for get_context_data and the word on dynamic filtering
Since your first argument is the self object, which in this case is request, you are getting the error.
If you read more carefully the error message, it appears that the URL was retrieved using a GET method. Not POST:
AttributeError at /visualizations/validar/
'IndexView' object has no attribute 'POST'
Request Method: GET
Request URL: http://127.0.0.1:8000/visualizations/validar/
See the following link for an in deep explanation of GET vs POST
TemplateView by default will return a method not allowed 405 when you try to post to it. You can write your own post method for it:
class IndexView(TemplateView):
template_name = 'visualizations/validar/index.html'
def get_context_data(request):
#define your context and return
context = super(ContactView, self).get_context_data(**kwargs)
#context["testing_out"] = "this is a new context var"
return context
def post(self, request, *args, **kwargs):
context = self.get_context_data()
if context["form"].is_valid:
print 'yes done'
#save your model
#redirect
return super(TemplateView, self).render_to_response(context)
If you're going to post from a form, use FormView instead, and you can still define context as you wish by overwriting get_context_data:
from django.views.generic import TemplateView, FormView
from forms import ContactUsEmailForm
class ContactView(FormView):
template_name = 'contact_us/contact_us.html'
form_class = ContactUsEmailForm
success_url = '.'
def get_context_data(self, **kwargs):
context = super(ContactView, self).get_context_data(**kwargs)
#context["testing_out"] = "this is a new context var"
return context
def form_valid(self, form):
# This method is called when valid form data has been POSTed.
# It should return an HttpResponse.
#form.send_email()
#print "form is valid"
return super(ContactView, self).form_valid(form)
contact_us = ContactView.as_view()
And urls.py:
from django.conf.urls import patterns, url
urlpatterns = patterns('contact_us.views',
url(r'^$', 'contact_us', name='contact_us'),
)
Hope this helps :) More on FormsView.