Is there a way to only customize the label of form fields without specifying the field type?
For example, I have the following model for a user's privileges on handling documents:
class Privilege(models.Model):
user = models.OneToOneField(User)
privCreate = models.BooleanField(default=False)
privEdit = models.BooleanField(default=False)
privDelete = models.BooleanField(default=False)
...
And I have the following form:
class PrivilegeForm(forms.ModelForm):
privCreate = forms.BooleanField(label='Create a document')
privEdit = forms.BooleanField(label='Edit a document')
privDelete = forms.BooleanField(label='Delete a document')
...
class Meta:
model = Privilege
fields = ('privCreate', 'privEdit', 'privDelete', ...)
There are a lot of fields, and this seems to violate DRY. How can I only customize the labels without specifying forms.BooleanField if they are the same as those in the models?
You can set the labels in the __init__() using .fields:
class PrivilegeForm(forms.ModelForm):
def __init__(self, *args, **kwargs):
super(PrivilegeForm, self).__init__(*args, **kwargs)
self.fields['privCreate'].label = 'Create a document'
...
Related
I am trying to find out an efficient way to set a field value within form init method. My models are similar to below
class Users(models.Model):
firstname = models.CharField()
lastname = models.CharField()
class profile(models.model):
user = models.ForeignKey(Users, on_delete=models.PROTECT)
class logindetails(models.model):
user = models.ForeignKey(Users, on_delete=models.PROTECT)
profile = models.ForeignKey(profile, on_delete=models.PROTECT)
login_time = models.DateField(auto_now=True)
My form is like as below:
class LoginForm(forms.ModelForm):
class Meta:
model = logindetails
fields = [__all__]
def __init__(self, *args, **kwargs):
self._rowid = kwargs.pop('rowid', None)
super(LoginForm, self).__init__(*args, **kwargs)
instance = profile.objects.get(id=self._rowid)
self.fields['user'] = instance.user <--- Facing difficulties here
Any help will be appreciated.
Django had built-in ways of setting initial form values, the documentation is available here: https://docs.djangoproject.com/en/3.0/ref/forms/api/#dynamic-initial-values
My goal is to loop through all form fields and to assign certain classes to them like this:
class ContactForm(forms.Form):
def __init__(self, *args, **kwargs):
super(ContactForm, self).__init__(*args, **kwargs)
for field_name, field in self.fields.items():
field.widget.attrs['class'] = 'form-control input-sm plain'
if field.required == True:
field.widget.attrs['required'] = ''
class Meta:
model = Contact
fields = '__all__'
The issue with this code is that self.fields.items() seems to be empty (and as a result I never get into the for-loop).
My guess is that the issue arose either because of my upgrade from Django 1.9 and python 2 to Django 1.10 and python 3, or because of custom manager present in the definition of the underlying model.
Could anyone share expertise on this?
class Contact(BaseMixin, DeleteMixin):
provider_account = models.ForeignKey(ProviderAccount, models.DO_NOTHING)
client_id = models.IntegerField()
name = models.CharField(max_length=300)
profile_photo_url = models.CharField(max_length=100, default = 'no_image.jpg')
event_type_id = models.IntegerField(EventType.choices(), blank=True, null=True)
is_satisfied = models.NullBooleanField()
objects = CustomQuerySetManager()
class Meta:
managed = False
db_table = 'contact'
class QuerySet(QuerySet):
#....
Your form is a standard form, not a model form; the Meta class is ignored and the only fields are those you define yourself.
Your form should inherit from forms.ModelForm for this to work.
I write the code to edit the list of users which belong to a team. For this I create a form, as below:
class Organization(models.Model):
name = models.CharField(blank=False, verbose_name=_("Name"), help_text=_('Organization Name'), max_length=256)
class Team(models.Model):
organization = models.ForeignKey('Organization')
name = models.CharField(blank=False, verbose_name=_("Name"), help_text=_('Team Name'), max_length=256)
users = models.ManyToManyField('User', related_name='teams')
def __str__(self):
return self.name
class TeamUsersForm(forms.ModelForm):
class Meta:
model = Team
fields = ['users']
users = forms.ModelMultipleChoiceField(queryset=User.objects.filter(request.user.organization), required=False)
def clean_users(self):
users = self.cleaned_data['users']
if users.exclude(organization=request.user.organization):
raise ValidationError(_("Cannot add user from another organization"))
return users
The code above should look into request value to determine the current organization and restrict display and model store only to users from the same organization.
But the above code cannot work, because the value of request is not known at class loading time.
What do you suggest to do?
I thought of two variants:
create a local (to a function) class like the above class TeamUsersForm
dismiss using Django forms for this altogether and use more low-level API
Overide the __init__ of the TeamUsersForm and access request there.
class TeamUsersForm(forms.ModelForm):
def __init__(self, *args, **kwargs):
self.request = kwargs.pop('request')
super().__init__(*args, **kwargs)
self.fields['users'] = forms.ModelMultipleChoiceField(queryset=User.objects.filter(self.request.user.organization), required=False)
This implies that when you instantiate your form, you should it this way:
# somewhere in your views.py, probably
f = TeamUsersForm(request.POST, request=request)
i try to order properties in the admin but it does not work
model
class Physic(models.Model):
name = models.ForeignKey(Property, verbose_name=_('name'), null=True, blank=True,)
lapropriete = models.CharField(_('property'), max_length=100)....
class Essai_Temperature(models.Model):
name = models.ForeignKey(Material,
nature_unit = models.ForeignKey(Property,
choix = ChainedForeignKey(Physic, verbose_name=_('properties'), null....
form
class Essai_TemperatureForm(forms.ModelForm):
class Meta:
model = Essai_Temperature
def __init__(self, *args, **kwargs):
super(Essai_TemperatureForm, self).__init__(*args, **kwargs)
self.fields['choix'].queryset = Physic.objects.order_by('-lapropriete')
admin
class Essai_TemperatureInline(admin.TabularInline):
model = Essai_Temperature
form = Essai_TemperatureForm
extra = 5
what is the problem here ?
maybe choix ?
I have dropdown list ('Hardness Vickers (GPa)', Shear Modulus (MPa)'......
Why not just use the ordering attribute of the ModelAdmin (which will also work on the TabularInline - it previously didn't work but has been fixed)
class Essai_TemperatureInline(admin.TabularInline):
model = Essai_Temperature
form = Essai_TemperatureForm
ordering = ('-choix__lapropriete',)
extra = 5
I have two django models related with a OneToOneField. I'll show the relevant fields:
class User(AbstractBaseUser, PermissionsMixin):
email = models.EmailField(unique=True, db_index=True)
And
class PasswordRecovery(models.Model):
user = models.OneToOneField(User, primary_key=True)
token = models.CharField(default=utils.make_token)
password = models.CharField(max_length=128)
Then I have a form for the PasswordRecovery model
class PasswordRecoveryForm(forms.ModelForm):
password_check = forms.CharField(max_length=128)
class Meta:
model = PasswordRecovery
fields = ('user', 'password', 'password_check')
A few details are omitted here. Tell me if you think they are relevant.
The problem is that the user field shows as a 'select' element and I would like it to be an email field. Instead of being able to chose a user from a lista I want it instead to required the email to be typed.
How can I do this?
Thanks in advance
You should override the clean_user method to pass the User objects
class PasswordRecoveryForm(forms.ModelForm):
user = forms.EmailField(required=True)
password_check = forms.CharField(max_length=128)
class Meta:
model = PasswordRecovery
fields = ('user', 'password', 'password_check')
def clean_user(self):
user_email = self.cleaned_data['user']
if User.objects.get(email__iexact=user_email):
return User.objects.get(email__iexact=user_email)
return None
#If you wanna to fill in the email add this
def __init__(self, *args, **kwargs):
super(PasswordRecoveryForm, self).__init__(*args, **kwargs)
if self.instance:
self.fields['user'].initial = self.instance.user.email