Django admin page combobox, possible? - django

I have a simple model in django with a field using choices. As it is now, I am forced to use one of the available choices, how can I be able to use those choices and also be able to enter text manually?
WHERE_CHOICES = (
('CHL', 'Center HL'),
('CHD', 'Center HD')
)
class Event(models.Model):
ev_start = models.DateTimeField()
ev_end = models.DateTimeField()
where = models.CharField(max_length=3, default='CHL', choices=WHERE_CHOICES)
Thanks

You can override the admin form field widget with a datalist tag.
It would look like that (using the floppyforms library):
class EventAdminForm(ModelForm):
class Meta:
model = Event
fields = "__all__"
widgets = {
'where': floppyforms.widgets.Input(datalist=[v[0] for v in Event.WHERE_CHOICES])
}
class EventAdmin(admin.ModelAdmin):
form = EventAdminForm
admin.site.register(Event, EventAdmin)

Related

how to populate drop down choice from data base in django form

I want to try populating fields from the database in Django form, but it's showing me blankly.
Can anyone give me an idea?
Here I am sharing my code.
class circleform(forms.ModelForm):
class Meta:
model = curd
fields = ['Zone','Circle','circle_code','circle_address']
widgets = {
'Zone':forms.Select(attrs = {'class':'form-control'}),
'Circle':forms.TextInput(attrs = {'class':'form-control'}),
'circle_code':forms.TextInput(attrs = {'class':'form-control'}),
'circle_address':forms.TextInput(attrs = {'class':'form-control'}),
}
I think you could use a field overriding like
class YourForm(forms.ModelForm):
your_foreign_key_field_name = forms.ModelChoiceField(queryset=YourChoiceModel.objects.all())
class Meta:
....
or in case you just want a form that reflect all your model's fields, try using Admin
https://docs.djangoproject.com/en/4.1/intro/tutorial07/
If you are looking for a field that will populate your query based on a query then ModelChoiceField is what you are looking for. You can use it like that
class circleform(forms.ModelForm):
your_field = ModelChoiceField(queryset="you query here to populate choice field")
# ...
but if you have some hard-coded choices that you want to populate then you can pass a choices=YOUR_CHOICES_TUPLE like that.
class circleform(forms.ModelForm):
class Meta:
model = curd
fields = ['Zone','Circle','circle_code','circle_address']
YOUR_CHOICES = (
('', 'Select your zone'),
('1', 'First'), #First one is the value of the select option and the second is the displayed value in the option
('2', 'second'),
)
widgets = {
'Zone':forms.Select(attrs = {'class':'form-control'}, choices=YOUR_CHOICES), # new
}

Django inline formset multiple models

TL;DR: I need a some kind of formset for formsets.
I have two different models related to one buisness-entity, and I need to make a form to edit both models like a one form. And I need to create a lot of such forms on the one page like Django inline formset does.
Now I have the following thing:
class Parent(models.Model):
name = models.Charfield()
class FirstChild(models.Model):
name = models.Charfield()
e_id = models.IntegerField()
parent = models.ForeignKey(Parent)
class FirstChildForm(django.forms.ModelForm):
class Meta:
model = Child
fields = ('name', 'e_id', 'parent')
widgets = {'parent': forms.TextInput}
And I render a lot of them using inline formsets:
formset_class = inlineformset_factory(Parent, FirstChild,
form=FirstChildForm, extra=1)
But now I have to add second child model and a form for it, and still render it like an one inline form, but make it form actually edit two models. Like this:
class SecondChild(models.Model):
name = models.Charfield()
e_id = models.IntegerField()
parent = models.ForeignKey(Parent)
class SecondChildForm(django.forms.ModelForm):
class Meta:
model = Child
fields = ('name', 'e_id', 'parent')
widgets = {'parent': forms.TextInput}
formset_class = inlineformset_factory(models=[Parent, FirstChild],
forms=[FirstChildForm, SecondChildForm],
extra=1)
As far as I understand, Django formsets cannot work with multiple models right now.
So which way should I choose to implement this behaviour and do not broke all django conceptions?, I cannot use some extra libraries so I have to implement everything by myself and I use django 1.6 if it is important.
So, finally I used this approach as a base: https://micropyramid.com/blog/how-to-use-nested-formsets-in-django/

Adding custom data to django model field

