Override `render_FOO` for a related field - django

I have a table like that:
import django_tables2 as tables
from .models import MyModel
class MyTable(tables.Table):
class Meta:
model = MyModel
fields = ['myfield', 'relatedtable.otherfield']
Since I can not have render_relatedtable.otherfield and render_relatedtable__otherfield does not work, how can I override render_<column_name> or value_<colum_name> for relatedtable.otherfield? Is it even possible?
I tried following approaches, but none of them worked:
Override attributes in __init__()
class MyTable(tables.Table):
class Meta:
model = MyModel
fields = ['myfield', 'relatedtable.otherfield']
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.columns['relatedtable.otherfield'].render = myrenderfnc
# and/or
self.columns['relatedtable.otherfield'].column.render = myrenderfnc
Custom column
class MyColumn(tables.Column):
def render(self, record):
return getattr(record, 'relatedtable.otherfield')
class MyTable(tables.Table):
class Meta:
model = MyModel
fields = ['myfield']
otherfield = MyColumn()
'Renaming' column
class MyTable(tables.Table):
class Meta:
model = MyModel
fields = ['myfield']
def __init__(self, *args, **kwargs):
exclude = ['relatedtable.otherfield']
extra_columns = [('otherfield', self.base_columns['relatedtable.otherfield')]
super().__init__(*args, exclude=exclude, extra_columns=extra_columns, **kwargs)
self.columns['relatedtable.otherfield'].render = myrenderfnc
# and/or
self.columns['relatedtable.otherfield'].column.render = myrenderfnc

One way to do it is explicitly define the column with an accessor, and then use the column name in your render_FOO method name like this:
class MyTable(tables.Table):
otherfield = MyColumn(accessor='relatedtable.otherfield')
class Meta:
model = MyModel
fields = ['myfield']
def render_otherfield(self, record, value):
return value
Your 'custom column' example example should also work though.

Related

How can i change queryset on SelectField?

I have a form, and a select input, i need change the queryset of tthat select, how can i make this?
my form exemple:
class myModelForm(forms.ModelForm):
class Meta:
model = myModel
fields = '__all__'
Try overriding __init__ and setting the queryset on your field:
class myModelForm(forms.ModelForm):
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.fields['<your_field_name'].queryset = <your_queryset>
if you want to make a form to catch only some of the field of the model you have to specify such field:
class Meta:
model = myModel
fields = ['field1','field3','field12']
if you mean that you want to make a change into the form after you get it into your view:
form = myModelForm(request.POST)
form.cleaned_data['field1'] = 'change what you want'

Django manytomany field is absent in modelform

Suppose I have following Model
class Member(models.Model):
name = ...
qualities = models.ManyToManyField(ProfessionalQuality, related_name='members')
And following form:
class CommonMemberForm(forms.ModelForm):
"""This form for gathering common features in both admin and member forms
"""
class Meta:
model = Member
fields = '__all__'
def __init__(self, *args, **kwargs):
super(CommonMemberForm, self).__init__(*args, **kwargs)
self.fields['qualities'].validators.append(...)
When I try to instantiate form, I get KeyError: 'qualities' are not in self.fields. Why is that?
This code works in admin.
What is the correct way of handling such fields?
Try this:
class CommonMemberForm(forms.ModelForm):
"""This form for gathering common features in both admin and member forms
"""
class Meta:
model = Member
fields = '__all__'
widgets = {
'qualities': forms.CheckboxSelectMultiple()
}
def __init__(self, *args, **kwargs):
super(CommonMemberForm, self).__init__(*args, **kwargs)
#self.fields['qualities'].widget...
This works for me:
class CommonMemberForm(AbstractUser):
class Meta:
model = Member
fields = '__all__'
def __init__(self, *args, **kwargs):
super(RegularUser, self).__init__(*args, **kwargs)
self._meta.get_field('qualities').validators = [validate_qualities]

How do I add a help_text to a ModelForm?

I know how to add a 'class' or other widget attribute to an automatically built ModelForm:
class ExampleSettingForm(ModelForm):
def __init__(self, *args, **kwargs):
super(ExampleSettingForm, self).__init__(*args, **kwargs)
self.fields['example_field'].widget.attrs['class'] = 'css_class'
class Meta:
model = Example
How do I insert a help_text= into the example_field Field?
As of Django 1.6: You can edit it within the Meta class. Try:
class ExampleSettingForm(ModelForm):
def __init__(self, *args, **kwargs):
super(ExampleSettingForm, self).__init__(*args, **kwargs)
self.fields['example_field'].widget.attrs['class'] = 'css_class'
class Meta:
model = Example
help_texts = {
'example_field': ('Here is some help'),
}
Docs on this are at https://docs.djangoproject.com/en/dev/topics/forms/modelforms/#overriding-the-default-fields. See release notes at http://django.readthedocs.org/en/latest/releases/1.6.html . You can set your own label, help_text and error_messages.
This is what I did in Django 1.9:
class MyModelForm(forms.ModelForm):
class Meta:
model = MyModel
fields = ('__all__')
help_texts = {
"my_field": "This is case sensitive..."
}

Overriding max_value in django form

I use a ModelForm and I want to set a max_value for an IntegerField without losing the other attributes which where created from the model (verbose_name, etc.).
This is my ModelForm:
class DataForm(ModelForm):
def __init__(self, *args, **kwargs):
super(DataForm, self).__init__(*args, **kwargs)
self.fields['start_range_points'].max_value = 1000
class Meta():
model = DataModel
This doesn't work, django does not apply the validation for large numbers. If I create the field in the following way the validation works but I lose the information which was created from the Model.
class DataForm(ModelForm):
start_range_points = forms.IntegerField(min_value=0, max_value=1000)
class Meta():
model = DataModel
What can I do to achieve something similar to attempt #1?
The validator for max_value is added in IntegerField's __init__ function if max_value is present. So you will need to manually add the validator, something like:
from django.core.validators import MaxValueValidator
class DataForm(ModelForm):
def __init__(self, *args, **kwargs):
super(DataForm, self).__init__(*args, **kwargs)
validators = [ v for v in self.fields['start_range_points'].validators if not isinstance(v, MaxValueValidator) ]
validators.append( MaxValueValidator(1000) )
self.fields['start_range_points'].validators = validators
class Meta():
model = DataModel

How to create validator on form fields in model forms

How to validate model field title? What if for example, every use of the title field started with the word ‘Blog’.
models.py
class TitleAbstract(models.Model):
title = models.CharField(max_length=255)
class Meta:
abstract = True
class Blog(TitleAbstract):
..............
forms.py
class BlogForm(forms.ModelForm):
class Meta:
model = Blog
views.py
class BlogCreateView(CreateView):
model = Blog
action = 'created'
validators.py
from django.core.exceptions import ValidationError
def validate_title(value):
if not value.lower().startswith(u'blog'):
msg = u"Enter a value starting with 'Blog'"
raise ValidationError(msg)
forms.py
class BlogForm(forms.ModelForm):
def __init__(self, *args, **kwargs):
super(BlogForm, self).__init__(*args, **kwargs)
self.fields['title'].validators = [validate_title]
class Meta:
model = Blog
views.py
class BlogCreateView(CreateView):
model = Blog
action = 'created'
form_class = BlogForm