Assign different CSS classes to Django ModelChoiceField from its queryset - python

I don't know if I am trying the impossible but I have HTML select option that comes from Django's forms.Form's queryset, States.objects.all().
Model:
class Countries(models.Model):
name = models.CharField(max_length=25)
Model:
class States(models.Model):
country_id = models.ForeignKey('Countries')
name = models.CharField(max_length=25)
Form:
class sign_up_form_school(forms.Form):
states = forms.ModelChoiceField(
queryset = States.objects.all(),
widget=forms.Select(attrs={
'class': states.country_id.name #is this POSSIBLE?
}))
I want each select option value to have different class as I have tried above but it returns error: name 'states' is not defined.

I think this answer will also be answer to your problem: Django form field choices, adding an attribute
You would just need to add class instead of title and change rendering a bit.

Related

Select2 and django_filters not querying foreign keys

I'm using django_filters for an advanced search and select2Widget to display the options of a foreign key field.
The proper values load but whenever I submit the form I get an error message: Select a valid choice. That choice is not one of the available choices.
The error might seem pretty obvious but I can't find out how to solve it. Any suggestions?
filters.py
class MyFilter(django_filters.FilterSet):
b = django_filters.ModelChoiceFilter(
queryset=ModelA.objects.values_list('b__name', flat=True)
widget=Select2Widget()
)
class Meta:
model = ModelA
fields = ('b',)
models.py
class ModelA(models.Model):
b = models.ForeignKey('ModelB', on_delete=models.CASCADE)
class ModelB(models.Model):
name = models.CharField(max_length=100, unique=True)
def __str__(self):
return self.name
AS user #dirkgroten pointed out in a comment to the question, the following line looks strange:
queryset=ModelA.objects.values_list('b__name', flat=True)
This way the widget has no way of knowing the pk of each element of the list (since it only return the names). That might couse that the view cannot save a selected ModelB instance, since it does not know the selected pk.
Ah, you might also want to use ModelB instead of ModelA
Try changing it to something like this
queryset=ModelB.objects.values('pk', 'b__name')
or even this
queryset=ModelB.objects.all()
and let us know if that works.

Can't disable ForeignKey referential integrity check in Django 1.9

I have a model with two entities, Person and Code. Person is referenced by Code twice, a Person can be either the user of the code or the approver.
What I want to achieve is the following:
if the user provides an existing Person.cusman, no further action is needed.
if the user provides an unknown Person.cusman, a helper code looks up other attributes of the Person (from an external database), and creates a new Person entity.
I have implemented a function triggered by pre_save signal, which creates the missing Person on the fly. It works fine as long as I use python manage.py shell to create a Code with nonexistent Person.
However, when I try to add a new Code using the admin form or a CreateView descendant I always get the following validation error on the HTML form:
Select a valid choice. That choice is not one of the available choices.
Obviously there's a validation happening between clicking on the Save button and the Code.save() method, but I can't figure out which is it. Can you help me which method should I override to accept invalid foreign keys until pre_save creates the referenced entity?
models.py
class Person(models.Model):
cusman = models.CharField(
max_length=10,
primary_key=True)
name = models.CharField(max_length=30)
email = models.EmailField()
def __unicode__(self):
return u'{0} ({1})'.format(self.name, self.cusman)
class Code(models.Model):
user = models.ForeignKey(
Person,
on_delete=models.PROTECT,
db_constraint=False)
approver = models.ForeignKey(
Person,
on_delete=models.PROTECT,
related_name='approves',
db_constraint=False)
signals.py
#receiver(pre_save, sender=Code)
def create_referenced_person(sender, instance, **kwargs):
def create_person_if_doesnt_exist(cusman):
try:
Person = Person.objects.get(pk=cusman)
except Person.DoesNotExist:
Person = Person()
cr = CusmanResolver()
Person_details = cr.get_person_details(cusman)
Person.cusman = Person_details['cusman']
Person.name = Person_details['name']
Person.email = Person_details['email']
Person.save()
create_Person_if_doesnt_exist(instance.user_id)
create_Person_if_doesnt_exist(instance.approver_id)
views.py
class CodeAddForm(ModelForm):
class Meta:
model = Code
fields = [
'user',
'approver',
]
widgets = {
'user': TextInput,
'approver': TextInput
}
class CodeAddView(generic.CreateView):
template_name = 'teladm/code_add.html'
form_class = CodeAddForm
You misunderstood one thing: You shouldn't use TextField to populate ForeignKey, because django foreign keys are populated using dropdown/radio button to refer to the id of the object in another model. The error you got means you provided wrong information that doesn't match any id in another model(Person in your case).
What you can do is: not using ModelForm but Form. You might have some extra work to do after you call form.is_valid(), but at least you could code up your logic however you want.

