Handling forms from class based view - python

Hello how can I pass form into template from class based view? In HTML everything inherits and I can render elements inside block content but I can not render form. This is my code. :
views.py:
class Signup(TemplateView):
model = Profile
template_name = 'home/sign-up.html'
form_class = UserCreationForm()
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
context['form'] = UserCreationForm
HTML:
{% extends "home/todo.html" %}
{% block content %}
<form method="POST">
{{form}}
</form>
{% endblock content %}

Give this a try
context['form'] = self.form_class
should work
But for User creation, you may better use CreateView instead of TemplateView
from django.views.generic import CreateView
class Signup(CreateView):
template_name = 'home/sign-up.html'
form_class = UserCreationForm()

Related

Show other contents besides a form in FormView?

I really dislike django CBV design which makes things without flexibility.
I would like to have a page whose upper part showing the content of objects and lower part has a form to be posted.
CBS formview
class EditStudent(FormView):
template_name = "editstudent.html"
model = models.Student
success_url = "/home"
Update:
I add the method but the error
'NoneType' object is not callable shows up.
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
context['students'] = Student.objects.all()[:5]
return context
How can I retriev objects of studens and show them on the template.
Thanks.
'NoneType' object is not callable: I get this error when I don't specify a form class. Created form class 'StForm' associated with model 'Student'.
In the EditStudent view class, the CreateView class was inherited, since the data was not saved to the database with the FormView.
Replace bboard with the name of the folder where your templates are placed.
I have this: templates/bboard which are in the application folder.
template_name = 'bboard/tam_form.html'
The success_url row specifies a path based on the path name.
success_url = reverse_lazy('student')
The five most recent records are also transmitted in the context.
context['students'] = Student.objects.order_by('-pk')[:5]
In the template, the first five records are displayed on top and a form is displayed below to fill out.
forms.py
from django.forms import ModelForm
from .models import Student
class StForm(ModelForm):
class Meta:
model = Student
fields = '__all__'
views.py
from .models import Student
from django.views.generic.edit import CreateView
from django.urls import reverse_lazy
from .forms import StForm
class EditStudent(CreateView):
template_name = 'bboard/editstudent.html'
form_class = StForm
success_url = reverse_lazy('student')
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
context['students'] = Student.objects.order_by('-pk')[:5]
return context
urls.py
from django.urls import path
from .views import *
urlpatterns = [
path('student/', EditStudent.as_view(), name='student'),
]
editstudent.html
<h4>
{% for aaa in students %}
<p>{{ aaa }}</p>
{% endfor %}
</h4>
<h2>form</h2>
<form method="post" action="{% url 'student' %}">
{% csrf_token %}
{{ form.as_p }}
<input type="submit" value="adding">
</form>

Django - TypeError __init__() missing 1 required positional argument when uploading a file

I want to set an initial value "test" to the field name when I'm uploading a file with a Django. Here is what I tried in views.py:
class UploadFile(CreateView):
form_class = UploadFileForm
template_name = "tool/upload.html"
success_url = reverse_lazy('tool:index')
fields = ['file',]
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})
And in forms.py:
class UploadFileForm(forms.ModelForm):
class Meta:
model = CheckFile
fields = ['file', ]
def __init__(self, file, *args, **kwargs):
file = kwargs.pop('file')
super(UploadFileForm, self).__init__(*args, **kwargs)
if file:
self.fields['name'] = "test"
But I end up having the following error: TypeError: UploadFileForm.__init__() missing 1 required positional argument: 'file'
I don't understand why I keep having this error. Could you please help me?
Thanks!
Edit : here's the HTML form.
{% extends 'base.html' %}
{% block content %}
<h1>Enregistrer les tarifs</h1>
<form method="POST">
<p>
{% csrf_token %}
{{ form.as_p }}
</p>
<button type="submit">Save</button>
</form>
{% endblock %}
You are doing too much, the file = kwargs.pop('file') makes no sense: the data is passed as request.FILES and is passed to the ModelForm, your ModelForm can thus look like:
class UploadFileForm(forms.ModelForm):
class Meta:
model = CheckFile
fields = ['file', ]
# no __init__
The same for your view: Django will automatically create the form and pass the data accordingly. If you want to specify the name of the CheckFile, you can do that in the form_valid method:
class UploadFileView(CreateView):
form_class = UploadFileForm
template_name = "tool/upload.html"
success_url = reverse_lazy('tool:index')
def form_valid(self, form):
form.instance.name = 'test'
return super().form_valid(form)
If you are submitting files, you should specify enctype="multipart/form-data":
<form method="POST" enctype="multipart/form-data">
<p>
{% csrf_token %}
{{ form.as_p }}
</p>
<button type="submit">Save</button>
</form>
and that's all that is necessary.

How to get user object using username in django template

