After logging in, my users complete a four forms and a pdf is generated containing the data from the forms. I can successfully do this and save the pdf, but dont know how to attach the generated pdf to the user. I usually save form data in an if request.method == 'POST': statement in the view.py file, but the pdf isnt being sent through POST, it is instead generated and saved within a function called after if request.method == 'POST': so I guess i need a way to attach it to the users pdf model within that function?
Also, the questionnaire is quite large so I broke it into four separate forms and four seperate models each with a one-to-one relationship with the user. Is this good practice or should I create one large model and break it up using four separate forms?
utils.py
def generate_questionnaire_pdf(request):
# get user
user = request.user
# create pdf
pdf = SimpleDocTemplate(settings.MEDIA_ROOT+'\pdfs\\questionnaire_pdfs\\user_%s.pdf' %user.id)
[..cont..]
pdf.build(elems, onFirstPage=partial(pageSetup, title=title, user=user), onLaterPages=pageSetup)
form.py
class QuestionnairePdfForm(forms.ModelForm):
class Meta:
model = QuestionnairePdf
fields = ['questionnaire_pdf']
model.py
class QuestionnairePdf(models.Model):
user = models.OneToOneField(User, on_delete=models.CASCADE)
questionnaire_pdf = models.FileField(upload_to='pdfs\\questionnaire_pdfs')
view.py
def final_question(request):
if request.method == 'POST':
form = FinalQuestionForm(request.POST, request.FILES, instance=request.user.finalquestion)
if form.is_valid():
form.save()
# generate pdf containing all answers to questionnaire
utils.generate_questionnaire_pdf(request)
Thank you.
Related
I am building a BlogApp App and I have two different sections, One is Blog Section and another is Article Section.
AND i am trying to create two different profiles for them.
When a user register or signup then a Profile is successfully creating for Blog Section ( NOT Article section ). BUT i am trying to do :- When user click on Article section after signup then there will be option of creating another Profile for Article Section and both will be different profile. ( AND there will be no relation between Blog Profile and Article Profile BUT user will same )
Blog Profile is successfully creating BUT I am trying to make Article Profile.
models.py
class ArticleProfile(models.Model):
user = models.ForeignKey(User,default='',null=True,on_delete=models.CASCADE)
full_name = models.CharField(max_length=30,default='')
views.py
def create_profile(request):
if request.method == 'POST':
form = ArticleProfileForm(request.POST,request.FILES,instance=request.user)
if form.is_valid():
custom_form = form.save(False)
custom_form.save()
messages.success(request, "Article Profile is Created")
return redirect('dating:DatingSection')
else:
form = ArticleProfileForm(instance=request.user)
context = {'form':form}
return render(request, 'dating/create_profile.html', context)
BUT when i create profile using this form then it is not saving in Admin.
Any help would be Appreciated.
Thank You in Advance.
I think the problem is here:
form = ArticleProfileForm(request.POST,request.FILES,instance=request.user)
^^^^^^^^^^^^
You are passing User as instance where the ArticleProfileForm creates ArticleProfile instance. So you need to remove that part of the code. And update the code like this:
form = ArticleProfileForm(request.POST,request.FILES)
if form.is_valid():
custom_form = form.save(False)
custom_form.user = request.user # change here
custom_form.save()
If still the problem persists, try renderning the form errors to pin point what is exactly wrong here.
I am working on a webcomics platform, and I need to allow users to upload multiple images in one post.
Ideally - keep it as simple as possible, so that a person wouldn't have to refresh the page to upload each image, or create and save a post before adding images.
If a user could delete or reorder images it would be nice.
Also, I need to make it scalable, so that I wouldn't have problems with it later.
Can you give me advice on how to do it properly?
Should images have their own model, and be connected to the post with foreign key? (not sure if this makes sense, seems kinda ugly)
Or should I just keep a list of image urls in the some type of field on a post model, and then create some sort of cdn and upload it there?
Any advice is really appreciated.
If you're talking about scale then you need to figure out what the best practice is for serving images.
I would recommend that you use S3 to serve your static files (this will include your user-uploaded files too). Follow this tutorial which shows you how to set this up from scratch.
Now, digging into your schema, you will need both a Post and PostImage model:
models.py:
class Post(models.Model):
title = models.CharField(max_length=200)
slug = models.SlugField(max_length=50)
body = models.TextField()
class PostImage(models.Model):
image = models.ImageField(
upload_to='<path_from_s3_tutorial>'
)
width_x = models.IntegerField()
width_y = models.IntegerField()
# Foreign Key to Post
post = models.ForeignKey('Post', null=True, blank=True)
Then when you will need to create a class in forms.py that uses an Inline Formset which allows you to upload multiple images when you create a post, as below:
>>> from myapp.models import Post, PostImage
>>> from django.forms import inlineformset_factory
>>>
>>> PostImageFormSet = inlineformset_factory(Post, PostImage, fields=('image',))
>>> post = Post.objects.get(id=13)
>>> formset = PostImageFormSet(instance=post)
You will then validate your formset in your view like so:
views.py
def create_post(request, post_id):
post = Post.objects.get(pk=post_id)
PostImageInlineFormSet = inlineformset_factory(Post, PostImage, fields=('image',))
if request.method == "POST":
formset = PostImageFormSet(request.POST, request.FILES, instance=post)
if formset.is_valid():
formset.save()
return redirect('index')
else:
formset = PostImageFormSet(instance=post)
return render(request, 'manage_books.html', {'formset': formset})
Note: Most of this example was modified from the one in the Django docs which I linked above.
I'm new here and also new to Django and any kind of web development.
Right now, I am working on a project that allows users to submit academic papers to be edited by other users.
The problem I am having is that I would like to allow users to upload a file and with that file, upload some data about the file (meta data?) such as the title of the paper (listed as titleField) prompt, etc.
I have been able to find answers on how to only upload the file, but not on how to upload the data and the file as a whole package.
If anyone can shed any light on this, that would help me a lot!
Here is the models.py:
from django.db import models
class Document(models.Model):
docfile = models.FileField(upload_to='documents/%Y/%m/%d')
titleField = models.CharField(max_length=100, default="")
dueDateField = models.IntegerField(default=10)
classNumField = models.IntegerField(default=0)
promptField = models.CharField(max_length=300, default="")
And below is the function that uploads the file. I understand how this section works, however it is uploading the additonal data from the forms that confuses me:
views.py
def list(request):
# Handle file upload
if request.method == 'POST':
form = DocumentForm(request.POST, request.FILES)
if form.is_valid():
newdoc = Document(docfile = request.FILES['docfile'])
newdoc.save()
# Redirect to the document list after POST
return HttpResponseRedirect(reverse('ReadMyPaper.myapp.views.list'))
else:
form = DocumentForm() # A empty, unbound form
# Load documents for the list page
documents = Document.objects.all()
# Render list page with the documents and the form
return render_to_response(
'myapp/list.html',
{'documents': documents, 'form': form},
context_instance=RequestContext(request)
)
Are you using a ModelForm ? If no, thats how to create one:
# forms.py
from django import forms
from .models import Document
class DocumentForm(forms.ModelForm):
class Meta:
model = Document
And in both cases, how to properly use it:
# views.py
from .forms import DocumentForm
def document_list(request):
# Handle file upload
if request.method == 'POST':
form = DocumentForm(request.POST, request.FILES)
if form.is_valid():
new_doc = form.save()
# Redirect to the document list after POST
return HttpResponseRedirect(reverse('ReadMyPaper.myapp.views.list'))
else:
form = DocumentForm() # A empty, unbound form
# Load documents for the list page
documents = Document.objects.all()
# Render list page with the documents and the form
return render_to_response(
'myapp/list.html',
{'documents': documents, 'form': form},
context_instance=RequestContext(request)
)
First point : Django forms (the non-ModelForm ones) do two things:
they display their fields, and
they sanitize and validate their data.
So when using Djago forms, you shouldn't have to access request.POST (or request.GET in the rare cases you have a GET form) directly, only form.cleaned_data.
Second point: ModelForms also know
how to create their own fields based on the associated model (but you can restrict / override these fields manually) and
create or update a model instance based on their (validated) data.
So when using a ModelForm, you shouldn't even have to do anything with the model itself in your view (for the most common use cases at least).
I am new to Django. I have a custom form that uses forms.Modelform to create a custom form from my model. I have some data in my database already that I manually input for testing.
However, the user and course field shows up as dropdowns. But they do not have any data in the dropdown list. How can I have django to pull data from the database and display the information into each dropdown on my form?
models.py:
class Student(models.Model):
user = models.OneToOneField(User)
course = models.ForeignKey(Course)
view.py:
def home(request):
if request.method == 'GET':
form = StudentForm()
else:
form = StudentForm(request.POST)
if form.is_valid():
pass
return render(request, "request.html", {'form': form}, context_instance=RequestContext(request))
forms.py:
class StudentForm(forms.ModelForm):
class Meta:
model = Student
Update
Actually found out that the changes weren't saved to my DB. They are now loading into the form. However in the dropdown list, it is showing up as "Student Object", and "Course Object"
How can I make it so they show up with proper names?
I would advocate that you move away from doing this if this is testing, and instead follow the guidelines for testing as outlined in the django tutorials, i.e. it creates a fake database for you and you create Users and Courses via Users.objects.create(username=...)
I am using a Django form for user signup, where the user is able to enter a coupon code. I want all characters entered in the coupon code field to be converted to lowercase. I've tried using .lower() in the save method, in a custom cleaning method, and in a custom validator, but am having no luck with those approaches. Below is my code.
class StripeSubscriptionSignupForm(forms.Form):
coupon = forms.CharField(max_length=30,
required=False,
validators=[validate_coupon],
label=mark_safe("<p class='signup_label'>Promo Code</p>")
def save(self, user):
try:
customer, created = Customer.get_or_create(user)
customer.update_card(self.cleaned_data["stripe_token"])
customer.subscribe(self.cleaned_data["plan"], self.cleaned_data["coupon"].lower())
except stripe.StripeError as e:
# handle error here
raise e
As mentioned above, I've also tried a cleaning method, but this doesn't work either:
def clean_coupon(self):
return self.cleaned_data['coupon'].lower()
The solution is to create a custom form field, which allows you to override the to_python method, in which the raw values from the form fields can then be modified.
class CouponField(forms.CharField):
def to_python(self, value):
return value.lower()
class StripeSubscriptionSignupForm(forms.Form):
coupon = CouponField(max_length=30,
required=False,
validators=[validate_coupon],
label=mark_safe("<p class='signup_label'>Promo Code</p>")
)
Try using a css text-transform with widget in your form like this:
class StripeSubscriptionSignupForm(forms.Form):
coupon = forms.CharField(max_length=30,
required=False,
validators=[validate_coupon],
label=mark_safe("<p class='signup_label'>Promo Code</p>")
widget=TextInput(attrs={'style': 'text-transform:lowercase;'})
)
I came across this problem myself when working on ensuring that the email field in the user model was only saved as lowercase. The advantage to the method I outline below is that you can control the formating of each field in the form - as against the selected answer above, which will convert all fields to lowercase regardless of whether you wish so or not.
The issue for me and I believe for the OP above is that the cleaned values are now indeed in lower case, however the HTML page (the one rendered after the validation and cleaning) shows the pre-cleaned value (i.e. still in uppercase), which would confuse the user. What is happening is that the the form field value is still as per initial data i.e. X#Y.com and the cleaned data is actually x#y.com .
After processing the submitted form:
>>>user_form.cleaned_data['email']
'x#y.com'
and
>>>user_form['email'].value()
'X#Y.com'
The template uses the user_form['email'].value() instead of the value provided by user_form.cleaned_data['email'], so the user thinks his email has been saved in the uppercase form whereas really it has been saved in lowercase.
In such cases, the simplest way to present the user_form back to the client with the cleaned fields appearing in the template is to just reload the saved form directly after saving. As per the following two examples (one saving to the database one not saving to the database).
forms.py
from django.contrib.auth.models import User
class UserForm(forms.ModelForm):
"""
UserForm is a simple form to allow a user to change his/her name and email.
"""
class Meta:
model = User
fields = ['first_name', 'last_name', 'email']
def clean_email(self):
"""
ensure that email is always lower case.
"""
return self.cleaned_data['email'].lower()
in views.py
def post(self, request):
user_form = UserForm(request.POST, instance=request.user)
if user_form.is_valid():
user_form.save() # using the provided save from Modelform in this case
user_form = UserForm(instance=request.user) # reload the amended user data
return render(request, 'myApp/user_details.html',{'user_form': user_form})
The key line here is in views.py,the user_form = UserForm(instance=request.user), where the form is reloaded. The effect here is to repopulate the form with the cleaned, (and in this case saved) data before it is presented to the user.
Now you can change every charfield in the form to lowercase by having the appropriate clean_fieldname call for those fields.
Note: if you are not interacting with a database (or just donĀ“t wish to reload from the database) you can repopulate the form as follows:
def post(self, request):
user_form = UserForm(request.POST) #gather the post'ed data
if user_form.is_valid():
user_form.process() # process the gathered cleaned data
user_form = UserForm(
{'email': user_form.cleaned_data['email'],
'first_name': user_form.cleaned_data['first_name'],
'last_name': user_form.cleaned_data['last_name'],}
) # reload the form
return render(request, 'myApp/user_details.html',{'user_form': user_form})
As a slight optimization here, you can use the built in check :
if user_form.has_changed():
following on from the is_valid() check (or in conjunction with it) -usually there is no need to save or process a form if nothing has changed on the form.