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!
Related
I am a beginner and I am creating a forum using html, css, bootstrap, python and django. I created a view for deleting posts:
class DeletePost(DeleteView):
model = Post
success_url = '/'
def get_queryset(self):
queryset = super().get_queryset()
return queryset.filter(author_post_id=self.request.user.id)
When a user will click the "Confirm button", when he need to remove a post, i would like to redirect him to the same discussion's page in which there was the post that he deleted, but i don't know how.
Can somebody help? Thanks in advance.
Post model:
class Post(models.Model):
post_author = ForeignKey(User, on_delete=models.CASCADE, related_name='posts')
content = models.TextField(default="Your content here...")
creation_date = DateTimeField(auto_now_add=True)
discussion = ForeignKey(Discussion, on_delete=models.CASCADE)
def __str__(self):
return self.post_author.username
class Meta:
verbose_name = 'Post'
verbose_name_plural = 'Posts'
Urls:
Discussion's url:
path('discussion/<int:pk>', views.view_discussion, name='view_discussion')
DeleteView's url:
path('discussion/<int:id>/delete_post/<int:pk>/', views.DeletePost.as_view(), name='delete_post')
You can override the get_success_url with:
class DeletePost(DeleteView):
model = Post
def get_queryset(self):
return super().get_queryset().filter(
author_post_id=self.request.user.id
)
def get_success_url(self):
return reverse('view_discussion', kwargs={'pk': self.object.discussion_id})
You can use the 'redirect' method in Django.
First import it: from django.shortcuts import redirect
then write this one line of code : return redirect('/nameOfURL') under your class/function based views.
Update :
def delete_post(request, id):
if request.method == 'POST':
pi = Post.objects.get(pk=id)
pi.delete()
return redirect('/view_discussion')
I would like to create a mutli-step form in Django that only submits the data for processing at the end of all the steps. Each step needs to be able to access and display data that we entered in previous step(s).
Is there a way to do this with Django? Django's Form-Wizard can't handle this basic functionality.
Of course there's a way to do this in Django.
One way is to hold your values in session until you submit them at the end. You can populate your forms using values held in session if you return to previous step.
With some searching, you may find an app that someone has already written that will do what you want, but doing what you need isn't hard to do with Django, or any other framework.
Example, ignoring import statements:
#models/forms
class Person(models.Model):
fn = models.CharField(max_length=40)
class Pet(models.Model):
owner = models.ForeignKey(Person)
name = models.CharField(max_length=40)
class PersonForm(forms.ModelForm):
class Meta:
model = Person
class PetForm(forms.ModelForm):
class Meta:
model = Pet
exclude = ('owner',)
#views
def step1(request):
initial={'fn': request.session.get('fn', None)}
form = PersonForm(request.POST or None, initial=initial)
if request.method == 'POST':
if form.is_valid():
request.session['fn'] = form.cleaned_data['fn']
return HttpResponseRedirect(reverse('step2'))
return render(request, 'step1.html', {'form': form})
def step2(request):
form = PetForm(request.POST or None)
if request.method == 'POST':
if form.is_valid():
pet = form.save(commit=False)
person = Person.objects.create(fn=request.session['fn'])
pet.owner = person
pet.save()
return HttpResponseRedirect(reverse('finished'))
return render(request, 'step2.html', {'form': form})
We'll assume that step2.html has a link to go back to step1.html.
You'll notice in the step1 view I'm pulling the value for fn from session that was set when the form was saved. You would need to persist the values from all previous steps into the session. At the end of the steps, grab the values, create your objects and redirect to a finished view, whatever that might be.
None of this code has been tested, but it should get you going.
You can easily do this with the form wizard of django-formtools. A simple example would be something like the following.
forms.py
from django import forms
class ContactForm1(forms.Form):
subject = forms.CharField(max_length=100)
sender = forms.EmailField()
class ContactForm2(forms.Form):
message = forms.CharField(widget=forms.Textarea)
views.py
from django.shortcuts import redirect
from formtools.wizard.views import SessionWizardView
class ContactWizard(SessionWizardView):
def done(self, form_list, **kwargs):
do_something_with_the_form_data(form_list)
return redirect('/page-to-redirect-to-when-done/')
urls.py
from django.conf.urls import url
from forms import ContactForm1, ContactForm2
from views import ContactWizard
urlpatterns = [
url(r'^contact/$', ContactWizard.as_view([ContactForm1, ContactForm2])),
]
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.
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.
Edit:
I want the 'success_url' (ie, result.html) to display the 'data' from 'form.process()'. The following code obviously doesn't work.
Can anyone please tell me what's wrong with it or suggest another way to basically view the context 'data' in a template (either in the form of list or dict), ie a better way to display data to the user after a form has been submitted.
Many thanks in advance.
-- urls.py --
url(r'^$', view='main_view'),
url(r'^result/$', view='result_view'),
-- views.py --
class ResultView(TemplateView):
template_name = "result.html"
class MainView(FormView):
template_name = 'index.html'
form_class = UserInputForm
success_url = 'result/'
def form_valid(self, form):
data = form.process()
return super(MainView, self).form_valid(form)
def get_context_data(self, **kwargs):
context = super(MainView, self).get_context_data(**kwargs)
context['data'] = data
return context
main_view = MainView.as_view()
result_view = ResultView.as_view()
As far as I understood your question, you want to show the contents of the user submitted form in the result view. Is that correct?
In this case the method get_context_data won't help you at all, because it will only store data in the current context which is in MainView.
The form_valid method of FormView will make a HttpResponseRedirect to the success_url. So the question now is, how can we give the data to this view.
As explained in Django return redirect() with parameters the easiest way would be to put the data into the session. In the result.html-template you could then access this data as explained in Django: accessing session variables from within a template?
Here is the code:
class ResultView(TemplateView):
template_name = "result.html"
class MainView(FormView):
template_name = 'index.html'
form_class = UserInputForm
success_url = 'result/'
def form_valid(self, form):
self.request.session['temp_data'] = form.cleaned_data
return super(MainView, self).form_valid(form)
in the result.html template you could then access this temp_data so:
{{ request.session.temp_data }}
As suggested above, you can override get_context_data.
For example, you can do something like the below:
def get_context_data(self, **kwargs):
context = super(MainView, self).get_context_data(**kwargs)
#set some more context below.
context['foo'] = bar
...
return context
Look for get_context_data in context the Django class-based view docs. The dict returned by the overridden method will be passed into the templates.
There are a couple of things that could be your problem. First, in form_valid() method, you process the form before you call that class' parent form_valid(). Also, you're no storing the result in a common place for both methods to grab it. Try something like:
def form_valid(self, form):
self.data = form.cleaned_data
return super(MainView, self).form_valid(form)
def get_context_data(self, **kwargs):
context = super(MainView, self).get_context_data(**kwargs)
context['data'] = self.data
return context