So I basically have this code:
#render_to('hello/home.html')
def home(request):
info = Info.objects.get(pk=1)
if request.method == "POST":
form = InfoForm(request.POST, instance=info)
else:
form = InfoForm(instance=info)
return {"info": info, "form": form}
aaand it doesn't work as I guessed it would be.
If I initialize form with ONLY either model instance or POST, it works, but not when both.
Is there a (nice?) way to create form with data populated from model instance, and update it with data from request.POST?
The code you are writing is already in the framework.
urls.py
from django.views.generic import UpdateView
from myapp.forms import InfoForm
urlpatterns = patterns('',
url(r'^info/(?P<pk>[-_\w]+)/update/$', UpdateView.as_view(model= Info,template_name="hello/home.html",form_class=InfoForm), name='info_update'),
)
# you might need to include a success url in the **kwargs i.e. success_url="/thankyou/"
Related
This is my views function,
def studentcreate(request):
reg = StudentForm()
string = "Give Information"
if request.method == "POST":
reg = StudentForm(request.POST)
string = "Not Currect Information"
if reg.is_valid():
reg.save()
return render('http://localhost:8000/accounts/login/')
context = {
'form':reg,
'string': string,
}
return render(request, 'student.html', context)
Here first we store form in reg variable then also we write reg = StudentForm(request.POST) why?
acutally why we write this?
I can't tell you why you are writing this. Maybe only you know. It does not make much sense. I would recommend reading the Django documentation on this at https://docs.djangoproject.com/en/4.0/topics/forms/#the-view
from django.http import HttpResponseRedirect
from django.shortcuts import render
from .forms import NameForm
def get_name(request):
# if this is a POST request we need to process the form data
if request.method == 'POST':
# create a form instance and populate it with data from the request:
form = NameForm(request.POST)
# check whether it's valid:
if form.is_valid():
# process the data in form.cleaned_data as required
# ...
# redirect to a new URL:
return HttpResponseRedirect('/thanks/')
# if a GET (or any other method) we'll create a blank form
else:
form = NameForm()
return render(request, 'name.html', {'form': form})
You read from data if the request is a POST. Otherwise, return an empty form.
You could think of the "request.POST" as a parameter passed onto the form in the view. This tells the view that the form mentioned has POST data from the form in name.html. Otherwise it is just an empty form.
Here is my code that I believe pertains to this situation. I'm sorry, I'm new to django.
views.py
from django.http import HttpResponseRedirect
from django.shortcuts import render
from .forms import SearchForm
def result_one(request):
return render(request, "testresult.html", {})
def get_results(request):
if request.method == 'POST':
form = SearchForm(request.POST)
if form.is_valid():
return HttpResponseRedirect('/result/')
else:
form = SearchForm()
return render(request, 'index.html', {'form': form})
urls.py
from django.conf.urls import url
from django.contrib import admin
urlpatterns = [
url(r'^admin/', admin.site.urls),
url(r'^search/$', "search.views.get_results"),
url(r'^result/$', "search.views.result_one"),
]
forms.py
from django import forms
class SearchForm(forms.Form):
client_group_number=forms.IntegerField(label='Group Number', widget=forms.TextInput(attrs={'placeholder': 'Group Number'}))
From my understanding, what I believe should happen is that an input will be put into a html page. When the user hits submit, the input gets saved into forms.py as data. This data gets manipulated in views.py which gets displayed in a different html page. (I hope this is correct)
What I want it to do is take in an input for client_group_number(in forms.py) from index.html(for example: 123), that can be accessed in views.py and displayed in another html template that I have called testresult.html, which would display Group Number = 123 (the 123 coming from either the forms.py or views.py).
This might be a very simple thing to accomplish and I apologize if it is, but I can't seem to find what I need on the internet.
Django validate the form input data in the cleaned_data dictionary. You would need to pass this to the new template either as arguments in the redirect or using session. Here is one simple example to give you an idea, there are probably better ways.
if form.is_valid():
group_number = form.cleaned_data["client_group_number"]
HttpResponseRedirect("/result/?group_number=" + group_number)
When I load my view at : localhost:8000/Scan, it throws an issue of:
TypeError on views.py in Scan, line 27:
form = Scan() # Otherwise, set the form to unbound
Any idea what I'm doing wrong here? I tried researching, but couldn't find the answer. (Django newbie here) . Thank you all!
Views.py
from django.http import HttpResponse
from Scanner.forms import SubmitDomain
def Scan(request):
if request.method == 'POST': # If the form has been submitted...
form = SubmitDomain(request.POST) # A form bound to the POST data
if form.is_valid(): # If form input passes initial validation...
form.cleaned_data['domainNm'] ## clean data in dictionary
try:
## check if Tld Table has submitted domain already
from Scanner.models import Tld
Tld.objects.get(domainNm=form.cleaned_data['domainNm'])
except Tld.DoesNotExist:
print "Would you like to create an account?"
## redirect to account creation
else:
print "Do you have an account? Please login."
## redirect to account login
else:
form = Scan() # Otherwise, set the form to unbound
Forms.py
from django.forms import ModelForm
from Scanner.models import Tld
class SubmitDomain(ModelForm):
class Meta:
model = Tld #Create form based off Model for Tld
fields = ['domainNm',]
def clean_domainName(self):
val = self.clean_domainName('domainNm')
return val
## This creates the form.
form = SubmitDomain()
In your model form:
from django.forms import ModelForm
from Scanner.models import Tld
class SubmitDomainForm(ModelForm):
class Meta:
model = Tld
fields = ['domainNm']
def clean_domainName(self):
val = self.cleaned_data.get('domainNm')
if Tld.objects.filter(domainNm=val).count() > 0:
raise forms.ValidationError(u'Sorry that domain already
exists, etc, etc')
return val
In your view, do:
from django.shortcuts import render
from Scanner.forms import SubmitDomainForm
def scan(request): # functions should start with a lowercase letter
# Bind the post data to the form, if it exists.
# No need for a separate if statement here
form = SubmitDomainForm(request.POST or None)
if request.method == 'POST':
if form.is_valid():
# save your model form, or do something else
return render(request, 'your-template.html', {'form': form})
Hope that helps you out. Your view is currently instantiating the wrong type of object for the form, hence the TypeError. Your current clean method on your model form will never validate anything. It just sets the value equal to the clean function. Instead of cluttering your view with form validation logic, put that into the clean method of the form for that field and you can raise exceptions for different conditions.
it fails when reuqest.method != "POST", in which case form is not defined
The problem is not specific to django, it's basic python. Your indentation is wrong. The code should probably look like this:
if request.method == 'POST':
form = SubmitDomain(request.POST)
if form.is_valid(): # indent fixed here
form.cleaned_data['domainNm']
I am trying to pass the id through reverse. But it's not working. I'm getting this error
Reverse for 'reg.views.thanks' with arguments '(20,)' and keyword arguments '{}' not found.
Here is my views.py:
from django.http import HttpResponse, Http404, HttpResponseRedirect
from django.core.urlresolvers import reverse
from reg.models import registration, registrationform
from django.shortcuts import render_to_response, get_object_or_404
from django.template import RequestContext
def registration(request):
if request.method == 'POST':
form = registrationform(request.POST)
if form.is_valid():
data = form.save()
id = data.id
return thanks(request,id)
else:
form = registrationform()
return render_to_response('registration.html', {'form' : form}, context_instance=RequestContext(request))
def thanks(request, id):
p = get_object_or_404(registration, pk=id)
return render_to_response('thanks.html', {'reg' : p})
Here is my urls.py:
from django.conf.urls import patterns, include, url
url(r'^registration/$', 'reg.views.registration'),
url(r'^thanks/$', 'reg.views.thanks'),
url(r'^$','django.views.generic.simple.direct_to_template', {'template' : 'index.html'}),
)
Here is thanks.html:
<html>
<body>
<p>Thank you for registration mr.{{reg.username}}</p>
</body>
</html>
and I'm also showing my models.py:
from django.db import models
from django.forms import ModelForm
class registration(models.Model):
username = models.CharField(max_length=100)
password = models.CharField(max_length=100)
def __unicode__(self):
return self.name
class registrationform(ModelForm):
class Meta:
model = registration
Thanks.
from this links (django tutorial):
https://docs.djangoproject.com/en/dev/topics/http/urls/#django.core.urlresolvers.reverse
example:
def myview(request):
return HttpResponseRedirect(reverse('arch-summary', args=[1945]))
so your code goes to:
in urls.py:
url(r'^thanks/(?P<id>\d+)$', 'reg.views.thanks', name='my_thanks_url')
in your function:
return HttpResponseRedirect(reverse('my_thanks_url', args=[id]))
This line
return HttpResponseRedirect(reverse('reg.views.thanks', args=(id,)))
Is trying to construct a url to your view reg.views.thanks, with the id variable used as a parameter.
This line in urls.py
url(r'^thanks/$', 'reg.views.thanks'),
Does not have anywhere for that parameter to go.
The first thing that you need to figure out is whether you actually want to send an HTTP redirect to the browser to tell it to go to the 'thanks' page. If you really do, then you need a way to send that id in the URL. You can do it as part of the URL path itself, as #moguzalp suggests, or you can put it in the query string, like
/thanks/?id=12345
Or you can do other things, like stashing the id in the user's session, and pulling it out when they request the thanks page. That's a bit more complicated, though.
If you don't actually need to issue an HTTP redirect, then there's nothing stopping you from just calling the thanks() function from inside your view function, like this:
def registration(request):
if request.method == 'POST':
form = registrationform(request.POST)
if form.is_valid():
data = form.save()
id = data.id
return thanks(request, id)
else:
form = registrationform()
return render_to_response('registration.html', {'form' : form}, context_instance=RequestContext(request))
The URL won't change in the browser, but the correct ID will be used, and doesn't need to appear anywhere else, in the URL, the query parameters, or the session
I know how to set initial values to a form from the view. But how do I go about letting a generic view set initial values to a form? I can write a wrapper view for the generic view, but I still have no access to the form object instantiation.
The specific goal I'm trying to achieve is to have a user create a new object, using the create_object generic view. However, I'd like to set a field of the object 'user' to the currently logged in user, which is only accessible as request.user. How can the form be initialized to have this field?
Edit: I came across __new__. Could this call its own constructor with some default arguments?
Many thanks.
Unfortunately, you cannot achieve this behavior through Django's create_object generic view; you will have to write your own. However, this is rather simple.
To start off, you must create a new form class, like this:
from django import forms
class MyForm(forms.ModelForm):
class Meta:
model = MyModel # model has a user field
Then you would be able to create a view like this:
from django.shortcuts import render_to_response
from django.template import RequestContext
from django.http import HttpResponseRedirect
from django.contrib.auth.decorators import login_required
#login_required
def create_mymodel(request):
if request.method == 'POST':
# Get data from form
form = MyForm(request.POST)
# If the form is valid, create a new object and redirect to it.
if form.is_valid():
newObject = form.save()
return HttpResponseRedirect(newObject.get_absolute_url())
else:
# Fill in the field with the current user by default
form = MyForm(initial={'user': request.user})
# Render our template
return render_to_response('path/to/template.html',
{'form': form},
context_instance=RequestContext(request))
You could do this in a generic view wrapper by dynamically constructing a form class and passing it to the generic view, but that cure is probably worse than the disease. Just write your own view, and wait eagerly for this to land.
If you want all the features of the generic view then you can just create a new generic view using the original as a template.
Eg:
def create_object_with_initial(request, model=None, template_name=None,
template_loader=loader, extra_context=None, post_save_redirect=None,
login_required=False, context_processors=None, form_class=None, initial=None):
if extra_context is None: extra_context = {}
if login_required and not request.user.is_authenticated():
return redirect_to_login(request.path)
model, form_class = get_model_and_form_class(model, form_class)
if request.method == 'POST':
form = form_class(request.POST, request.FILES)
if form.is_valid():
new_object = form.save()
msg = ugettext("The %(verbose_name)s was created successfully.") %\
{"verbose_name": model._meta.verbose_name}
messages.success(request, msg, fail_silently=True)
return redirect(post_save_redirect, new_object)
else:
print "creating", form_class, " with initial data ", initial
form = form_class(initial=initial)
# Create the template, context, response
if not template_name:
template_name = "%s/%s_form.html" % (model._meta.app_label, model._meta.object_name.lower())
t = template_loader.get_template(template_name)
c = RequestContext(request, {
'form': form,
}, context_processors)
apply_extra_context(extra_context, c)
return HttpResponse(t.render(c))
This is copied from /site-packages/django/views/generic/create_update.py with only lines 3 and 21 changing to incorporate the initial data.
Then use it as you might expect:
object_info = {
'model': YourModel,
'initial': {'data' : 'Initial Value'},
'template_name': 'template.html'
}
url(r'^path/$',
login_required(create_object_with_initial),
object_info,
name='url_name'),
That should work.