django image upload help - django

I have a template where the user can input data about himself, and upload his photo. Photo uploading will be done using ajax, with a separate upload button inside the form. My question is how do I upload the photo (when the user clicks on the upload button) and then save the user info when the user clicks on the submit button.
The model looks like this:
class User(models.Model):
name = models.CharField(max_length=50)
# some other fields
image = models.ImageField(upload_to="assets/images")
Thanks!

You could return the id of the User instance you used to save the picture as part of your js callback/success function, use it to populate a hidden field, and then call that user instance and save the rest of the info when the user submits the form.
The bigger question is, especially given that the user is going to submit the form anyway, why do you want to save just the image first?

You would need to use an <input type="button" /> with a JavaScript event handler to process the upload. jQuery's $.POST can do this very easily for you.
If you use an <input type="submit" /> for the image upload, it will also submit its containing form.
You will probably want to disable the actual "save" button until the ajax process has finished and that record has been saved, in case you need to make any associations to other data from your form, etc.
Hope that gets you going.

Related

Django form ignore validations on save vs submit

I am trying to create a Django form in which the user will have two options
Save the form (temporarily)
Submit the form
What I am trying to do is to allow the users to save the form temporarily and after they have all the data they can come back, edit the form and make the final submission.
The problem is that the form validation will not allow partially filled form to be saved.
Is there any way I can ignore validations when "Save" is pressed whereas perform all the validations when "Submit" is pressed?
I do not want to have 2 views. I want the same view with two buttons "Save" and "Submit" if Save is pressed some of the validations will be ignored (i.e. required field left empty due to the fact that the user might not currently have the information). But if the "Submit" is pressed, all the date should be validated.
Please note that all the validations takes place backend with Django.
Thanks

Setting up a custom workflow for the model change-form view

Context
I have a model, let's call it Application.
class Application(models.Model):
# various fields here
status = status = models.CharField(
max_length=100,
choices=APPLICATION_STATUSES,
default=PENDING_STATUS[0],
)
assigned_operator = models.OneToOneField(
settings.AUTH_USER_MODEL,
on_delete=models.PROTECT,
editable=True,
null=True,
)
This model has some fields, but the ones we care here are the status, which is simply a choice field, and the assigned_operator field, which defines a 1-1 relationship with a User instance. This model also has its corresponding ApplicationAdmin view defined.
Description
The requirement is that when trying to edit an Application, from the admin view, the default workflow, where you make whatever changes you want and then simply save the form, should be replaced with the following workflow:
The application form is readonly unless the user is the assigned_operator of the application, in which case the application is editable.
When the user is not the application's assigned_operator the actions at the bottom will be 1 button:
"Assign to myself" - When clicked the Application model is updated to reference the current user as its assigned_operator and the page refreshes
When the user is the application's assigned_operator the actions at the bottom will be 3 buttons:
"Save changes" - Does what default "Save" button does
"Reject" - When clicked changes the status field of the application to the appropriate one
"Accept" - When clicked changes the status field of the application to the appropriate one
The problem
Well, the problem is that I am pretty new with django and I am pretty lost here.
What I know:
How to make the fields of the form editable or read only based on the assigned_operator value. I think I just have to set up a get_readonly_fields and do my checks there. Correct me if wrong.
I can replace the current list of form actions with some custom buttons by adding a change_form_template = "path/to/change_form.html" field to the ApplicationAdmin. An example change_form.html that I have now:
{% extends 'admin/change_form.html' %}
{% block submit_buttons_bottom %}
<div>
<input type="submit" value="Assign to me" class="default" name="????">
</div>
{% endblock %}
What I don't know
How to conditionally show either the "Assign to myself" or the group-of-3-buttons, depending on the assigned_operator value of the Application model.
How to connect those new custom buttons to interact with the models and do stuff on them, when they are clicked
In general how the change_form.html part, which is just a template as far as I know, can know things from the currently displayed model instance and the current user.
While code examples are welcome, I do not ask you to give me the implementation. Clear directives/instructions will do just fine, I just need some guidance
Thanks
UPDATE
I figured how to pass info to the template, by using the change_view method of the ModelAdmin. So now I can conditionally display the appropriate buttons.
UPDATE 2
Just figured out how to also do something to a model once a button is clicked. We can use either response_change or change_view for that (not sure which one is the more "correct" option, but both work. Difference is that change_view runs before the view is even rendered, while response_change runs after the form has been saved and the model updated)
How to conditionally show either the "Assign to myself" or the group-of-3-buttons, depending on the assigned_operator value of the Application model.
By overriding the change_view method of the ModelAdmin in our custom Admin view we can pass extra context to our html templates, as showcased in the docs here. So now we can conditionally display the appropriate buttons, by adding an {% if context_value %} in the template.
How to connect those new custom buttons to interact with the models and do stuff on them, when they are clicked
We can use either response_change or change_view for that on our Admin view. In there we can listen for the value of our button's name in the request.POST values (for example _save etc) and act accordingly
(not sure which one is the more "correct" option to use, the response_change or the change_view but both work. Difference is that change_view runs before the view is even rendered, while response_change runs after the form has been saved and the model updated)
In general how the change_form.html part, which is just a template as far as I know, can know things from the currently displayed model instance and the current user.
A combination of passing it context from the Admin view and listening for button names from the template in the request.POST

