Django - how to set forms.FileField name - python

I'd like to set custom name to a FileField object in my admin form so that it's html name attribute will not be equal to my instance field name.
class MyAdminForm(forms.ModelForm):
file_field = forms.FileField()
def __init__(self, *args, **kwargs):
if kwargs.has_key('instance'):
instance = kwargs['instance']
self.initial['image_file'] = instance.file_field
With this code I get <input type="file" name="file_field" /> and what I want to do is set it's name attribute to something else.
EDIT:
I accepted the answer below, but I have another question. Is it possible to construct variable number of FileField objects? I mean - what if I'd like to have 4 of those now, but under some circumstances only one? Will I have to declare all of those as a class fields, like file_field1, file_field2 and so on, or is it possible to add them to a dictionary, like that: { 'file_field1: FileField(), 'file_field2' : FileField() } - I actually tried it and got an error...

The name attribute in the HTML is the same as the name in the form definition so if you don't want it to be file_field then don't call it file_field.
class MyAdminForm(forms.ModelForm):
new_field = forms.FileField()
# Rest of the form goes here

Related

Django - Creating a Custom Template Tag to show Model Name

I have a model:
class Survey(models.Model):
name = models.CharField(max_length = 200)
def __str__(self):
return self.name
And in my template I want to show the name of the current Survey model:
<h1> {{survey.name |name}} </h1>
I'm using a custom template tag/filter to display that name; however, it is showing as 'str' instead of the name of the current Survey model.
Here is the filter code:
from django import template
register = template.Library()
#register.filter
def name(value):
return value.__class__.__name__
What am I doing wrong here?
When you are calling the template tag with <h1> {{survey.name |name}} </h1> you are passing it the string associated with the model. As the field is a CharField it will return a string and therefore the name of the that class is str.
I believe what you are wanting it <h1> {{survey|name}} </h1> which will send the template tag the instance of Survey and therefore get the class name from that.
As an addition to the above answer...
Your filter is calling __class__.__name__, which I believe would return str
Try changing your filter to return value.__name__
See this similar question
you can do something like this:
if you have defined verbose_name in meta then you can do:
return (model-name)._meta.verbose_name
otherwise you can do:
return (model-name).name

Override Title value in dexterity type