Django: how can I a create categories field/dropdown menu?

This is a very simple question, how can I create dropdown field in Django with only specific categories(something similar to the countries dropdown, but not with countries).
With the choice attribute of a Field if it is for fixed values. Or with a ForeignKey field if the Categories should be created dynamicly.
For the ForeignKey field you would do the following:
from django.db import models
class Category(models.Model):
name = models.Charfield(max_length=255)
# ...
def __str__(self):
return self.name
class Item(models.Model):
category = models.ForeignKey(Category)
# ...
Django's most powerful feature is to offer you direct forms.
It's a broad question but you want to define a model that can be paired with a form that you can put in a template.
Take a look here: https://docs.djangoproject.com/en/1.8/topics/forms/ and here:
Django options field with categories and here Creating a dynamic choice field

how can I make a Django model form with a field name in the form different from the model field name?

I have a model and a form like this:
class Content(models.Model):
title = models.CharField(_("title"), max_length=16)
category = models.ForeignKey(Category, verbose_name = _('category'))
class ContentForm(forms.ModelForm):
class Meta:
model=Content
fields = ('title', 'category', )
I would like to have the name of the field in the form to be f_category (of course the name of the field in the model is to stay category). Is it possible to do that, without having to construct the whole form manually (which is difficult because the field is a ForeignKey and has to be a select field with a list of options)?
To clarify: by name I mean the name as in the HTML form code: <input type="select" name="f_category" />
Your comment reveals what you actually need to do - this is why you should always describe your actual problem, not your proposed solution. Naturally, there is a proper way to deal with two identical forms on the same page in Django - use the prefix parameter when instantiating the field.
form1 = MyForm(prefix='form1')
form2 = MyForm(prefix='form2')
Now when you output form1 and form2, all the fields will automatically get the relevant prefix, so they are properly separated.
I'm not sure what you mean by "the name of the field in the form". Do you mean the label? Or the id? Or something else? Configuring the label is pretty easy:
class ContentForm(forms.ModelForm):
category = forms.ModelChoice(queryset=Category.objects.all(), label='f_category')
class Meta:
model=Content
fields = ('title', 'category', )

Can you change a field label in the Django Admin application?

As the title suggests. I want to be able to change the label of a single field in the admin application. I'm aware of the Form.field attribute, but how do I get my Model or ModelAdmin to pass along that information?
the verbose name of the field is the (optional) first parameter at field construction.
If your field is a property (a method) then you should use short_description:
class Person(models.Model):
...
def address_report(self, instance):
...
# short_description functions like a model field's verbose_name
address_report.short_description = "Address"
As Javier suggested you can use verbose name in your fields in model.py. Example as below,
class Employee(models.Model):
name = models.CharField(max_length = 100)
dob = models.DateField('Date Of Birth')
doj = models.DateField(verbose_name='Date Of Joining')
mobile=models.IntegerField(max_length = 12)
email = models.EmailField(max_length=50)
bill = models.BooleanField(db_index=True,default=False)
proj = models.ForeignKey(Project, verbose_name='Project')
Here the dob,doj and proj files will display its name in admin form as per the verbose_name mentioned to those fields.
from django.db import models
class MyClassName(models.Model):
field_name = models.IntegerField(verbose_name='Field Caption')
Building on Javier's answer; if you need one label in forms (on the front-end) and another label on admin it is best to set internal (admin) one in the model and overwrite it on forms. Admin will of course use the label in the model field automatically.
Use "verbose_name" to change a field name as the example below.
"models.py":
from django.db import models
class MyModel(models.Model): # Here
name = models.CharField(max_length=255, verbose_name="My Name")
If you want change the field label only on particular admin model without changing field of the model:
class MyModelAdmin(admin.ModelAdmin):
def get_form(self, request, obj=None, **kwargs):
form = super().get_form(request, obj, **kwargs)
form.base_fields["name"].label = "New label"
return form

Categories

Resources