DJANGO , custom LIST_FILTER - django

I am using only the django admin , and trying to creating a custom filter, where is to filter the date of another model.
My models
class Avaria(models.Model):
.....
class Pavimentacao(models.Model):
avaria = models.ForeignKey(Avaria, related_name='AvariaObjects',on_delete=models.CASCADE)
date= models.DateField(blank=True,null=True)
AvariaAdmin
class AvariaAdmin(admin.ModelAdmin):
list_filter = ('')

For example, Let's say you have a model and you have to add custom ContentTypeFilter to your model admin then. you can define a class which inherit SimpleListFilter and define lookups and queryset based on your requirement and add this class to list_filter like
list_filter = [ContentTypeFilter]
Refer to docs
Example class definition is like below:
class ContentTypeFilter(admin.SimpleListFilter):
# Human-readable title which will be displayed in the
# right admin sidebar just above the filter options.
title = _('content type')
# Parameter for the filter that will be used in the URL query.
parameter_name = 'type'
def lookups(self, request, model_admin):
"""
Returns a list of tuples. The first element in each
tuple is the coded value for the option that will
appear in the URL query. The second element is the
human-readable name for the option that will appear
in the right sidebar.
"""
models_meta = [
(app.model._meta, app.model.__name__) for app in get_config()
]
return (item for item in models_meta)
def queryset(self, request, queryset):
"""
Returns the filtered queryset based on the value
provided in the query string and retrievable via
`self.value()`.
"""
if not self.value():
return
model = apps.get_model(self.value())
if model:
return queryset.models(model)

You have to add the field you want to filter. In your example if you want to filter on date you put list_filter('date'). Dont forget to register the model admin as seen here

Related

Django admin different list_display based on what filter is selected?

I want to display based on a Boolean field filter different list_displays for my model in Django admin. For example, if the boolean field is false I should list_display=('name', 'age') but if is true I should display list_display=('name', 'school', 'grades') assuming that my Model have all those fields.
According to the documents best practice would be using ModelAdmin.get_list_display which allow you to change list_display per request
class MySimpleListFilter(admin.SimpleListFilter):
parameter_name = 'filter_parameter_name'
...
class MyModelAdmin(models.ModelAdmin):
list_display = ('my','default','fields')
def get_list_display(self,request):
if request.GET.get('filter_parameter_name',None) is not None:
return self.list_display + ['my_protected_column']
def my_protected_column(self,instance):
return "Protected column for "+str(instance)

How to return None if no request is made using django-filter

Hello I am a bit puzzled on how to achieve this. I have a filter built with django filter() method and by default it returns a list of objects in the database.I don't want to display the list until a filter is made/searched how do I go about that?
You can simple check url Get parameter before filter.
Here is an example using function based views.
Here Article model has title field and value of title is being checked in get parameters. If none just return empty list
class ArticleListView(FilterView):
model = Article
template_name = 'post/article_list.html'
filterset_class = ArticleFilter
def article_search(request):
user_list = Article.objects.all()
if request.GET.get('title'):
# Add more logics based on your needs
user_filter = ArticleFilter(request.GET, queryset=user_list)
return render(request, 'post/article-list-filter.html', {'filter':user_filter})
return render(request, 'post/article-list-filter.html', {'filter':[]})
There is an optional Meta argument 'strict' on FilterSet that defines the behavior if filterset is not valid, as mentioned in the docs here
from django_filters import FilterSet, STRICTNESS
class ProductFilter(FilterSet):
class Meta:
model = Product
fields = ['name', 'release_date']
strict = STRICTNESS.RETURN_NO_RESULTS
FilterView also defines a logic for filtering, where no results should be returned if strict=True property is set on the FilterView or filterset is not valid or bound, it is located here

django-autocomplete-light initial data using Select2 widget

