I have Django application and admin page.
Inside admin page, I have one model that has autocomplete_fields. I can sort results but, I can't sort the results.
It always sort by pk and not by value that I set.
#admin.register(Assortment)
class AssortmentAdmin(ImportExportActionModelAdmin):
list_display = ['name']
exclude = ['customers']
# inlines = [ProductAssortmentInLine]
autocomplete_fields = ['products']
#admin.register(Product)
class ProductAdmin(ImportExportActionModelAdmin):
exclude = ['associated_products', 'subsidiary_excluded', 'customers']
list_display = ['product_ref', 'name', 'price', 'group', 'retail_unit', 'active']
list_editable = ['price', 'retail_unit', 'active']
list_filter = ['group']
search_fields = ['product_ref', 'name', 'group']
resource_class = ProductResource
# inlines = [CustomerInLine]
def get_queryset(self, request):
qs = super(ProductAdmin, self).get_queryset(request)
qs = qs.order_by(Cast(F('product_ref'), IntegerField()))
return qs
How to solve this?
According to the django docs the ordering for autocomplete fields is set by the get_ordering method of the Product Admin not get_queryset. Hope this helps but not sure how you would integrate the complex query that you have into it.
https://docs.djangoproject.com/en/3.1/ref/contrib/admin/#django.contrib.admin.ModelAdmin.autocomplete_fields
Related
I have a Billing model with a boolean field
class Billing(models.Model):
...
is_paid = models.BooleanField(verbose_name='Statut', default=False, choices=[(True, 'Payée'), ('False', 'Non payée')])
...
This is Django Admin
class BillingAdmin(BaseOnlyModelAdmin):
...
list_display = ['month', 'year', 'date', 'is_paid']
list_filter = ['is_paid']
...
is_paid is correcly displayed as Payée / Non payée when listing
But for list_filter it's translated to Oui / Non
How can I change this behaviour ? I want it to display choices, so it would look like this
I was able to fix is by implementing a custom list filter
from django.contrib.admin import SimpleListFilter
class BillingStatusFilter(SimpleListFilter):
title = 'Statut'
parameter_name = 'is_paid'
def queryset(self, request, queryset):
if self.value():
return queryset.filter(is_paid__exact=self.value())
def lookups(self, request, model_admin):
return model_admin.model.STATUS
list_filter = [BillingStatusFilter]
class EventViewSet(viewsets.ModelViewSet):
queryset = Event.objects.all()
serializer_class = EventSerializer
def get_queryset(self):
return super().get_queryset().annotate(
is_active=ExpressionWrapper(
Q(start_date__lt=timezone.now()) & Q(end_date__gt=timezone.now()),
output_field=BooleanField()
),
)
search_fields = [
'name',
'short_desc',
'desc',
]
filterset_fields = [
'is_active',
]
I have this ViewSet that I want to filter on an annotated field, normally you can simply just filter on the annotation in django querysets, however the above combined with this serializer:
class EventSerializer(serializers.ModelSerializer):
is_active = serializers.SerializerMethodField()
#staticmethod
def get_is_active(obj):
return obj.is_active
class Meta:
model = Event
fields = [
'timestamp',
'id',
'name',
'short_desc',
'desc',
'start_date',
'end_date',
'is_active',
]
I haven't looked deep into the source code but I'd assume it would do a simple qs.filter for the fields in filterset_fields but I'm getting this beautiful error that fails to explain much(at least to me):
'Meta.fields' contains fields that are not defined on this FilterSet: is_active
Apparently you simply don't add the declared filters on the Meta.fields list. Literally inside the docs and I found out about it by reading the code.
Also, when adding an annotated field to the declared_fields AKA the filterset class body, add a label or django-filters can't produce field label properly and just goes with "invalid name" instead of you know, the field name. Who knows why.
I'm experiencing a weird problem where one of my serializers is not getting the context and thus failing.
First, the viewset, I've implemented a list method where I'm filtering orders based on some criteria that is dependent on nested relations in the model.
class OrdersInAgendaViewSet(OrderMixin, viewsets.ReadOnlyModelViewSet):
queryset = Order.objects.all()
serializer_class = OrderInAgendaSerializer
permission_classes = (
CanManageOrder,
)
def list(self, request):
final_orders = set()
qs = super(OrdersInAgendaViewSet, self).get_queryset()
# Get only orders that have lines with products that have no rentals objects
for order in qs:
accommodations = False
lines = order.lines.all()
for line in lines:
if line.product.rental:
accommodations = True
break
if not accommodations:
final_orders.add(order.pk)
qs = qs.filter(pk__in=final_orders)
serializer = self.serializer_class(qs, many=True)
return Response(serializer.data)
And now the main Serializer for this ViewSet
class OrderInAgendaSerializer(serializers.ModelSerializer):
lines = LineForAgendaSerializer(many=True, read_only=True)
customer = CustomerInOrderSerializer(many=False, read_only=False)
notes = OrderNoteSerializer(many=True, read_only=True)
class Meta:
model = Order
fields = (
'id',
'date_placed',
'status',
'payment_status',
'email_billing',
'notes',
'customer',
'lines',
)
extra_kwargs = {'date_placed': {'required': False}}
As you can see I'm using 3 more serializers on this one, the one that is failing is LineForAgendaSerializer:
class LineForAgendaSerializer(serializers.ModelSerializer):
product = ProductForAgendaSerializer(many=False, read_only=True)
customers = serializers.SerializerMethodField()
class Meta:
model = Line
fields = (
'starting_date',
'ending_date',
'product',
'customers',
'rents',
)
def get_customers(self, obj):
customers = obj.customerinline_set.all()
session_filter = self.context['request']\
.query_params.get('session', None)
if session_filter is not None:
customers = customers.filter(
sessions__id=session_filter).distinct()
serializer = CustomerInLineForAgendaSerializer(customers, many=True, context=self.context)
return serializer.data
The offending line is in the get_customers method:
session_filter = self.context['request']\
.query_params.get('session', None)
Checking self.context, is empty, so I get KeyError all the time...
How can I pass the context to this serializer...should it be done from the Viewset (if so how?) or from the OrderInAgendaSerializer (and again, how?)
Thanks
Yes you should pass context from your viewset.
On this line :
serializer = self.serializer_class(qs, many=True, context={your context})
Alternatively you can user self.get_serializer() method that should work.
If there are two models
models.py
class ModelA(models.Model):
pass
class ModelB(models.Model):
a = models.ForeignKey(ModelA, null=True)
admin.py
class ModelBAdmin(admin.ModelAdmin):
list_display = ('id', 'a', )
list_display_links = None
ordering = ('-id', )
admin.site.register(ModelB, ModelBAdmin)
class ModelAAdmin(admin.ModelAdmin):
list_display = ('id', )
list_display_links = None
admin.site.register(ModelA, ModelAAdmin)
Is there a way to link a with its detail view in list view of ModelB? If not, then can we do the same in detail view of ModelB? That is, display a as a link to its detail view?
Currently in list view of ModelB there is only id of ModelA. And to view its detail I have to go to ModelA list view and search for the id. What I want id in list view of ModelB to point to detail view of a (like /admin/ModelA/{a.id})
The fields in the list view can be callables, so you can do this:
from django.core.urlresolvers import reverse
class ModelBAdmin(admin.ModelAdmin):
list_display = ('id', 'a_link', )
list_display_links = None
ordering = ('-id', )
def a_link(obj):
return format_html('{}', reverse(
'admin:myapp_a_change', args=[obj.a.id]), obj.a.name)
a_link.short_description = "Model A Details"
admin.site.register(ModelB, ModelBAdmin)
I would like to request assistance in this matter
I have the following models:
class Job(models.Model):
Job_Position = models.CharField(max_length=30, null=True, unique=True)
class Job_Posting(models.Model):
fkey = models.ForeignKey("Job", verbose_name="Job Positions", unique=True)
and Admin:
class jobs(admin.TabularInline):
model = Job_Posting
readonly_fields = [ 'fkey',]
extra = 0
class applicant(admin.ModelAdmin):
model = Job
list_display = ('Job_Position')
list_filter = ['Job_Position']
inlines = [jobs]
Is it possible to add a list filter option from inline? Something like this list_filter = ['Job_Position', 'Job_Posting.fkey'] or for example, the current list_filter I have shows all items under Job_Position(selecting a Job_Position shows all record that have that position) and I want to add another option filtering all Job_Position that have that specific Job_Posting.fkey while giving me an option to see all the records
Can you do this or it's not just possible? or if there are other options what would it be? Thanks in advance.
EDIT
I need something like this, filtering all Job that has that Job_Posting, fkey in list_filter
I have found what I am looking for Here, to filter Job through Job_Posting fkey, I just need to add Job_Posting__fkey in my list_filter looking like this:
class applicant(admin.ModelAdmin):
model = Job
list_display = ('Job_Position')
list_filter = ['Job_Position', 'Job_Posting__fkey']
inlines = [jobs]