[Answered ]-Django queryset hide value of object

1👍

I would like to start by saying that I do not understand why would you want to hide information from the admin of your system. Unless you have a complex work environment where only the DBA have access to such information, I honestly do not see the point.

To answer your question…

To hide information in the admin page, one option is to disable all links and replace the HTML with the edit link when is_anonymized value is False:
(adapted from answer_1 and answer_2)

admin.py:

from django.utils.html import format_html

class OrderAdmin(admin.ModelAdmin):
    list_display = ['anonymous_address']

    def anonymous_address(self, obj):
        if not obj.is_anonymized:
            return format_html(u'<a href="/admin/app/order/{}/change/">{}</a>', obj.id, obj.billing_address.address)
        else:
            return ("%s" % ('anonymous'))
    
    def __init__(self, *args, **kwargs):
        super(OrderAdmin, self).__init__(*args, **kwargs)
        self.list_display_links = None

admin.site.register(Order, OrderAdmin)

Note that with this solution admin still has access to BillingAddress model, if you registered it in the admin site. In that case it will be also necessary to override that.

On your queries, you can aggregate values with conditional expressions:

views.py:

from core.models import Order
from django.db.models import When, Case

def anonymous_address(request):
    orders = Order.objects.annotate(anonymised_address=Case(
        When(is_anonymized=True, then=None),
        When(is_anonymized=False, then='billing_address'),
    )).values('is_anonymized', 'anonymised_address')
    
    context = {'orders': orders}
    return render(request, 'anonymous_address.html', context)

anonymous_address.html:


{% block content %}
    {% for order in orders %}
        Should be anonymous: {{order.is_anonymized}} <br>
        Address: {{order.anonymised_address}}
        <hr>
    {% endfor %}
{% endblock content %}

And, instead of having this long query in every view, it is possible to replace that by a custom manager:

models.py:

class AnonymousOrdersManager(models.Manager):
    def get_queryset(self):
        return super().get_queryset().annotate(anonymised_address=Case(
                    When(is_anonymized=True, then=None),
                    When(is_anonymized=False, then='billing_address'),
                )).values('is_anonymized', 'anonymised_address')

class Order(models.Model):
    is_anonymized = models.BooleanField(default=False)
    billing_address = models.ForeignKey(BillingAdress, null=True, blank=True, on_delete=models.CASCADE)

    objects = models.Manager()
    anonymous_orders = AnonymousOrdersManager()

views.py:

def anonymous_address(request):
    orders = Order.anonymous_orders.all()
    
    context = {'orders': orders}
    return render(request, 'anonymous_address.html', context)
👤Niko

Leave a comment