Django, passing data through a view context, preferred storage method - python

I'm trying to pass some data through a django context and am finding it kind of cumbersome. I'm very new to Python and a bit unfamiliar with storing data, I have a few suggestions here shown in the code:
1. A form to pass data:
def formview(request):
if request.method == 'POST':
form=LogonForm(request.POST)
if form.is_valid():
request.session['firstname']=form.cleaned_data['entrykey']
request.session['lastname']=form.cleaned_data['firstfield']
request.session['age']=form.cleaned_data['secondfield']
request.session['location']=form.cleaned_data['thirdfield']
return HttpResponseRedirect('thanks')
else:
form=LogonForm()
return render(request, 'logon/form.html', {'form': form})
A view which reacts to the submitted data, but not from database:
def thanksforform(request):
try:
#Using class
class thanksclass():
firstname=request.session['firstname']
lastname=request.session['lastname']
age=request.session['age']
location=request.session['location']
under18='Come back in %s years' % str(18-age)
over18='Step right up!'
#Using array
data=np.empty(6, dtype=object)
data[0]=request.session['firstname'] #etc. etc. ect.
#using list
listdata=[request.session['firstname']] #etc etc etc
except KeyError:
return HttpResponseRedirect('/logon/')
request.session.flush()
return render(request, 'logon/thanks.html', {'thanksclass': thanksclass})
Which type of object is preferred in Django for this kind of purpose, is there a better way to pass data through the view context?
PS. Please disregard the source being session data, It's just an example as I was messing around, I'm aware that you can call session data directly from the template aswell.

For myself, depends on how I'm retrieving/creating the data.
In general forms are a nice way to do it if you want to have some validation or allow the user to submit data or if you're representing something from the ORM but Django's templates accept a lot of data types.
Otherwise I'd recommend creating a dictionary and setting content equal to it. I.E.
varOne = '1'
varTwo = 'Two'
varThree = 3.0
myPassThrougData =
{'variableOne': varOne, 'variableTwo': varTwo, 'VariableThree':
varThree }
return render(request, 'logon/form.html', {'form': form}, content=myPassThoughData)

Related

Pass a variable to another function and render an html template at the same time in django

We want to access the same variable in every function inside our views.py. Since it is not constant, we cannot use it as a global variable.
Is it possible to pass a variable to another function while also rendering an HTML template? What are the alternatives if none exist?
This is our login function in views.py
def loginpage(request):
errorMessage = ''
# Applicant Login
if request.method=="POST":
if request.POST.get('username') and request.POST.get('pwd'):
try:
currentUser=Applicant.objects.get(username=request.POST['username'],pwd=request.POST['pwd'])
currentUser=Applicant.objects.get(username=request.POST['username'])
first = currentUser.firstname
middle = currentUser.middleinitial
last = currentUser.lastname
AppDashboard = ApplicantDashboardPageView(currentUser, request)
except Applicant.DoesNotExist as e:
errorMessage = 'Invalid username/password!'
return render(request, 'home.html')
The currentUser variable inside our login function is the variable we want to pass in this function
def ApplicantdashboardPageView(currentUser, request):
appPeriod = ApplicationPeriod.objects.all()
exam = ExaminationSchedule.objects.all()
posts = Post.objects.all().order_by('-created_on')
form = PostForm()
name=userNaCurrent
print('from storeCurrentUser', name)
if request.method == "GET":
try:
posts = Post.objects.all().order_by('-created_on')
form = PostForm()
#applicantID=currentUser.id
#applicantNotification = Applicant.objects.get(id=applicantID)
return render(request, 'applicantdashboard.html', context={'UserName' : name, 'posts':posts, 'appPeriod':appPeriod, 'exam':exam})
except ObjectDoesNotExist:
return render(request, 'applicantdashboard.html', context={'UserName' : name, 'posts':posts,})
return render(request, 'applicantdashboard.html', context={'UserName' : name, 'posts':posts, 'appPeriod':appPeriod, 'exam':exam})
I am new to Django so please bear with me if my question seem too basic. Thank you
Store raw user password is a very big flaw in security. Please read more about Django Authentication system https://docs.djangoproject.com/en/4.1/topics/auth/
Basically, to store critical confidential information like passwords you need to at least, encrypt it. But for passwords you don't need to see the raw value of it, isn't it? Therefore, you just need to hash it and compare it every time you need to authenticate the user. Read more here Best way to store password in database
Django Auth system will also help to solve the issue by injecting the current user into a "global" request object so that you can access it everywhere.
You can do the same by keeping those 2 methods in a class and accessing variables by creating objects for it.

How to remove built-in errorlist of Django model forms?

I made a model form in Django that enables user to create an instance of that model. All is well save one thing. Built-in error lists of Django is annoying. I want those errors to show itself when user actually made that error. When I open my page it looks like this
Please help me how do I remove these errorlist temporarily so that when user left input fields empty. It pop ups itself?
I don't know if you need these codes to solve this problem, but here it is:
views.py file here
#login_required(login_url='/accounts/login/')
def article_create(request):
article_form = ArticleForm(request.POST or None, request.FILES)
if article_form.is_valid():
instance = article_form.save(commit=False)
instance.author = request.user
article_form.save()
return render(request, 'blog/article-create.html', {'form': article_form})
Thank you
You use the request.POST or None idiom - which I dislike, but never mind - for the data parameter, but not for the files parameter. Since you pass an (empty) dict for the files, Django takes your form as bound, and therefore tries to validate it.
If you insist on using this idiom, you need to do it for both:
article_form = ArticleForm(request.POST or None, request.FILES or None)
But really, it's much more Pythonic to be explicit:
if request.method == 'POST':
article_form = ArticleForm(request.POST, request.FILES)
if article_form.is_valid():
instance = article_form.save(commit=False)
instance.author = request.user
article_form.save()
return redirect('/')
else:
article_form = ArticleForm()
return render(request, 'blog/article-create.html', {'form': article_form})
Note, you always need to redirect after a successful POST, as I have done above.

