Django ModelForm with dynamic model init kwargs - python

I have a model with an __init__ method:
class Foo(models.Model):
name = models.CharField(max_length=50)
def __init__(self, *args, **kwargs):
self.bar = kwargs.pop('bar', False)
super(Foo, self).__init__(*args, **kwargs)
if self.bar:
# do something
pass
Now, i need to create a specific ModelForm:
class FooForm(ModelForm):
class Meta:
model = Foo(bar='something')
fields = ('name',)
That does not work apparently:
TypeError: 'Foo' object is not callable
Is there any way i can overcome this?
Update
More information on what i want to achieve: I have an Image model with an ImageField. It has different storage methods depending on the form that uses it.
The model:
class Image(models.Model):
image = models.ImageField(upload_to=imageUploadTo)
user = models.ForeignKey('auth.User')
def __init__(self, *args, **kwargs):
self.overwrite = kwargs.pop('overwrite', False)
super(Image, self).__init__(*args, **kwargs)
if self.overwrite:
self.image.storage = OverwriteStorage()
Now i want to be able to create forms that overwrite the old image and forms that use the default behavior. What's the best way to achieve this?

No, that's not how it works at all, and this has nothing to do with your custom init. You don't call things inside Meta. In your case, you pass the parameter when you initialize the form in your view.

Related

How to change the fields displayed if an instance is passed to a form?

I have a form something like this:
class ExampleForm(forms.ModelForm):
class Meta:
model = Example
fields = ('field1','field2')
Now, I want to add an additional field if an instance is passed to it. Which means that, if I create an form with an instance (for editing that object) I want to change the fields being displayed.
I know I can use create an another form for this purpose and create an instance of that rather than using this. However, is there a way to do this in this same form?
Override the __init__ method, and modify self.fields when instance is passed to the form.
class ExampleForm(forms.ModelForm):
class Meta:
model = Example
fields = ('field1','field2')
def __init__(self, *args, **kwargs):
super(ExampleForm, self).__init__(*args, **kwargs)
if kwargs.get('instance'):
self.fields['field3'] = forms.CharField()

Abstract Django model doesn't have a "model" attribute?

I have an abstract model in a Django app:
class HistoryTrackedModel(models.Model):
def save(self, *args, **kwargs):
super(self.model, self).save(*args, **kwargs) # Call the real save method
# Do some miscellaneous work here (after saving)
class Meta:
abstract = True
A child model uses the abstract model as its base:
class Project(HistoryTrackedModel):
name = models.TextField(unique=True, blank=False, db_index=True)
... other fields ...
def __unicode__(self):
return self.name
class Meta:
ordering = ('name',)
When I instantiate an instance of Project (the child model), and call the save() method, I get the following error:
'Project' object has no attribute 'model'
It's failing on the super(self.model, self).save() call in the abstract class's save method. I attempted to change that method to the following, but it (fairly obviously, now that I look at it) gets caught in a recursive loop:
class HistoryTrackedModel(models.Model):
def save(self, *args, **kwargs):
my_model = type(self)
super(my_model, self).save(*args, **kwargs) # Call the real save method
What am I doing wrong here? Shouldn't all child classes that inherit from a base class (which itself inherits from models.Model) include the model attribute?
super(HistoryTrackedModel, self).save(*args, **kwargs)
should work.

Get an attribute of the model from ModelForm without the instance (overriding __init__)

I have a MultipleChoiceField and for displaying the values that had been previous selected in the admin, I have to override method init from a ModelForm. I have the following class with its form:
class Profile(models.Model):
name = models.CharField(max_length=64)
contract = models.CharField(max_length=100)
class ProfileForm(forms.ModelForm):
CONTRACT_CHOICES = (
('scholar', _(u'Scholar')),
('freelance', _(u'Freelance')),
('contract', _(u'Contract')),
('volunteer', _(u'Volunteer'))
)
contract = forms.MultipleChoiceField(choices=CONTRACT_CHOICES)
def __init__(self, *args, **kwargs):
initial = kwargs.get('initial',{})
initial['contract'] = ['scholar', 'contract', 'freelance'] #Here I would have to be able to get the attribute contract from the Profile class, not this list
kwargs['initial'] = initial
super(ProfileForm, self).__init__(*args, **kwargs)
With the initial['contract']=['scholar','contract','freelance'] works (this values are shown as selected) but I have to achieve this with the attribute contract from Profile. I know that you can access to the model from a ModelForm with the attribute instance, but there's one problem: you can only have access to instance once the native method of init is called. And in this case, I have to call it later because otherwise it doesn't work for me. I already have tried to do it the following way:
def __init__(self, *args, **kwargs):
super(ProfileForm, self).__init__(*args, **kwargs)
self.fields['contract'].initial = self.instance.contract
But that doesn't work (it shows no errors but the selected attributes doesn't appear as selected). And furthermore, the following doesn't work either:
def __init__(self, *args, **kwargs):
super(ProfileForm, self).__init__(*args, **kwargs)
self.fields['contract'].initial = ['scholar', 'contract', 'freelance']
It has only worked as the first way, but with the problem that I don't know how to access to the attribute contract.
Any ideas? Thanks in advance

Modify variable just in the Django admin but not in database

I want to modify a single value when I open an instance of a model in the Django admin.
Basically I want to display a value that is the opposite of the one stored in the database. So here is what I did in admin.py :
class MyModelAdminForm(forms.ModelForm):
import_file = forms.FileField(required=False)
class Meta:
model = MyModel
def __init__(self, *args, **kwargs):
super(MyModelAdminForm, self).__init__(*args, **kwargs)
print(self.instance.value)
self.instance.value = self.instance.get_reverted_value()
print(self.instance.value)
I works I can see it with the prints, but the admin still displays the original value that is stored in database.
Any idea ?
Thanks in advance
What about:
def __init__(self, *args, **kwargs):
super(MyModelAdminForm, self).__init__(*args, **kwargs)
self.fields['value'].value = self.instance.get_reverted_value()

Hidden form field using none model forms

When I'm using model forms I can exclude a field from showing by using a Meta class and exclude. However, with standard none model forms this does not work. I want to hide a field call amount and populate on init. How?
amount = forms.FloatField()
well I have tried to first exclude like this...
class Meta:
exclude = ('amount',)
but this does not seems to work on none model forms.
Use forms.ModelForm to override the init
class YourForm(forms.ModelForm):
amount = forms.FloatField()
def __init__(self, *args, **kwargs):
super(YourForm, self).__init__(*args, **kwargs)
self.fields['amount'].widget = forms.HiddenInput()
self.fields['amount'].initial = ''

Categories