I have a custom type in dexterity (schema driven) without title or description fields.
class IAnimal(model.Schema):
name = schema.TextLine(title=_(u"Name"),required=True,)
specie = schema.Choice(title=_(u"Specie"),vocabulary=animalSpecies)
weight = schema.TextLine(title=_(u"Weight"))
(etc)
I really don't need the title field on my model, but when I create some content, on folder listing is displaying:
— by admin — last modified Oct 17, 2015 02:27 PM
I created this product with mr.bob and didn't override any forms yet. This can be accomplished by override any forms, a custom behavior (like plone.app.content.interfaces.INameFromTitle) or what?
I just want the "name" field as "title" without changing "name" for "title", even that I must have to hide the "title" field in the model.
Looking at some old archetypes products, it was a method like:
def at_post_create_script(self):
title = self.name
plone_utils = getToolByName(self, 'plone_utils', None)
new_id = plone_utils.normalizeString(title)
self.setTitle(new_id)
I didn't get why you can't simply provide a "title" field named "Name" (easiest way), however you can also override the title attribute and Title method of the base class.
If you used mr.bob you probably don't have a base class you can customize.
Check your type definition XML: in the klass property you probably have plone.dexterity.content.Item. Change it to a new dexterity base class you must add to you product (example: https://github.com/collective/wildcard.media/blob/84b82994dc424fe40b92b1c9af8d48edb558a78d/wildcard/media/content.py#L6)
When you have the base class you can add the Title method and a title attribute, something like:
class MyType(Item):
implements(IMyType)
def Title(self):
return self.name
#property
def title(self)
return self.name

Where's the primary key of the object I want to update in django using modelform?

I'm using modelform in django to insert and update objects in my database, but when I try to update I cannot see the primary key/id of the object being updated:
My model:
class Category(models.Model):
name = models.CharField(max_length=20, db_index = True)
and my form:
class CategoryForm(ModelForm):
class Meta:
model = Category
fields = ['name']
and in my template I got:
{% csrf_token %}
{{ category_form.as_p }}
In my view I do
cat = Category.objects.get(pk = cat_id)
data['category_form'] = CategoryForm(instance = cat)
and pass the data to my template, which renders the form ok, but the id of the object I about to update is nowhere in the html source. How can the code then now what object to update?
I feel stupid asking this since it should be pretty basic, but I've followed all the tutorials and looked thru the django docs, googled and search this site without luck.
Thanks in advance.
Where is cat_id coming from in your view? I guess you receive it in url, like so:
url( r'categories/(\d+)/edit/', your_view, {} ),
in urls.py somewhere. Now in your view you can read it from appropriate view function argument:
def your_view( request, cat_id ):
Now you can obtain object with proper id, which you do here:
cat = Category.objects.get(pk = cat_id)
...and instantiate ModelForm passing it cat object if you want to edit existing object, or don't pass it, if you want an empty form for object creation.
The explanation for this can be found in the django docs here: http://docs.djangoproject.com/en/dev/topics/forms/modelforms/#the-save-method
While trying to update already saved entity you must provide an instance parameter when you recreate the form. Otherwise django will try to insert a new entity.
foo_form = FooForm(request.POST, instance=foo)
The primary key is an attribute called "id" on your instance object "cat". The form itself, and in your example represented by "cat_id". The Model form should takes care to track the primary key - all you should need to do is pass the resulting "request.POST" data back into CategoryForm, valid the data with is_valid() and then save it.
i.e.
form_with_post = CategoryForm(request.POST)
if form_with_post.is_valid():
form_with_post.save()
else:
... return the form_with_post through the context to display the errors
The ID doesn't need to be in the HTML, because you've passed the instance into the form object when you instantiate it. Django simply updates that instance when you do form.save().

Attaching additional information to form fields

I'm trying to pass on additional information to fields of a Django form to be displayed in a template. I tried to override the constructor and add another property to the field like this:
self.fields['field_name'].foo = 'bar'
but in the template this:
{{ form.field_name.foo }}
didn't print anything. Does anyone know how to add additional information to a field without rewriting/inheriting the forms field classes?
According to django.forms.forms, the __getitem__() method of a Form creates something called a BoundField out of the Field before returning it, thus stripping it of whatever changes you made. If you really want to insert more functionality into that, override that method to do stuff to the bound field before returning it:
class MyForm(forms.Form):
def __getitem__(self, name):
boundfield = super(forms.Form,self).__getitem__(name)
boundfield.foo = "bar"
return boundfield
Then, "bar" will appear for all fields in that form. You can also make a function and call that instead, to make it more than just a hard-coded string.
While it's more standard to add more fields, or to add properties to the form itself, if you have a whole new class of info that every field needs to contain, this may do it for you.
Another way to get the same thing is to edit an attribute of the field, then access it via the BoundField's "field" attribute:
class MyForm(forms.Form):
def __init__(self, *args, **kwargs)
super(forms.Form, self).__init__(*args, **kwargs)
self.fields['field_name'].foo = "bar"
Then, to access foo in a template:
{{ form.field_name.field.foo }}

Overriding initial value in ModelForm

in my Django (1.2) project, I want to prepopulate a field in a modelform, but my new value is ignored.
This is the snippet:
class ArtefactForm(ModelForm):
material = CharField(widget=AutoCompleteWidget('material', force_selection=False))
def __init__(self, *args, **kwargs):
super(ArtefactForm, self).__init__(*args, **kwargs)
self.fields['material'].initial = 'Test'
I also tried with self.base_fields, but no effect: there is always the database-value displaying in the form. Any ideas?
Try this:
def __init__(self, *args, **kwargs):
initial = kwargs.get('initial', {})
initial['material'] = 'Test'
kwargs['initial'] = initial
super(ArtefactForm, self).__init__(*args, **kwargs)
Old question but adding a descriptive answer as I believe it would be helpful for some new developer.
I also tried with self.base_fields, but no effect: there is always the database-value displaying in the form. Any ideas?
If a form is "initialized" form, either:-
using initial argument (eg. YourModelFrom(initial={'filed1': variable}) — generally the case, when you want to pass dynamically calculated initial values for some fields). Reference Setting Initial Values
or
using instance argument (eg. YourModelFrom(instance=model_object) — usually the case, when you wants to update an existing model instance object) . References read ModelFrom's save() method
Note:
1 `ModelFrom` class inherits `BaseModelFrom` class. The `BaseModelFrom` class inherits `BaseForm` class.
2 The argument instance is added in `BaseModelFrom` class constructor, when we assign a model class instance object to instance argument (hence instance is not None) then `BaseModelFrom` constructor calls model_to_dict() and updates initial argument before to call super class constructor. Check def __init__ in BaseModelFrom class
Then assigning initial value to a field explicitly (as shown in OP's code in question) don't effect, this is due to the way _clean_fields method is written in BaseFrom class.
Code Snip:
def _clean_fields(self):
for name, field in self.fields.items():
value = field.widget.value_from_datadict(
self.data, self.files, self.add_prefix(name))
try:
if isinstance(field, FileField):
initial = self.initial.get(name, field.initial) # <- Check
value = field.clean(value, initial)
else:
According to code line initial = self.initial.get(name, field.initial), if initial value for field is given in initial dict then value assigned to field.initial is not used.
[ANSWER]:
Although, #Daniel answer is perfectly correct but one can also like another way to achieve same effect is using self.initial:
def __init__(self, *args, **kwargs):
super(ArtefactForm, self).__init__(*args, **kwargs)
self.initial['material'] = 'Test'
Give it a try!!
self.initial is nothing but it the dict we pass in argument. Check code __init__ in BaseForm:
class BaseForm(object):
def __init__(........
........):
:
self.prefix = prefix
self.initial = initial or {} # <-- Notice
self.error_class = error_class
:
Note: I didn't find any documentation related to use initial attribute, I just explored the base code and used it.
Edit: the behavior reported in Question is also documented in Django Model
Dynamic initial values
Form.initial
Note that if a Field defines initial and you include initial when
instantiating the Form, then the latter initial will have precedence.
In this example, initial is provided both at the field level and at
the form instance level, and the latter gets precedence:
>>> from django import forms
>>> class CommentForm(forms.Form):
... name = forms.CharField(initial='class')
... url = forms.URLField()
... comment = forms.CharField()
>>> f = CommentForm(initial={'name': 'instance'}, auto_id=False)
>>> print(f)
<tr><th>Name:</th><td><input type="text" name="name" value="instance" />
<tr><th>Url:</th><td><input type="url" name="url" /></td></tr>
<tr><th>Comment:</th><td><input type="text" name="comment" /></td></tr>
PS: Btw, point 2 in my answers tell difference between initial and instance argument. Their is one more key-value argument data - values in that triggers form validations. read this Difference between Django Form 'initial' and 'bound data'?.

Categories