I'd like to add some info to a model field to use at form rendering time. My real model has about 15 values of varying field types (adding and removing as I dev), and it does almost everything I need, so I'd rather not create custom model fields for all of them.
I'd like to do something like this:
from django.db import models
class MyModel(models.Model):
cost = models.DecimalField(max_digits=5,
decimal_places=2,
custom_info= {'glyph': 'glyphicon glyphicon-usd' }
)
And then in my form template use that glyph much like I'd use a verbose_name or help_text.
Something I learned from a post just the other day. Will defining the custom information on the form instead of the model work?
When you define formfield_callback on a forms.ModelForm it will iterate over the form fields and you can manipulate them. This comes in handy when you need to add a css class to widgets and don't want to explicitly override the field. Now you only need to put formfield_callback = modify_form_field on any forms.ModelForm where you want the custom_info to show up.
from django.db import models
def add_glyphicons(model_field):
form_field = model_field.formfield()
if isinstance(model_field, models.IntegerField):
form_field.custom_info = {'glyph': 'glyphicon glyphicon-usd'}
elif isinstance(model_field, models.CharField):
form_field.custom_info = {'glyph': 'glyphicon glyphicon-yen'}
return form_field
class MyModel(models.Model):
formfield_callback = add_glyphicons
class Meta:
model = MyModel
class MyOtherModel(models.Model):
formfield_callback = add_glyphicons
class Meta:
model = MyOtherModel

Django: Change field label in admin doesn't work

Unfortunately, I'm still using django 1.4 and the verbose_name doesn't work for foreign keys.
It is there a way to change the label of a foreign key. For now, it is not working:
class ProductVariant(models.Model):
product = models.ForeignKey(TestProduct, verbose_name='test product', on_delete=models.PROTECT)
ProductVariant
class ProductVariantForm(forms.ModelForm):
product = forms.ModelChoiceField(queryset=TestProduct.objects.order_by("product__article_code"))
test_software = forms.ModelChoiceField(queryset=TestSoftware.objects.order_by("name"))
class Meta:
model = ProductVariant
class ProductVariantAdmin(admin.ModelAdmin):
fields=["product", "test_software", "test_variables", "name", "description"]
list_display = ("name", "product_name", "test_software_name", "test_variables", "description")
search_fields = ["name"]
form = ProductVariantForm
I hope you can help me.
Thanks in advance!
verbose_name should work with Django 1.4 according to the 1.4 docs.
I think because you're overriding the field in the form it's not using the verbose name for the label. What you could do is set the label on the ModelChoiceField.
class ProductVariantForm(forms.ModelForm):
product = forms.ModelChoiceField(label="Test Product", queryset=TestProduct.objects.order_by("product__article_code"))
test_software = forms.ModelChoiceField(queryset=TestSoftware.objects.order_by("name"))
class Meta:
model = ProductVariant
I'm not quite sure how to use the model's verbose name on the field though, so you might have to define it twice.

Model form - How to change default ManyToMany widget?

I use Django Model Form:
class Fruit(models.Model):
name = models.CharField(max_length=40)
class Box(models.Model):
user = models.ForeignKey(User)
name = models.CharField(max_length=199)
fruit = models.ManyToManyField(Fruit)
and forms.py:
class BoxModelForm(ModelForm):
class Meta:
model = Box
I have default django ManyToMany widget in form:
http://nov.imghost.us/ly5M.png
How can I change this to input (text type) and if I type into this input:
apple,banana,lemon - comma separated
this Fruit will be created?
As stated here in the documentation :https://docs.djangoproject.com/en/dev/topics/forms/modelforms/#overriding-the-default-fields
You can add a widgets attribute to the Meta of your Modelform to change the default widgets used in the form.
In your case it would be something like this :
class BoxModelForm(ModelForm):
class Meta:
model = Box
widgets = {
'fruit': TheWidgetYouWantToUse(),
}
But actually for the behavior you want to achieve, you could proceed another way.
You should add an extra text field, and write the addition/removal of fruits in the save step, while checking the validity of the differents tags in the clean step.
class BoxModelForm(ModelForm):
fruit_selector = forms.TextField(
max_length=255,
tag = 'Whatever'
)
class Meta:
model = Box
fields = ['user','name']
def clean_fruit_selector(self):
data = self.cleaned_data['fruit_selector']
# Check that data are corrects ie the string is correctly formatted
# If not raise validation error
....
fruit_tags = data.split(",")
#Check that all tags are fruit or raise a validation error
...
return data #or only the list of correct tags
def save(self, commit=True):
instance = super(MyForm, self).save(commit=False)
# Compare the list of tags fruit_tags with self.instance.fruit.all()
....
# Take the right actions
if commit:
instance.save()
return instance
Look into this page for more details on how to change the field validation https://docs.djangoproject.com/en/dev/ref/forms/validation/
This is just a schematic.
django-taggit is a perfect app for this use case.
Define your models like this:
from taggit.managers import TaggableManager
from taggit.models import TagBase, GenericTaggedItemBase
class Fruit(TagBase):
class Meta:
verbose_name = "Fruit"
verbose_name_plural = "Fruits"
class TaggedFruit(GenericTaggedItemBase):
tag = models.ForeignKey(Fruit,
related_name="%(app_label)s_%(class)s_items")
class Box(models.Model):
name = models.CharField(max_length=199)
fruits = TaggableManager(through=TaggedFruit)
Then create basic model form:
class BoxModelForm(ModelForm):
class Meta:
model = Box
And that's it! You can now add fruit tags into your box, separated by comma. In case the fruit doesn't exist, it will be added into Fruit table. Read the docs for more details on how to use django-taggit.
You can use it together with jquery based Selectize.js.