explain me please how to use it in my Admin?
You can just create a custom ModelForm for your model, with the following:
remove_the_file = forms.BooleanField(required=False)
def save(self, *args, **kwargs):
object = super(self.__class__, self).save(*args, **kwargs)
if self.cleaned_data.get('remove_the_file'):
object.the_file = ''
return object
Use that form in your ModelAdmin, and there's no need to change the database.
there is what i created in forms.py:
class MediaForm(forms.ModelForm):
remove_the_file = forms.BooleanField(required=False)
def save(self, *args, **kwargs):
object = super(self.__class__, self).save(*args, **kwargs)
if self.cleaned_data.get('remove_the_file'):
object.the_file = ''
return object
And there is my admin.py:
class MediaAdmin(admin.ModelAdmin):
raw_id_fields = ('parent',)
how should i change MediaAdmin class to apply it?
class MediaAdmin(admin.ModelAdmin):
raw_id_fields = ('parent',)
form = MediaForm
Related
I have one model name is cityform
i want to get url parmeter in this CityFrom hwo can i do this?
here is my url
path('state/city/<int:id>/', City.as_view(), name="city")
http://localhost:8000/country/state/city/3/
here is my form
class
CityFrom(forms.ModelForm):
def __init__(self, *args, **kwargs):
super(CityFrom,self).__init__(*args, **kwargs)
print(args)
print(kwargs)
self.fields['state'] = forms.ModelChoiceField(
empty_label = 'Select',
queryset = State.objects.all()
)
class Meta:
model = City
fields = ('state', 'name')
in this form i want to access id = 3
here is my view
from django.views import View
class City(View):
def get(self, request, *args, **kwargs):
Forms = CityFrom()
return render(request, 'albums/add.html', {'Forms': Forms})
Pass url parameter as keyword argument from views.py as following.
form = CityFrom(id=kwargs.get("id"))
To get the id in your forms.py, use following code in your form's __init__ method.
self.id = kwargs.get('id')
Your form should look like this.
CityFrom(forms.ModelForm):
def __init__(self, *args, **kwargs):
self.id = kwargs.get('id')
super(CityFrom,self).__init__(*args, **kwargs)
self.fields['state'] = forms.ModelChoiceField(
empty_label = 'Select',
queryset = State.objects.all()
)
class Meta:
model = City
fields = ('state', 'name')
* Call super after getting the id in your form as above. Here order of calling super is important.
Try
CityFrom(forms.ModelForm):
def __init__(self, *args, **kwargs):
self.id = kwargs.pop('id')
super(CityFrom,self).__init__(*args, **kwargs)
I have a model with a FileField namely file_test
I would like to manually create a file and assign in to file_test in the serializer
Below are my code, would like some help. Thanks
class Test(models.Model):
file_test = models.FileField(storage=OverwriteStorage(),
upload_to=_get_landmark_upload_path, max_length=100, blank=True)
class TestSerializer(serializers.ModelSerializer):
test = serializers.CharField(write_only=True, required=True)
class Meta:
model = Test
fields = ('file_test','test')
def save(self, *args, **kwargs):
self.file_test.save('test.txt', ContentFile(self.validated_data['test']))
return super().save(*args, **kwargs)
Or is there a way to create a file and assign it to file_test?
example in serializer
def save(self, *args, **kwargs):
kwargs['file_test'] = ?????(how to create this file)
return super().save(*args, **kwargs)
I'd manage to solve the issue by using ContentFile
Look at example below
def save(self, *args, **kwargs):
kwargs['file_test'] = ContentFile(
self.validated_data['test'], name="test.txt")
return super().save(*args, **kwargs)
Let's say we got two model:
model.py
class Engine(models.Model):
name = models.CharField(max_length=25)
class Car(models.Model):
name = models.CharField(max_length=25)
engine = models.OneToOneField(Engine)
engine_admin.py
class EngineAdmin(admin.ModelAdmin):
def get_changelist_form(self, request, **kwargs):
return EngineChangeListForm
form.py
class EngineChangeListForm(forms.ModelForm):
class Meta:
model = Engine
fields = []
# this work!
def save(self, *args, **kwargs):
car_obj = Car.objects.create(engine = self.instance)
return super(EngineChangeListForm, self).save(*args, **kwargs)
if I change save() to below, it would create a new car object, but in the end, engine object's car field will be empty.
I don't understand why the code below won't work.
# this won't work!
def save(self, *args, **kwargs):
car_obj = Car.objects.create(engine = self.instance)
self.instance.car = car_obj
return super(EngineChangeListForm, self).save(*args, **kwargs)
You need to call super() first to save the engine, before you create the car.
def save(self, *args, **kwargs):
instance = super(EngineChangeListForm, self).save(*args, **kwargs)
car_obj = Car.objects.create(engine=instance)
return instance
Is there a way to modify the data obtained from the model before inserting it in the form?
Here's my model:
class SomeData(models.Model):
Some_No = models.ForeignKey('SomeDef', on_delete=models.PROTECT)
Some_Val = models.DecimalField(max_digits=10, decimal_places=3, verbose_name=_('Some_Val'))
And here's my form:
#autostrip
class SomeForm(forms.ModelForm):
class Meta:
model = models.SomeData
fields = ('Some_Val', 'Some_No')
def __init__(self, *args, **kwargs):
super(SomeForm, self).__init__(*args, **kwargs)
self.fields['Some_No'].label = _(' ')
def clean_some(self):
some = None
some_id = self.cleaned_data['some']
some = models.SomeDef.objects.get(Some_No=some_id)
return some
def save(self, something, *args, **kwargs):
orig_commit = kwargs.get('commit', True)
kwargs['commit'] = False
ri = super(SomeForm, self).save(*args, **kwargs)
ri.Some_No = something
if orig_commit:
try:
ri.save()
except ValidationError as e:
raise ValidationError
return ri
The data saved inside of the models is a bit different from what I want to show in the forms when these are populated with data. However, I cannot figure out how to do it in a smart way.
Using the pre_save signal. Signals
You can set the initial value in the __init__ method:
def __init__(self, *args, **kwargs):
super(SomeForm, self).__init__(*args, **kwargs)
self.fields['Some_No'].initial = f(self.instance)
You can pass an initial data dictionary argument to your form, when you instantiate it into your view.
Have a inline form class:
class ItemColorSelectForm(forms.ModelForm):
def __init__(self, *args, **kwargs):
super(ItemColorSelectForm, self).__init__(*args, **kwargs)
#here i need current object
Inline class:
class ItemColorSelectInline(generic.GenericTabularInline):
model = ColorSelect
extra = 1
form = ItemColorSelectForm
Admin class
class ItemAdmin(admin.ModelAdmin):
inlines = [ItemColorInline,]
Question: how can a get current object in ItemColorSelectForm.
print kwargs return:
{'auto_id': u'id_%s', 'prefix': u'catalog-colorselect-content_type-object_id-__prefix__', 'empty_permitted': True}
Currently accepted solution is not thread safe. If you care about thread safety, never, ever assign an instance to a static class property.
Thread safe solutions are:
For Django 1.7 < 1.9 (possibly earlier versions, unclear):
from django.utils.functional import cached_property
def get_formset(self, *args, **kwargs):
FormSet = super(InlineAdmin, self).get_formset(*args, **kwargs)
class ProxyFormSet(FormSet):
def __init__(self, *args, **kwargs):
self.instance = kwargs['instance']
super(ProxyFormSet, self).__init__(*args, **kwargs)
#cached_property
def forms(self):
kwargs = {'instance': self.instance}
forms = [self._construct_form(i, **kwargs)
for i in xrange(self.total_form_count())]
return forms
return ProxyFormSet
As of Django >= 1.9 it's also possible to pass form_kwargs:
def get_formset(self, *args, **kwargs):
FormSet = super(InlineAdmin, self).get_formset(*args, **kwargs)
class ProxyFormSet(FormSet):
def __init__(self, *args, **kwargs):
form_kwargs = kwargs.pop('form_kwargs', {})
form_kwargs['instance'] = kwargs['instance']
super(ProxyFormSet, self).__init__(
*args, form_kwargs=form_kwargs, **kwargs)
return ProxyFormSet
Above solutions will make an instance kwarg available in the model form:
class InlineForm(forms.ModelForm):
def __init__(self, *args, **kwargs):
super(InlineForm, self).__init__(*args, **kwargs)
print('instance', kwargs['instance'])
Solution:
Override the formset method in Inline class
def get_formset(self, request, obj=None, **kwargs):
InlineForm.obj = obj
return super(InlineAdmin, self).get_formset(request, obj, **kwargs)
To fix: currently accepted solution not safe in multi-thread mode
Arti's solution works, another better option could be:
Instead of passing the current object id into the inline form,
use the object id to create a inline form field within the get_formset().
# admin.py
class TransactionInline(admin.TabularInline):
model = Transaction
form = TransactionInlineForm
def get_formset(self, request, obj=None, **kwargs):
# comment Arti's solution
# TransactionInlineForm.project_id = obj.id
formset = super().get_formset(request, obj, **kwargs)
field = formset.form.declared_fields['purchase']
field.queryset = get_object_or_404(Project, pk=obj.id).products.all()
return formset
# forms.py
class TransactionInlineForm(ModelForm):
purchase = ModelChoiceField(queryset=None, label='Purchase', required=False)
So, there is no need to override the __init__() in form anymore, neither the current object.
works in Django 2.1.7