A Select Widget with fields as checkboxes with multiple options possible - django

I have the following model:
class Owner(models.Model)
country = models.CharField(max_length=255, choices=COUNTRIES, default=COUNTRIES_DEFAULT)
COUNTRIES is compose of tuples:
COUNTRIES = (
('afg', 'Afghanistan'),
('ala', 'Aland Islands'),
('alb', 'Albania'),
('dza', 'Algeria'),
('asm', 'American Samoa'),
....... )
For FrontEnd, I need to show a Widget, and for each country to have a checkbox.
A Person/User can select multiple Countries.
I presume I need to use a custom widget, but I don't know where to start inherit for Field/Widget and make the query in the database.
--- Why is not a duplicate of Django Multiple Field question ----
I don't need a new Model field, or to store it in the database and is not a many to many relation, so something like the package django-multiselectfield is not useful.
The ModelField is storing just one value, but in the form will appear values from the tuple.I added just to see the correspondence.
Instead I need to be just a Form Field, to get the values, and query the database. Like get all owners that resides in USA and UK.
Also is not looking like Select2, I need to respect design. As functionality is like in the image:

In your Form you must define a MultipleChoiceField with the CheckboxSelectMultiple widget:
countries = forms.MultipleChoiceField(choices=COUNTRIES, widget=forms.CheckboxSelectMultiple)
This will give you a list of multiple choice checkboxes. You can style that yourself to appear with a scrollbar if you don't want to show a long list.
Here is an example from the Django documentation: https://docs.djangoproject.com/en/2.1/ref/forms/widgets/#setting-arguments-for-widgets

Related

Django: Create Choices For Filter Based on Distinct Model Values

Objective: I want to have a ModelChoiceFilter rendered on the page where the options/choices for the user to select are the distinct values of a field in the model.
The app allows users to track the cities that they have visited. I want users to be able to filter the model on country and for the filter options to only be countries that are in the model.
I am using django-filters and do successfully have a MultipleChoiceFilter working where the choices work when hard-coded (either in the models.py or in the FilterForm class:
class cityFilter(django_filters.FilterSet):
continent = MultipleChoiceFilter(
choices=cityModel.continent_choices,
widget=forms.CheckboxSelectMultiple,
label='Continent')
class Meta:
model = cityModel
fields = ['city', 'country', 'continent']
One can also set the choices directly in the FilterSet class like this:
country = MultipleChoiceFilter(
choices=(('GB','United Kingdom'),('FR','France')),
widget=forms.CheckboxSelectMultiple,
label='Country'
)
This works okay for continents but I want to allow a filter for countries. I only want to expose to the user the distinct set of countries in the model (as opposed to hard coding every country).
I could do something like this to get all the distinct countries in the model:
country_choices = cityModel.objects.values('country').distinct()
But I'm not sure where this should be placed in the app to get queried on the page load, and would then need to take each value in the queryset and iterate to turn it into a 'choice' tuple.
Is there a better pattern/approach?
If you want dynamic choices and the choices data from Model, you can try to use queryset in the ModelMultipleChoiceFilter like this:
continent = ModelMultipleChoiceFilter(
queryset=cityModel.objects.values('country').distinct(),
widget=forms.CheckboxSelectMultiple,
label='Continent')

How to filter choices in fields(forms) in Django admin?

I have model Tech, with name(Charfield) and firm(ForeignKey to model Firm), because one Tech(for example, smartphone) can have many firms(for example Samsung, apple, etc.)
How can I create filter in admin panel for when I creating model, If I choose 'smartphone' in tech field, it show me in firm field only smartphone firms? Coz if I have more than one value in firm field (for example Apple, Samsung, IBM), it show me all of it. But IBM must show only if in tech field I choose 'computer'. How release it?
class MyModelName(admin.ModelAdmin):
list_filter = (field1,field3,....)
refer:-
https://docs.djangoproject.com/en/2.1/ref/contrib/admin/
You can define the choices of the input with the attribute 'choices' of the widget. When you create the admin form of the model, you could define manually the fields, and also you can define the widget for each input. In the widget you could define with a tuple the choices and the initial values.

Django disable widget caching?

So I have a form where I defined a select widget like this:
class AdHocVoucherTemplateForm(ModelForm):
class Meta:
model = AdHocVoucherTemplate
widgets = {
'retailer_id': Select(choices=[(r.pk, r.name) for r in Retailer.objects.all()]),
}
This way I achieve a select input field with all retailers. User can select a retailer from a drop down list and submit the form.
The problem I noticed is that when I add a new retailer (Retailer.objects.create etc), it doesn't appear in the form in the drop down list. It appears to be cached. When I restart the uwsgi service running Django, it is there.
How can I make the widget always refresh the newest values from the database?
I don't see this caching behavior when I do something similar with a ModelChoiceField.
It's default widget is a Select.
Something like:
retailer = forms.ModelChoiceField(queryset=Retailer.objects.all())
When your code is evaluated, that choices parameter is constructed once and then your select just has a static list of retailer (id,name) tuples. When the ModelChoiceField is constructed, it is referencing a QuerySet which is not evaluated until the list of choices is actually requested/displayed.

dependent fields in django admin

I want to add, some fields depending on others. I have city and country model. I can include country as foreign key in city model. And then if I will add both city and country in another model ( say content) then will it be just like dependent selectboxes? like cities will be shown based on selected country via ajax? If not then what is correct way? and also is there a way to add city on the spot while adding main content data if city is not already on list?
So are above possible by using django admin or is it that django don't give? If not then how can it be done in django autogenerated admin?
You can do exactly what you ask using django-smart-selects
Hope that helps...
I can include country as foreign key in city model
This seems like a good idea.
And then if I will add both city and country in another model ( say content) then will it be just like dependent selectboxes? like cities will be shown based on selected country via ajax?
No, it will not get filtered automatically, you will need to write that code yourself. Both in admin and on frontend.
and also is there a way to add city on the spot while adding main content data if city is not already on list?
You will get this in the admin area.
Go ahead and start doing it, and when you run into specific problems, post them here if you can't solve it. Also read the Django docs, it is pretty elaborate on the topic of models.

django: iterating over items in ManyToMany table without intermediate model (without using 'through')

I have a simple case with 2 models: Item and Category with ManyToMany between them. I want to show a page listing all categories and for each category list of items. I have hundreds of categories so django hits db hundreds of times (when iterating thru categories and calling items.all() for each one). I need to select data from the intermediate table manually and use select_related() to pull item and category for each record - one query instead of hundreds.
I know that introducing 'through' would solve the problem but I don't want to do it now because it may break existing code (using through makes you can't use add, create, or assignment to create relationships - which I want to avoid for now).
So, is it possible at all without creating a model for intermediate table?
You could make a model for your existing table, and just not use it as the through field for the m2m, and make it unmanaged. eg:
class ItemCategory(models.Model):
item = models.ForeignKey('Item')
category = models.ForeignKey('Category')
class Meta:
db_table = 'the_name_of_the_existing_m2m_table'
managed = False
Something like that, anyway.