What are the properties of ImageField in django? - django

I have created a userUpdate view with a partial modelForm to update user data, which consists of an imageField.
Form in my template looks like:
<div class='field'>{{ form.photo.label_tag }} {{ form.photo}}</div>
Here photo is the imageField.
The rendered html view is:
But,
I don't want the clear checkbox.
How to get the url of the current image if one exists for the model instance?
What are all the properties of the photo? So, that I can individually use them as required.

clear checkbox
You need to change the widget from ClearableFileInput to Fileinput
# forms.py
from django.forms.widgets import FileInput
class UserForm(forms.ModelForm):
class Meta:
model = User
fields = '__all__'
widgets = {
'photo': FileInput(),
}
The default FileField widget is ClearableFileInput.
https://docs.djangoproject.com/en/dev/ref/forms/widgets/#file-upload-widgets
Alternatively, You can render HTML manually for file type field.
<div class="field">
<!-- show label of field -->
{{form.photo.label_tag}}
<!-- check for input type -->
{% if form.photo.field.widget.input_type == 'file'%}
{{ form.photo.value }}<br/>
<input type="file" name="{{ form.photo.name }}" />
{% endif %}
</div>
get the URL of the current image if one exists for the model instance
You can get URL of current image using . operator
# URL of the image
photo.url
# name of the image
photo.name
properties of the ImageField
ImageField inherits all attributes and methods from FileField, but also validates that the uploaded object is a valid image.
In addition to the special attributes that are available for FileField, an ImageField also has height and width attributes.
Read the official docs for the list of all attributes

Related

Wagtail not pulling through custom field panels

