Convert my def view to class based view - python

I have this view in my app:
def contact(request):
form_class = ContactForm
if request.method == 'POST':
form = form_class(data=request.POST)
if form.is_valid():
contact_name = form.cleaned_data['contact_name']
contact_email = form.cleaned_data['contact_email']
contact_website = form.cleaned_data['contact_website']
contact_subject = form.cleaned_data['contact_subject']
form_content = form.cleaned_data['content']
template = get_template('contact/contact_template.txt')
context = Context({'contact_name': contact_name,
'contact_email': contact_email,
'contact_website': contact_website,
'contact_subject': contact_subject,
'form_content': form_content, })
content = template.render(context)
email = EmailMessage(
"New contact form submission",
content,
"www.inexistente.com" + '<support#inexistente.com>',
['mymail#gmail.com'],
headers={'Reply-To': contact_email}
)
email.send()
return redirect('/')
return render(request, 'contact/contact.html', {'form': form_class, })
I want to transform this to a class based view, I believe that is "more organized" for me...
What generic Django view to use?
Do you believe that is recommended to do this?
In the view, Is recommended use this code at the end to renew the form in case of not passing?
"else:
form = form_class()"
i was trying without that code and my form renews itself perfectly.
apologizeme in advance if I overlook something, any contribution is wellcome, Thanks for evaluate!

Since you have a view that displays a form and which redisplays the form with validation errors on error and redirects to a new URL on success, you can use FormView generic view.
Your FBV code converted to CBV:
from django.views.generic import FormView
class Contact(FormView):
form_class = ContactForm # Form class to be used
template_name = 'contact/contact.html' # Template to be used
success_url = '/' # Redirect to this url when form is valid
def form_valid(self, form):
template = get_template('contact/contact_template.txt')
context_dict = form.cleaned_data
context_dict['form_content'] = form.cleaned_data['content']
context = Context(context_dict)
content = template.render(context)
email = EmailMessage(
"New contact form submission",
content,
"www.inexistente.com" + '<support#inexistente.com>',
['mymail#gmail.com'],
headers={'Reply-To': contact_email}
)
email.send()
return super(Contact, self).form_valid(form)
Here,
form_class: defines the form class to be used.
template_name: defines the template to be used to display the form.
success_url: defines the url to be used when the form is valid.
You can put all the logic for the code to be executed when form is valid inside the form_valid() function. After performing all the operations, call the super() which redirects to the success_url defined in your class.
Also, when you are building context to be passed to the email template, you can use the form.cleaned_data dictionary. All the keys you have used to build the context dictionary is same as in the form's cleaned_data dictionary except the form_content key. So, i have just used the form's cleaned_data dictionary and added an extra key form_content in a context_dict dictionary which will be then used in the email template for rendering.

Related

When I pass a url parameter to modelform, None is passed instead of the url parameter

