Django. Unbound method in urls - python

I trying to accept localhost:8000/upload file and run into this problem
unbound method upload_file() must be called with Upload instance as first argument (got WSGIRequest instance instead)
urls.py
from django.conf.urls import include, url
from django.contrib import admin
from upload.views import Upload
urlpatterns = [
url(r'^admin/', include(admin.site.urls)),
url(r'^upload/$', Upload.upload_file),
url(r'^thanks/$', Upload.thanks),
]
views.py
from django.http import HttpResponse
from django.template import RequestContext
from django.shortcuts import render_to_response
from upload.forms import FileForm
from upload.models import upFile
class Upload():
def upload_file(request):
if request.method == "POST":
form = FileForm(request.POST, request.FILES)
if form.is_valid():
form.save()
return HttpResponseRedirect('thanks')
else:
form = FileForm()
return render_to_response('temp1.html', {'form': form}, context_instance = RequestContext(request))
def thanks(request):
return render_to_response('temp2.html')

Your view is not inheriting from a Django class based view: https://docs.djangoproject.com/en/1.8/topics/class-based-views/intro/
from django.views.generic import View
class Upload(View):
def upload_file(self, request):
if request.method == "POST":
form = FileForm(request.POST, request.FILES)
if form.is_valid():
form.save()
return HttpResponseRedirect('thanks')
else:
form = FileForm()
return render_to_response('temp1.html', {'form': form}, context_instance = RequestContext(request))
def thanks(self, request):
return render_to_response('temp2.html')
You need to inherit form one of these view classes otherwise Django will treat your view as a normal class which is why you are getting that error.
you also need to adjust your urls.py:
urlpatterns = [
url(r'^upload/', Upload.as_view()),
]
After looking through the docs and at the structure of your vie I'm not sure you are structuring your views properly for class based views. You may want to read through the docs some more and adjust your structure accordingly.
I believe you will want somethign that looks more like this:
class Upload(View):
def get(self, request):
form = FileForm()
return render_to_response('temp1.html', {'form': form}, context_instance = RequestContext(request))
def post(self, request):
form = FileForm(request.POST, request.FILES)
if form.is_valid():
form.save()
return HttpResponseRedirect('thanks')
else:
return render_to_response('temp2.html')

I don't understand why you have the Upload class at all. Python is not Java, there's no need to put everything into classes. Put upload_file and thanks at the module level, and refer to them directly in the url patterns.

Related

How to create a class-based view for multiple file uploads

I am uploading multiple files and I would like to use classes in the models.py, forms.py, and also views.py so that I the code is easily changeable in one place and reused.
The issue I am having is not understanding how to implement a class-based view for file uploads that allows me to create instances for reuse.
I have tried to implement a class-based view as as shown below but I believe I need to insert an init method and insert self. on the attributes but I am confused being that there are functions such as reverse_lazy in the attributes.
My views.py
class FileUploadView(View):
form_class = DocumentForm
success_url = reverse_lazy('home') # want different url for every instance
template_name = 'file_upload.html' # same for template_name
def get(self, request, *args, **kwargs):
form = self.form_class()
return render(request, self.template_name, {'form': form})
def post(self, request, *args, **kwargs):
form = self.form_class(request.POST, request.FILES)
if form.is_valid():
form.save()
return redirect(self.success_url)
else:
return render(request, self.template_name, {'form': form})
EDIT: As Gasanov suggested, you can insert the success_url and template_name as parameters in the url_patterns as such:
urlpatterns = [
path('stylist/', payroll_views.FileUploadView.as_view(
success_url=reverse_lazy('landing.html'), template_name='stylist.html'), name='stylist'),
]
This allows for reuse of the class-based view in a clean and pragmatic way.
I'm not sure where you want to declare different success_url or template_name, but you can do it in urls.py like this:
urlpatterns = [
path('a/', FileUploadView.as_view(success_url=reverse_lazy('home'), template_name='index1.html')),
path('b/', FileUploadView.as_view(success_url=reverse_lazy('nothome'), template_name='index2.html'))
]
Looks like you could benefit from using FormView instead of View, because you are basically reimplementing post from there.
In order to "overwrite" success_url and template_name, there are already methods that do just that:
class FileUploadView(FormView):
...
def get_success_url(self):
if blahblah:
return something
else:
return something_else
def get_template_names(self):
if blahblah:
return ['some/template.html']
else:
return ['another/template.html']