Django ClearableFileInput - how to detect whether to delete the file

I'm using Django Crispy Forms for my form with an option to upload an image (ImageField in my Model)
The forms renders as I'd expect, with the checkbox to clear an existing file. However when processing the form submission the 'image-clear' checkbox always gives me a 'None' value.
image_clear = form.cleaned_data.get("image-clear")
print image_clear
In the HTML of the page I notice that the input checkbox doesn't have a value attribute, see:
<input id="image-clear_id" type="checkbox" name="image-clear">
So I wondered if this was the issue, but when I look at the rendering in the Django admin site, the corresponding HTML input field doesn't have a value either - yet it still identifies that the image should be removed.
I should note that if I upload a new image, then this works, it's only the case where I'm removing/clearing the image (and it works in Django admin pages, so assume that means my model definition is ok to allow no image to be attached to the model)
So... in my form processing, how do I detect whether or not the image should be removed or not?
I'm sure I'm missing something simple here - and any help much appreciated.
You shouldn't check the checkbox, but check the value of the file input field. If it is False, then you can delete the file. Otherwise it is the uploaded file. See: https://github.com/django/django/blob/339c01fb7552feb8df125ef7e5420dae04fd913f/django/forms/widgets.py#L434
# False signals to clear any existing value, as opposed to just None
return False
return upload
Let me add here my code that solved the problem - I decided to put this logic to ModelForm.clean():
class Document(models.Model):
upload = models.FileField(upload_to=document_name, blank=True)
class DocumentForm(ModelForm):
def clean(self):
cleaned_data = super(DocumentForm, self).clean()
upload = cleaned_data['upload']
if (upload == False) and self.instance.upload:
if os.path.isfile(self.instance.upload.path):
self.instance.upload.delete(False)

Saving Formset in a Session - Django

Is here any way to store formset to a session ?
My Scenario is like this . I have a form to fill user data and upload user certificates, and in the next page(form by clicking next) there is a form to enter Professional details .
Is it possible to limit Maximum number of forms generated using a formset?
If I understand your question correctly - how to save a state of the from in a session, then starting with Django 1.4, it actually comes with a way on how to do that out of the box.
https://docs.djangoproject.com/en/dev/ref/contrib/formtools/form-wizard/
It allows you to split a form into multiple section, which then user can fill separately. Once user fills any one section, he/she go to the next page, at which point the state of the form will be saved in a session. Once all the pages are filled, then everything can be saved to a database.
In addition, while going from one page to the other, you add logic of what should be on the next page.
Image that you have a wizard where on the first page it asks what type of content user wants to upload. Then upon going to the second page, then depending on the answer from the first page, appropriate upload fields can be present - field for video, music, or graphics.
I would have answered FormWizard but if you don't want to use it, you can simply create two forms. when the user submit the first one, you pickle it into a session and then you generate the second form. When he clicks on back link, you unPickle saved data and you prefill the form.
def submitFirstForm(request):
data = request.POST['data']
import cPickle
request.session['data'] = cPickle.dumps(data)
...
def backBtn(request):
import cPickle
data = cPickle.loads(request.session['page'])
form = DataForm(data)
...

Insert django form into template dynamically using javascript?

I want to add same django form instance on same template. i already add one before and other add dynamically using javascript.
for example 'form" is a django form: newcell.innerHTML = {{ form.firstname }};
The problem is that when i submit the form, in view the request object has only one value (that is not add using javascript). how can i get the values of other form elements values that is added dynamically runtime.
It is something like the "Attach Another File" feature in gmail, where the user is presented with a file upload field and new fields are added to the DOM on the fly as the user clicks to "Attach Another File" plus button
You could always try separating out your FileField into a FileModel.
Take a look at the following pseudo code (as in python based on memory--i've moved over to clojure for now).
models.py
class FileModel(models.Model):
file = models.FileField()
...
class ThingToWhichYoureAttaching(models.Model):
name = models.CharField()
attachments = models.ManyToManyField(FileModel)
...
forms.py
class FileForm(forms.ModelForm):
class Meta:
model=FileModel
class ThingForm(forms.ModelForm):
attachments = forms.MultipleChoiceField()#override the manytomany form field with style field of your choice.
class Meta:
model=ThingToWhichYoureAttaching
When they pop up the window with the PLUS button, show the FileForm but on the main page leave the ThingForm untouched. You can also have an initial FileField on the main page with the ThingForm for people who don't have javascript. Just make sure to process the FileForm BEFORE the ThingForm so that the File is available for the Thing.
When processing the popup form you can use AJAX (i recommend jquery) to submit the FileForm to the server, and return the markup to insert the File in the Attachments field.