I have a form field with autocomplete (using django-autocomplete-light app and Select2 widget), which serve as a search filter and it works as expected.
When I submit the form and search results are listed, I would like to set this form field initial value to previously submitted value - so the user can adjust some of the search parameters instead of setting up all search filters from scratch.
This form field will be used to choose one of the ~10000 values, so I need it to load values on-demand. As the form field is not prepopulated with any values, I have no idea how it would be possible to set initial value.
models.py
class Location(models.Model):
place = models.CharField(max_length=50)
postal_code = models.CharField(max_length=5)
views.py
class LocationAutocomplete(autocomplete.Select2QuerySetView):
def get_queryset(self):
qs = Location.objects.all()
if self.q:
qs = qs.filter(place__istartswith=self.q) | qs.filter(postal_code__istartswith=self.q)
return qs
forms.py
class LocationForm(forms.ModelForm):
class Meta:
model = Location
fields = ('place',)
widgets = {
'place': autocomplete.Select2(url='location_autocomplete')
}
Any suggestions?
Thanks!
In your views.py if you pass place value like this:
LocationForm(initial={'place': place })
It will be pre-populated in your form.
Docs: https://docs.djangoproject.com/en/1.11/ref/forms/fields/#initial

How to Customize Django Admin Filter

Using django 1.7.7 admin page, I want to list the data in a table where I can sort and filter.
That's exactly what the picture on the documentation shows:
https://docs.djangoproject.com/en/1.7/ref/contrib/admin/
under the list_filter section.
I tried that and got an error:
The value of 'list_display[0]' refers to 'book_type', which is not a callable.
Then, I tried this:
# model.py:
class Interp():
""" specifies the interpretation model """
BOOK_TYPES = ['drama', 'scietific']
BOOK_TYPES = tuple(zip(BOOK_TYPES, BOOK_TYPES))
comment = models.CharField(max_length=20)
book_type = models.CharField(max_length=20, choices=BOOK_TYPES,
default='not specified')
def __unicode__(self):
return self.book_type
# admin.py:
class bookTypeFilter(SimpleListFilter):
title = 'book type'
parameter_name = 'book_type'
def lookups(self, request, model_admin):
types = set([t.book_type for t in model_admin.model.objects.all()])
return zip(types, types)
def queryset(self, request, queryset):
if self.value():
return queryset.filter(book_type__id__exact=self.value())
else:
return queryset
class AdminInterpStore(admin.ModelAdmin):
""" admin page setting """
search_fields = ('comment', 'book_type')
list_display = ('book_type',)
list_filter = (bookTypeFilter, )
this shows a sidebar and lists the values but as soon as I click any of them, I get an error:
FieldError: Unsupported lookup 'id' for CharField or join on the field not permitted
How can I make a filter, preferably a table view as well?
Is the a complete sample for django1.7.7 that I can look at for filtering admin page?
You must replace
return queryset.filter(book_type__id__exact=self.value())
by
return queryset.filter(book_type=self.value())
See https://docs.djangoproject.com/en/1.8/ref/models/querysets/#field-lookups for more information.
Also, in the lookups method, using:
types = model_admin.model.objects.distinct('book_type').values_list('book_type', flat=True)
would be much more efficient as you would not retrieve the whole data from the database to then filter it.
Edit:
I realized that the book_type field is a choice field.
First, the value passed to the choices argument must be
An iterable (e.g., a list or tuple) consisting itself of iterables of exactly two items (e.g. [(A, B), (A, B) ...] A being the value stored in the database, B a human readable value)
So passing a list of strings will fail.
Second, the Django admin's default behaviour for such fields is exactly what you are trying to achieve so setting list_filter = ('book_type', ) in AdminInterpStore is enough.

How to create a sub-category filter which depends on a category filter in Django admin?

in the list filter of a model in my Django admin I have a filter Category, and I would like to add a filter Sub-category, which values depend on the selected Category value.
How can I achieve this using ModelAdmin.list_filter?
Thank you
Create a class inherting from SimpleListFilter for the Sub-Category.
Inside the method lookups check if inside the request.GET there is the matching querystring for Category, if there is, make a queryset based on this filter.
Should look something like that: (change according to your real models..might have syntax error, I didn't test the code, but it should look very similar)
class SubCategoryFilter(SimpleListFilter):
title = 'sub category'
parameter_name = 'sub_category'
def lookups(self, request, model_admin):
sub_categories = Category.objects;
if 'category' in request.GET:
sub_categories = sub_categories.filter(main_category=request.GET['category'])
return (
(sub_cat.pk,sub_cat.text) for sub_cat in sub_categories
)