I am trying to build up a posting webpage.
This is how it works:
you click a button, the posting form will appear, you fill in the form, you click the submit button, and the process is complete. And when the form is submitted, a url parameter will be passed as the value of a hidden input in the modelform in the views.py.
However, when I browse the model in manage.py shell, None is saved instead of the url parameter.
Here are the codes:
models.py
from django.db import models
from django.db.models import CharField, TextField, DateField
class Post(models.Model):
username = CharField(max_length=30, blank=True, null=True)
content = TextField()
dt_created = DateField(auto_now_add=True)
dt_modified = DateField(auto_now=True)
def __str__(self):
return self.username
forms.py
from django import forms
from django.forms import Textarea, HiddenInput
from .models import Post
class PostForm(forms.ModelForm):
class Meta:
model = Post
fields = ['content', 'username']
widgets = {
'content': Textarea(attrs={
'class': 'write_input',
'placeholder': 'write your story here...'
}),
'username': HiddenInput(attrs={
'value': ' '
})
}
labels = {
'content': ''
}
urls.py
from django.urls import path, include
from . import views
urlpatterns = [
path('<str:username>/main/', views.account_main, name='account_main')
]
views.py
from django.shortcuts import render, redirect
from .forms import PostForm
from .models import Post
def account_main(request, username):
context = dict()
if request.method == 'POST':
form = PostForm(request.POST, initial={'username': username})
if form.is_valid():
form.save()
return redirect('account_main', username=username)
form = PostForm()
posts = Post.objects.all().order_by('dt_created')
context['username'] = username
context['form'] = form
context['posts'] = posts
return render(request, 'Account/account_main.html', context=context)
What I have tried:
Passing initial={'username': username} as kwargs to PostForm(),
Accessing cleaned_data and passing the url parameter as value like: form.cleaned_data['username'] = username
I could not find any solution for the issue in Google or Stack Overflow so far. Thank you in advacnce for your answer!!
I found the solution.
After form.is_valid() returns True, I save the form by form = form.save(commit=False).
Then, I pass the url parameter as the value for form.username. Finally, I save the form by form.save().
When I browse the model, the url parameter is saved well as the username value.
Here is the code after I modified it:
def account_main(request, username):
context = dict()
if request.method == 'POST':
form = PostForm(request.POST)
if form.is_valid():
form = form.save(commit=False)
form.username = username
form.save()
return redirect('account_main', username=username)
If your main motive is to pass a hidden field along with a form you can directly send without including it in the URL.
And you can get files by
-->request.POST.get(#fieldName)

Django: get current URL path to use in a form

I have been stuck on this for a while now. I need to extract the current domain name of the tenant in order to use as a parameter to upload data in this tenant schema.
I am struggling to make this work because of the structure of my view. This is what I have been able to do so far
forms.py
class ETL(forms.Form):
Historical = forms.FileField()
Pre_processing = forms.FileField()
Supplier = forms.FileField()
parameters = forms.FileField()
def process_data(self, request ,*args, **kwargs):
url = request.get_full_path()
print(url)
dbschema = remove_www(request.get_host().split(':')[0]).lower()
print(url)
fh = io.TextIOWrapper(self.cleaned_data['Historical'].file)
fpp = io.TextIOWrapper(self.cleaned_data['Pre_processing'].file)
fs = io.TextIOWrapper(self.cleaned_data['Supplier'].file)
fp = io.TextIOWrapper(self.cleaned_data['parameters'].file)
........
and my view.py
#method_decorator(login_required, name='dispatch')
class Getfiles(LoginRequiredMixin,FormView):
template_name = 'upload.html'
form_class = ETL
success_url = 'Home'
def form_valid(self, form):
form.process_data()
print('data_processed well')
return super().form_valid(form)
with this view format, I am struggling on how to pass the request.get_hosts() inside of the view. How can I can fix it?
Is this a proper way to get the schema name or is there a better way to get the tenant schema in the form?
UPDATE:
I have been able to modify my view, no error and it redirect to the right page but it does not process my data.
#method_decorator(login_required, name='dispatch')
class Getfiles(LoginRequiredMixin,FormView):
template_name = 'upload.html'
form_class = ETL
success_url = 'Home'
def gooView(request, form):
if form.is_valid():
url = request.get_full_path()
form.process_data()
#redirect = 'Home'
#return HttpResponseRedirect(redirect)
return super().form_valid(form)
else:
form = ETL()
context = {
'form': form
}
return render(request, 'upload.html', context)
Well, to pass the request.get_hosts(), you should have access to the request variable. They only possible way that I can find is for a class-based view to use it through the self object. For example, self.request.get_hosts().
Reference: https://docs.djangoproject.com/en/3.0/topics/class-based-views/generic-editing/
I hope that helps!

Prepopulate ModelForm fields based on referring URL

I have a website which catalogs local hikes. Users can "log" that they have completed these hikes. I have both of these models+forms working as intended. Right now, though, in order to log a hike, you have to select the hike from a long list which contains all the hikes in the database. I'd like to be able to pre-populate that field so that if you are coming from the detail page of the hike in question, then that field is filled in with the hike.
Here's some code:
models.py:
model Hike(models.Model):
name = CharField(max_length=255)
slug = models.SlugField(unique=True)
...other fields...
model UserLog(models.Model):
hike = models.ForeignKey(Hike, on_delete=models.CASCADE)
user = models.ForeignKey(User, on_delete=models.CASCADE)
forms.py:
class LogHike(forms.ModelForm):
class Meta:
model = UserLog
fields = ('hike', 'date', ... other fields)
views.py:
def hike_detail(request, slug):
hike = Hike.objects.get(slug=slug)
log = UserLog.objects.filter(hike__slug=slug)
... more stuff here ...
return render(request, 'hikes/hike_detail.html' {
'hike': hike,
'log': log,
})
def log_hike(request):
if request.method == "POST":
form = LogHike(request.POST)
if form.is_valid():
obj = form.save(commit=False)
userid = request.user
obj.user = request.user
obj.save()
return redirect('user_profile', uid=userid.id)
else:
form = LogHike()
return render(request, 'log_hike.html', {'form': form})
So if a user is viewing the "hike_detail" view, I want to have a link that sends them to the "log_hike" view, but with the "Hike" field pre-populated based on the "Hike" that they came from. I think it might have something to do with the instance function? But I don't have a ton of experience with it. Is there an easy way to pass the data from the referring page in order to pre-populate the form?
You probably want to override your ModelForm __init__ method:
def __init__(self, *args, **kwargs):
super(LogHike, self).__init__(*args, **kwargs)
if 'hike' in kwargs:
self.fields['hike'].value = kwargs['hike']
Now all you need is another view which accepts a parameter passed and you're set. Extend your urls.py for that and then do something like:
def log_hike_with_pre_set_hike(request, *args, **kwargs):
if request.method == 'POST':
# see your code
else:
form = LogHike(hike=kwargs['hike'])
return render(request, 'log_hike.html', {'form': form})
Untested code, you might have to adapt it, I come from class-based views so it might be different for you.
You can pre-populate that form in log_hike when the request.method is get in the same way as when in post.
form = LogHike({'hike':hike_id})
The other thing is form where you'll take the hike_id. But that can come from request.GET for example.

ImageField doesnt work

When i try to upload file it gives me template error, that its required to fill in. Code:
models:
class ahoja(models.Model):
image = models.ImageField(upload_to='smayat')
forms:
class ahojaForm(ModelForm):
class Meta:
model = ahoja
exclude = ()
view:
def testview(request):
if request.method == 'POST': # pokud form byl odeslan
form = ahojaForm(request.POST, request.FILES) # formular s daty
if form.is_valid():
form.save() #vytvoří událost
return HttpResponseRedirect('/hlavni_stranka/kalendar/')
else:
form = ahojaForm() # prázdný formulář
return render(request, 'hlavni_stranka/test.html', {'form': form,})
The first thing to check is the enctype attribute in your template. From the docs:
Note that request.FILES will only contain data if the request method was POST and the <form> that posted the request has the attribute enctype="multipart/form-data". Otherwise, request.FILES will be empty.

django form default to ImageField for rendering

I have the following Django form:
class PageForm(forms.Form):
title = forms.CharField(max_length=50)
image = forms.ImageField(required=False)
content = forms.CharField(widget=forms.Textarea(attrs={'cols':20, 'rows':10}))
I'm using this to create new pages from a given template. But now I want to also add edit possibility, so I would like to use the form to render the same template only with some default values which are retrived from a page id. This is what I have:
page_to_edit = Page.objects.filter(id=page_id)[0] // Get page from model
title = page_to_edit.title
content = page_to_edit.content
picture = page_to_edit.picture.order_by('?')[0].file // Here file is a models.ImageField
initial_data = {'title' : title, 'content' : content, 'image' : picture}
form = PageForm(initial_data)
// Finally return this form to template
Now this works as I want for title and content, and those are properly rendered in template with initial values, but the ImageField is just empty. I've also tried passing picture.url instead of picture but no change.
Any help would be appreciated.
All the best
I would approach this the following way:
You can use .get() to retrieve a single record, Page.objects.get(pk=page_id), instead of .filter() which returns a queryset. There is also a shortcut get_object_or_404 that takes a common pattern of wrapping a .get() into a try..except block for you. If the model is not found, an HTTP 404 page is returned instead.
Use a ModelForm instead
A ModelForm accepts an instance parameter of an existing model so you don't need to set initial values.
With these things in mind your code would end up looking something like this:
# forms.py
from django import forms
class PageForm(forms.ModelForm):
class Meta:
model = Page
fields = ('title', 'image', 'content')
# views.py
from django.shortcuts import render, get_object_or_404
def edit_page(request, page_id):
page = get_object_or_404(Page, pk=page_id)
if request.method == 'POST':
form = PageForm(instance=page, request.POST)
if form.is_valid():
form.save()
else:
form = PageForm(instance=page)
return render(request, 'some_template.html', {'form': form})
def create_page(request):
if request.method == 'POST':
form = PageForm(request.POST)
if form.is_valid():
form.save()
else:
form = PageForm()
return render(request, 'some_template.html', {'form': form})
# urls.py
(r'^page/create/$', views.create_page, 'create_page'),
(r'^page/edit/(?P<page_id>\d+)/$', views.edit_page, 'edit_page'),

Categories

Resources