I'm overriding the wagtail AbstractFormField panel attribute in the following way:
...
before_input = RichTextField(verbose_name=_('before input'), blank=True)
after_input = RichTextField(verbose_name=_('after input'), blank=True)
panels = [
FieldPanel('label'),
FieldPanel('before_input'),
FieldPanel('after_input'),
FieldPanel('required'),
FieldPanel('field_type', classname="formbuilder-type"),
FieldPanel('choices', classname="formbuilder-choices"),
FieldPanel('default_value', classname="formbuilder-default"),
]
where the other panels are what comes out of the box.
This is working perfectly on the admin side and also saving as rich text into my database
I am pulling this through to my form in my template in the following way:
<form action="{% pageurl page %}" method="POST" class="lm-ls1" id="feedback-form">
{% csrf_token %}
{{ form.question1.help_text }} <!-- Simpler non interable way -->
{{ form.question1.before_input }}
<p>---------------</p>
{% for row in form.fields.values %}
{{row.choices}}
<p>---------------</p>
{{row.help_text}}
<p>---------------</p>
{{row.before_input}}
{% endfor %}
</form>
But I am only getting html output for the form panels excluding the before_input and after_input ones
I am getting through roughly the following:
Overall, how did you feel about the service you received today?
---------------
[('Very satisfied', 'Very satisfied'), ('Satisfied', 'Satisfied'),
('Neither satisfied nor dissatisfied', 'Neither satisfied nor dissatisfied'), ('Dissatisfied', 'Dissatisfied'), ('Very dissatisfied', 'Very dissatisfied')]
---------------
Overall, how did you feel about the service you received today?
---------------
---------------
How can I access the before_input field panel data stored in the _formfield wagtail table?
Bit late but hopefully this still helps you or someone else out there.
How Wagtail Forms Work
Wagtail forms provided to the view context for AbstractFormPage models is a fully instanced Django Form. This means that you will only ever find values in the form that can be given to a Django Form.
This includes fields, which are instances of Django's Fields (eg. CharField) and there is no simple way to add additional attributes to these fields.
You can see how the Form object is built in the Wagtail FormBuilder class definition.
1 - Make a Custom Template Tag
A somewhat simple way to get additional attributes on your FormField (Wagtail's FormField) is using a template tag.
Create a new file in in a folder templatetags in your app, and build a simple_tag that will take the form_page, the field (which will be a Django Field instance) and a string of the attribute name you want to get.
# myapp/templatetags/form_tags.py
from django import template
from django.utils.html import mark_safe
register = template.Library()
#register.simple_tag(name='form_field_attribute')
def form_field_attribute(form_page, field, attribute_name, default=None):
"""Return attribute on FormField where field matches 'field' provided."""
# field is a django Field instance
field_name = field.name
results = [
# if html is stored, need to use mark_safe - be careful though.
mark_safe(getattr(form_field, attribute_name, default))
# get_form_fields() is a built in function on AbstractFormPage
for form_field in form_page.get_form_fields()
# clean_name is property on AbstractFormField used for Django Field name
if form_field.clean_name == field_name]
if results:
return results[0]
return default
2 - Revise your form_page.html Template
In your template, cycle through your form (this is the Django Form instance) and use the template helper to get you the extra attributes you need. Example below, passing in page or self will work the same as they are both the instance of your FormPage.
<form action="{% pageurl page %}" method="POST" role="form">
{% csrf_token %}
{% for field in form %}
<div>{% form_field_attribute page field 'before_input' %}</div>
{{ field }}
<div>{% form_field_attribute page field 'after_input' %}</div>
{% endfor %}
<input type="submit">
</form>

How should I allow a FileField not need to upload a new file when the existed in Django?

I have a model like this:
class Assignment(models.Model):
content = models.FileField(upload_to='xxx')
other_val = models.CharField(...) # not important
And a form wrapping this model (ModelForm):
class AssignmentForm(ModelForm):
class Meta:
model = Assignment
fields = ['content', 'other_val']
My view looks like this (for simplicity I skip the request.POST/request.FILES. part):
#login_required(login_url='/login/')
def create_assignment(request):
form = AssignmentForm()
# render form
#login_required(login_url='/login/')
def update_assignment(request, assignment_id):
assignment = Assignment.objects.get(id=assignment_id)
form = AssignmentForm(instance=assignment)
Creating an assignment works just fine - It forces me to upload a file, which is what I want. But when I want to update the content of the assignment (the file), it first shows a link of a previously uploaded file (excellent!) then the upload button, like this:
Currently: AssignmentTask_grading_script/grading_script_firing.py
Change: [Choose File] no file chosen
But then I assume if I don't want to replace this file, I should simply click the submit button. Unfortunately, when I click the submit button, the form complains that I should upload a file. Is there a way to silent the complaint if a file is already in database?
As following the previous comments, maybe like this;
1. forms.py
class AssignmentForm(forms.ModelForm):
# as following #Rohan, to make it optional.
content = forms.FileField(required=False)
class Meta:
model = Assignment
fields = ['content', 'other_val']
2. yourtemplate.html
<form method="post" enctype="multipart/form-data" action=".">
{% csrf_token %}
{{ form.as_p }}
<button type="submit">Save</button>
</form>
<script>
{% if not form.content.value %}
$('#id_content').attr({'required': 'required'});
{% endif %}
</script>
The field of content is under required only if havn't value before...

Change default text shown for ImageField when not empty

I have following field:
photo = models.ImageField(null=True,blank=True,upload_to="product_images")
I have defined the following layout in forms.py for this field:
self.fields['photo'].label = "Asset Image"
self.helper.layout = Layout(
'photo',
HTML("""{% if form.photo.value %}
<img height="80"
width="160"
class="pull-left"
src="{{ MEDIA_URL }}{{ form.photo.value }}">
{% endif %}""", ),
Now I can upload images associated with this particular field just fine. However when I try to update the image I see the following in my template:
Is there any way I can change the layout so that only the browse button and existing image are shown when the image field is not empty? In other words, remove the text Currently: product_images/km_2.jpeg Clear Change:
I'm pretty sure ImageField uses ClearableFileInput in order to render the HTML.
So to get rid of the "Currently: ... Clear" stuff you need to subclass the ClearableFileInput and modify the template_with_clear and/or template_with_initial members.
from django.forms import ClearableFileInput
class MyClearableFileInput(ClearableFileInput):
template_with_initial = '%(input_text)s: %(input)s'
Subsequently you use MyClearableFileInput, e.g.:
class MyForm(ModelForm):
class Meta:
model = MyModel
widgets = {
"file": MyClearableFileInput(),
}
I tested this with a FileField, but I'm pretty sure it will also work with an ImageField.

Display image as property of a ChoiceField in a form

Hi Have a choice field
class PropertyReportForm(forms.Form):
property = forms.ChoiceField(widget = forms.RadioSelect,required = False)
def __init__(self,*args,**kwargs):
properties = kwargs.pop('properties')
property_choice = []
for property1 in properties:
index = (property1.id,"Name :"+property1.name+" Area:"+str(property1.area)+" "+property1.image)
property_choice.append(index)
super( PropertyReportForm, self).__init__(*args, **kwargs)
self.fields['property'].choices = property_choice
Now while displaying I want it to display
How can I do this?
Template code similar to what I want. This does not work. But I want this
{% for field in propertyreportform %}
{{ field }} <img src="/media/{{ field.image }}" />
{% endfor %}
To solve this problem you basically have three options:
Create your own renderer, and use it as argument for ChoiceField, unfortunately you will need to create it from scratch, since django doesn't allow you to simply override RadioFieldRenderer class. https://github.com/django/django/blob/1.5.4/django/forms/widgets.py#L693
Just loop over your choices and use manually created radio input tags, there's not a lot of validation to do and retrieving selected item or model object is also simple enough.
The simplest and less recommended way could be to include the whole image tag inside label string (use settings to get media url part).

How edit data from form django admin

I'm learning Django Framework, and I have a question. To help you understand I will try and explain using the example below:
Suppose that we have some table in db as is:
CREATE TABLE names (id INT NOT NULL PRIMARY KEY AUTO_INCREMENT, name VARCHAR(100));
And I have the form in Django Admin as is:
<form>
<textarea name="names"></textarea>
<input type="submit" name="sbt" value="Submit">
</form>
User entered something in the input names in the form and submitted it. Then a script catches this data and splits it into an array (str.split("\n")) and in cycle adding to table names!
And I many quetion:
How i can add form to Django Admin?
How i can catch form data and add this data to somethink table in database?
Thanks.
First of all you must create a django model.
Put this code in models.py.
class Names(models.Model):
name = models.CharField(max_length = 100)
Then you must create the admin model.
Put this code in admin.py.
class NamesAdmin(admin.ModelAdmin):
list_display = ['name']
# whatever you want in your admin panel like filter, search and ...
admin.site.register(Names, NamesAdmin)
I think it meet your request. And for split the names you can override save model method and split the names in there. But if you want to have an extra form, you can easily create a django model form.
Put the code somewhere like admin.py, views.py or forms.py
class NamesForm(forms.ModelForm)
class Meta:
model = Names
That's your model and form. So, if your want to add the form to django admin panel you must create a view for it in django admin. For do this create a view as common.
Put the code in your admin.py or views.py.
def spliter(req):
if req.method == 'POST':
form = NamesForm(req.POST)
if form.is_valid():
for name in form.cleaned_data['names'].split(' '):
Names(name = name).save()
return HttpResponseRedirect('') # wherever you want to redirect
return render(req, 'names.html', {'form': form})
return render(req, 'names.html', {'form': NamesForm()})
Be aware you must create the names.html and put the below code in you html page.
{% extends 'admin/base_site.html' %}
{% block content %}
<!-- /admin/names/spliter/ is your url in admin panel (you can change it whatever you want) -->
<form action="/admin/names/spliter/" method="post" >{% csrf_token %}
{{ form }}
<input type="submit" value="'Send'" >
</form>
{% endblock %}
This is your view and your can use it everywhere. But if you want only the admin have permission to see this page you must add this method too your NamesAdmin class.
def get_urls(self):
return patterns(
'',
(r'^spliter/$', self.admin_site.admin_view(spliter)) # spliter is your view
) + super(NamesAdmin, self).get_urls()
That's It. I hope this can help you.