I am trying to get user's profile picture in a template using their username. What I have tried:
templatetags/users_extras.py:
from django import template
from django.contrib.auth.models import User
register = template.Library()
#register.filter(name="get_user", is_safe=True)
def get_user(username):
return User.objects.filter(username=username).first()
My template:
{% load users_extras %}
<img src="{{ username|get_user.profile.image.url }}">
My Profile view:
class Profile(ListView):
model = Post
template_name = "users/profile.html"
context_object_name = 'posts'
ordering = ['-datePosted']
def get_queryset(self):
user = get_object_or_404(User, username=self.kwargs.get('username'))
return Post.objects.filter(author=user).order_by('-datePosted')
def get_context_data(self, **kwargs):
context = super(Profile, self).get_context_data(**kwargs)
context['username'] = self.kwargs['username']
return context
The url for profile page is like path('profile/<str:username>/', Profile.as_view(), name='profile')
But that gives error
Could not parse the remainder: '.profile.image.url' from 'username|get_user.profile.image.url'
How can I fix this error or how can I get user object using username in django template?
You may need to get the result of the filter in a variable.
{% load users_extras %}
{% with username|get_user as user %}
<img src="{{ user.profile.image.url }}">
{% endwith %}
No need for solving things in template. First it is a bad practive. Second there's a better way. Just edit the function get_context_data
def get_context_data(self, **kwargs):
context = super(Profile, self).get_context_data(**kwargs)
context['user_requested'] = get_object_or_404(User,
username=self.kwargs.get('username'))
return context

form.is_valid() is returning False when using ModelForm

I am creating a form using ModelForm to let the users upload a file along with a description . The is_valid() function isn't returning true and I am really confused. I have searched and there are many questions with same title as mine but they don't solve my problem.
here is forms.py:
class PostForm(forms.ModelForm):
document = forms.FileField(widget=forms.FileInput)
class Meta:
model = FeedModel
fields = ['description', 'document']
Here is models.py:
class FeedModel(models.Model):
description = models.CharField(max_length=255, blank=True)
document = models.FileField()
like = models.IntegerField(default=0)
dateTime = models.DateTimeField(auto_now=True, auto_created=True)
user = models.ForeignKey(User, on_delete=models.CASCADE, default=0)
def get_absolute_url(self):
u=self.user
return reverse('home:feed',u.primary_key)
Here is views.py:
class PostView(CreateView):
form_class = PostForm
template_name = 'home/feedModel_form.html'
def get(self, request, *args, **kwargs):
form=self.form_class(None)
return render(request, self.template_name, {'form':form })
def post(self, request, *args, **kwargs):
logger = logging.getLogger(__name__)
form=self.form_class(request.POST)
if form.is_valid():
user=request.user
self.object=form.save(commit=False)
self.object.user=user
self.object.save()
logger.error("voila")
redirect({'home:feed'}, user.id)
return render(request, self.template_name, {'form':form })
def feedview(request, user_id):
user = User.objects.get(pk=user_id)
return render(request, 'home/feed.html', {'user': user})
Here is feedModel_form.html:
{% extends 'home/navbar.html' %}
{% block body %}
<div class="form">
<form action="" method="post" enctype="multipart/form-data">
{% csrf_token %}
{% include 'home/form.html' %}
<button type="submit" class="button button-block" `
name="reg_btn">Post</button>`
</form>
</div>
{% endblock %}
Here is form.html:
{% for field in form %}
<div class="field-wrap">
<label>
{{ field.label_tag }}<span class="req">*</span>
</label>
<div>{{ field }}</div>
</div>
{% endfor %}
To see why the form isn't valid, you should check form.errors.
One error will be because you have not passed request.FILES to the form.
form=self.form_class(request.POST, request.FILES)
There may be other errors as well. If you used {{ form }} in your template, Django would include the errors automatically. Since you are rendering the fields manually, it's up to you to include the errors.
The key problem here is that you have overridden post. That means that you're missing out on lots of the code from CreateView.
In your case, it looks like you could remove the post method, and simply override form_valid instead.
def form_valid(self, form):
self.object=form.save(commit=False)
self.object.user=user
self.object.save()
# Note that you had {'home:feed'} here which was incorrect
return redirect('home:feed', user_id)
Your document field expects an uploaded file and is required. In order for the form to actually get the file, you have to also pass it the uploaded file in views.py:
form = self.form_class(data=request.POST, files=request.FILES)

Forbidden (403) CSRF verification failed. Request aborted.in Django

Why does Django show this error: 'Forbidden (403)CSRF verification failed. Request aborted.' when I already have {% csrf_token %} in the form.
templates/core/signup.html
{% block content %}
<form method="post">
{% csrf_token %}
{{ form.as_p }}
<button type="submit">Sign up</button>
</form>
{% endblock %}
views.py
from django.contrib.auth.forms import UserCreationForm
from django.views.generic.edit import CreateView
class SignUpView(CreateView):
template_name = 'core/signup.html'
form_class = UserCreationForm
Since you are already passing on the csrf token from django.core.context_processors.csrf to the context manager. Check whether the form HTML has something like this or not:
<input type='hidden' name='csrfmiddlewaretoken' value="jqhdwjavwjagjzbefjwdjqlkkop2j3ofje" />
A couple of other things are required to make the csrf protection work (check out the docs):
Your browser has to accept cookies from your server
Make sure you have 'django.middleware.csrf.CsrfViewMiddleware' included as middleware in your settings.py (alternatively use the decorator csrf_protect() on particular views you want to protect)
In your views.py you need to pass the RequestContext in your render_to_response for the context processors to actually be run.
from django.template import RequestContext
context = {}
return render_to_response('my_template.html',
context,
context_instance=RequestContext(request))
the new render shortcut (django 1.3+) will do it for you:
from django.shortcuts import render
context = {}
return render(request, 'my_template.html', context)
For class-based view:
class MyFormView(View):
form_class = MyForm
initial = {'key': 'value'}
template_name = 'form_template.html'
def post(self, request, *args, **kwargs):
form = self.form_class(request.POST)
if form.is_valid():
# <process form cleaned data>
return HttpResponseRedirect('/success/')
return render(request, self.template_name, {'form': form})

Categories

Resources