How do i pass a forms "text" input into another variable that is in views.py

In my Django project, I have to take the input from forms and pass it as an argument for a function that is in views.py. How do I do it?
My views.py code
from django.shortcuts import render,render_to_response
from django.http import Http404, HttpResponse, HttpResponseRedirect
from search_engine import query
from .forms import SearchForm
def query_input(request):
if request.method == "POST":
form = SearchForm(request.POST)
else:
form = SearchForm()
return render(request, 'search.html', {'form': form})
def search_results(request):
search_results = query.results(# text input from forms)
a = "<br /><br />".join(word for word in search_results)
return HttpResponse(a)
My forms.py code
from django import forms
class SearchForm(forms.Form):
your_query = forms.CharField(max_length=100)
After you checked that the request method is a POST you can validate the form and then access its attributes like this
In views.py:
if request.method = "POST":
form = SearchForm(request.POST)
if form.is_valid():
search_text = form.cleaned_data['search_text']
# code from search_results function to return HTTP Response
Check out the documentation on forms and view here for more information.

HttpResponse won't display `post` information when submitting a form

I'm working my way through Django and I'm creating an app that will allow users to use an ID number to sign-in to a system. So I have two views, one for users to log-in, and the other to sign-up. The former view works just fine, I can get it to display the information the user has submitted. However I can't get the second view to display the POST data to the user:
from .forms import NameForm, IdForm
from django.shortcuts import render
from django.http import HttpResponse
def sign_in(request):
if request.method == "POST":
#here will construct the form with the POST data
form = NameForm(request.POST)
#the next part is to check that the information submitted is valid
if form.is_valid():
post = form.save()
post.save()
return HttpResponse(post)
else:
return HttpResponse("Form is invalid")
else:
form = NameForm()
return render(request, 'checkin/base.html', {'form': form})
def sign_up(request):
if request.method == "POST":
form = IdForm(request.POST)
if form.is_valid():
post = form.save()
post.save()
return HttpResponse(post)
else:
return HttpResponse('Form is invalid')
else:
form = IdForm()
return render(request, 'checkin/base.html', {'form': form})
Basically I want to make the response to be "thank you, your ID number is: post".
Here is the class for my model:
from __future__ import unicode_literals
from django.db import models
from django import forms
from django.forms import ModelForm
# Create your models here.
class Question(models.Model):
question_text = models.CharField("What is your ID?", max_length=200)
id_text = models.CharField("Enter a new identification
number",max_length=200, null=True)
def __str__(self):
return self.question_text
And here are the form classes for both views:
from django.forms import ModelForm
from .models import Question
#put the form here
class NameForm(ModelForm):
class Meta:
model = Question
fields = ['question_text']
class IdForm(ModelForm):
class Meta:
model = Question
fields = ['id_text']
It's not generally acceptable to display the POST data as the respnose to the user. That's not HTML, merely a dictionary which the average user will not understand. The standard way of using forms in Django (and indeed almost any web framework) is to display the form validation errors to the user so that he may rectify it.
The right way
def sign_up(request):
if request.method == "POST":
form = IdForm(request.POST)
if form.is_valid():
post = form.save()
post.save()
return HttpResponseRedirect('/succes_url')
else:
form = IdForm()
return render(request, 'checkin/base.html', {'form': form})
The problem is in line return HttpResponse(post),You are passing a whole form into HttpResponse,but as you mentioned,you just need id_text field of the IdForm.
So the updated code should be :
def sign_up(request):
if request.method == "POST":
form = IdForm(request.POST)
if form.is_valid():
post = form.save()
post.save()
id = post.id_text
return HttpResponse('thank you, your ID number is: '+id)
else:
return HttpResponse('Form is invalid')
else:
form = IdForm()
return render(request, 'checkin/base.html', {'form': form})

Django file upload form constructor explained

As I go through Django tutorial, I'm confused about the way the form is constructed, here is the link where the following code is from:
forms.py
from django import forms
class UploadFileForm(forms.Form):
title = forms.CharField(max_length=50)
file = forms.FileField()
views.py
from django.http import HttpResponseRedirect
from django.shortcuts import render
from .forms import UploadFileForm
# Imaginary function to handle an uploaded file.
from somewhere import handle_uploaded_file
def upload_file(request):
if request.method == 'POST':
form = UploadFileForm(request.POST, request.FILES)
if form.is_valid():
handle_uploaded_file(request.FILES['file'])
return HttpResponseRedirect('/success/url/')
else:
form = UploadFileForm()
return render(request, 'upload.html', {'form': form})
Question: Where can I find the constructor declaration of UploadFileForm?
here is the constructor declaration: https://github.com/django/django/blob/master/django/forms/forms.py#L72-L98
Question answered?

login view not logging user in

I'm building my first django app. I'm trying to create a slightly customized authentication system but my login view doesn't work.
When I create a user, my register view creates the user, authenticates it and then redirects to another url properly.
If then I log out and got to my login form and post to the login view, I keep being redirected to the same form. my views.py looks like this:
from django.contrib.auth.forms import AuthenticationForm
from django.shortcuts import render
from django.contrib import messages
from general import forms
from django.http import HttpResponseRedirect
from django.contrib.auth.decorators import login_required
from django.contrib.auth import login,logout, authenticate
# Create your views here.
def home(request):
if request.user.is_authenticated():
return render(request, 'general/home.html')
else:
return HttpResponseRedirect('/login')
def loginView(request):
form = AuthenticationForm()
if request.method=='POST':
form = AuthenticationForm(request.POST)
if form.is_valid():
user = authenticate(username=request.POST['username'], password=request.POST['password'])
if user is not None:
messages.add_message(request, messages.SUCCESS,
"Welcome back, {}".format(user))
login(request, user)
return home(request)
return render(request, 'general/loginForm.html', {'form': form})
def logoutView(request):
if request.user.is_authenticated():
logout(request)
return HttpResponseRedirect('/')
def register(request):
if request.method=='POST':
form = forms.MyCreationForm(request.POST)
if form.is_valid():
form.save()
messages.add_message(request,messages.SUCCESS,
"Welcome to ShopGlue, in 3 steps you'll be up and running!")
user = authenticate(username=request.POST['username'], password=request.POST['password1'])
if user is not None:
login(request,user)
return profile(request)
else:
return render(request, 'general/registerForm.html', {'form': form})
else:
form = forms.MyCreationForm()
return render(request, 'general/registerForm.html', {'form': form})
#login_required()
def profile(request):
return render(request, 'general/profile.html')
My urls.py looks like this:
from django.conf.urls import url
from general import views
urlpatterns = [
url(r'^$', views.home, name="home"),
url(r'^login$', views.loginView, name="loginView"),
url(r'^logout$', views.logoutView, name="logoutView"),
url(r'^register$', views.register, name="register"),
url(r'^profile$', views.profile, name="profile"),
]
I can't for the life of me, figure out what I am doing wrong. Some feedback would be very much appreciated.
Thank you guys.
Edit: This is MyCreationForm():
class MyCreationForm(UserCreationForm):
class Meta:
model = User
fields = [
'username',
'email',
]
It's just extending UserCreation form provided by django.
Also, in the admin when I click on one user and try to see its password, I see this:
algorithm: pbkdf2_sha256 iterations: 20000 salt: cU32aI****** hash: sABS3A**************************************
Which means that the password has been hashed before it was stored.
Any ideas on how can I fix my login view? :(
The only problem i see with your view is your return statement after login() call. Why return a view and not an HttpResponse object
return HttpResponseRedirect('/')
Okay, figured it out.
form = AuthenticationForm(request.POST)
Should be:
form = AuthenticationForm(data=request.POST)

Categories

Resources