Django file field update causing error even though not required

I have an app that serves to update certain fields of a model. There are 4 possible fields that could be updated: resolution, upload4, upload5, and upload6. The upload fields are NOT required. If I do not include the request.FILES line, the uploaded file will not be saved to the database, but it seems like because I've included it, I need to always upload the 3 files, even though they are not required. The exception I am getting is "MultiValueDictKeyError" on the POST. How can I fix this? I want the option to add 3 files, but I don't want to have to every time. I understand how to make a field not required, I don't know how to code the request.FILES to understand that it is not required.
views.py
#login_required(login_url='/login/')
def report(request, case_id):
form = ReportForm()
case = get_object_or_404(Incident, pk=case_id)
# if this is a POST request we need to process the form data
if request.POST:
# create a form instance and populate it with the data from the request:
form = ReportForm(request.POST)
if form.is_valid():
resolution = (form.cleaned_data['resolution']) # grabbing action_taken from user input
case.resolution = resolution
case.upload4 = request.FILES['upload4']
case.upload5 = request.FILES['upload5']
case.upload6 = request.FILES['upload6']
case.status = Status.objects.get(status='closed')
case.save(update_fields=['resolution', 'status', 'upload4', 'upload5', 'upload6'])
context = { 'case': case,
'form': form}
return HttpResponseRedirect(reverse('dashboard_app:dashboard'))
template = "report.html"
#form = CaseForm()
context = { 'case': case,
'form': form}
return render(request, template, context)
The point is that you are ignoring the validation that form does, and going straight back to the data from the request. So, yes, that will break if the forms are not there. But this is exactly why we use forms.
case.upload4 = form.cleaned_data['upload4']
etc.
It would be even easier if you used a ModelForm; then you could pass case as the instance argument of the form, and just do form.save(), replacing almost all the code inside your is_valid block.
This will solve the problem.
case.upload4 = request.FILES.get('upload4')
case.upload5 = request.FILES.get('upload5')
case.upload6 = request.FILES.get('upload6')

Django form returns is_valid() = False and no errors

I have simple view in django app, which I want to show only when one of the forms is valid. I have something like:
#login_required
#require_role('admin')
def new_package(request):
invoicing_data_form = InvoicingDataForm(instance=request.user.account.company.invoicingdata)
if invoicing_data_form.is_valid():
# all here
return HttpResponse('Form valid')
else:
logger.info("Form invalid")
return HttpResponse(json.dumps(invoicing_data_form.errors)
I always get log info message that form is invalid, however, I get nothing in
invoicing_data_form.errors
It is very strange, because I am validating this form in other view using user input data and it works just fine. Any idea?
EDIT:
Just for clarification.
I am not requesting any data from user in this form.
I am using this form to validate some model instance (this form is subclassing from ModelForm).
That's because you're not "feeding" your form.
Do this:
invoicing_data_form = InvoicingDataForm(instance=invoice, data=request.POST or None)
You have an unbound form.
https://docs.djangoproject.com/en/1.7/ref/forms/api/#bound-and-unbound-forms
A Form instance is either bound to a set of data, or unbound.
If it’s bound to a set of data, it’s capable of validating that data and rendering the form as HTML with the data displayed in the HTML.
If it’s unbound, it cannot do validation (because there’s no data to validate!), but it can still render the blank form as HTML.
To bind data to a form, pass the data as a dictionary as the first parameter to your Form class constructor:
invoicing_data_form = InvoicingDataForm(request.POST or None, instance=invoice)
If you're already giving request.POST to your form using request.POST or None, but it's still invalid without errors, check that there isn't any redirect going on. A redirect loses your POST data and your form will be invalid with no errors because it's unbound.
I got this for AuthenticationForm which needs AuthenticationForm(None, request.POST) see Using AuthenticationForm in Django
I want to expand on the answer by #yuji-tomita-tomita
I typically use a CBV approach in Django, and how I'm handling forms:
def post(self, request, *args, **kwargs):
form = self.get_form()
if form.is_valid():
# do things
Reading the source code I noticed that self.get_form() using get_form_kwargs(self) to populate the form with request.POST, thus getting bound to data. So if you're overloading it like I did:
def get_form_kwargs(self):
company = self.get_company()
return {"company": company}
Make sure to call the super(), and it will finally work:
def get_form_kwargs(self):
company = self.get_company()
kwargs = super().get_form_kwargs()
kwargs.update({"company": company})
return kwargs

Retrieve Current User in Django Outside Template

Currently I have a form that was built using the form wizard, the form is processed using a separate script that I wrote. I need to pass the current user (user currently logged in) to this script so that I can run an insert query to my database. Any suggestions on how to do this?
class QuestionWizard(SessionWizardView):
def done(self, form_list, **kwargs):
import process_form
userID = request.user.id
result = process_form.main(form_list,userID)
return render_to_response('done.html', {
#'form_data': [form.cleaned_data for form in form_list],
'data_return': result[0],
})
I believe the form wizard done function only accepts two variables.
It turns out it was a lot simpler than I anticipated. Inside of the done function I added the following:
user_id = self.request.user.id
And then passed the user_id into the process_form function.
Annoying that I overlooked it, but glad that I figured it out.

Categories