Group list items by field value in the Django admin - python

I'm trying to group the items in the Django admin app by a specific field (e.g. date).
So I've added to the queryset in admin.ModelAdmin.getQueryset() the following:
queryset = queryset.values('date').annotate(Sum('amount'))
But this doesn't work because in this case, a dict is returned instead of a queryset.
I started exploring what's inside the django/contrib/admin folder, and I think something need to be done before sending the object to the template change_list.html.
I'm not sure but I think the class in views/main.py (admin folder) might need some change.
Can anybody confirm that what I'm trying to do is achievable at all?
Please find below a representation of what I'm trying to achieve:

Follow the below example in URL. it's has great way to understand with override django admin with custom queryset and groupby data
https://medium.com/#hakibenita/how-to-turn-django-admin-into-a-lightweight-dashboard-a0e0bbf609ad

I found this useful: https://github.com/xacce/django_admin_grouper
You can simply define the group in ClassAdmin
class RecordAdmin(admin.ModelAdmin):
def regroup_by(self):
return 'category'
The repo overrides Django's change_list_results.html. If your RecordAdmin has method reggroup_by than it inserts a row with the name of the category. If reggroup_by is missing it works as usual.

Related

Filtering Objects in a View in Django - Oscar?

Trying to implement a simple ordering query on ProductCategoryView in Django-Oscar. It should be fairly simple to implement but it's taking too much time to understand. I'm having second thoughts to go forward with Oscar or not as it seems difficult to extend.
The ProductCategoryView returns products of a certain category. I want to sort them according to certain field in product model say price. First I change the parent generic class from TemplateView to ListView so that I can use get_queryset method. Then I override the get_queryset method as below and write a simple queryset in that. Still the sorting doesn't happen though the flow does go inside the get_queryset method.
def get_queryset(self):
queryset = Product.objects.filter(categories = self.category)
logger.debug("inside")
queryset = queryset.order_by("price")
return queryset
So what methods I have to overwrite. Will there be so much trouble editing Oscar every time or I'm missing something?
P.S : I have asked lot of questions around Django/Oscar Class based view recently . So I might look like a Help Vampire. Please ignore this question if that is the case.
#Anentropic is right but let me elaborate a bit.
Oscar bases all its browse views on search engines so faceting can be used to narrow down the list of products returned. By default there are search engine integrations for Solr and Elasticsearch.
If you don't use Solr or Elasticsearch, the default implementation is SimpleProductSearchHandler. It does not use any external services but instead calls Product.browsable.get_queryset(). That code lives in oscar.apps.catalogue.managers and could be customized to provide custom ordering.
This is all assuming you don't want to use a search engine as customizations required to change the order of results for other search handler classes are backend-specific.

Manage slug for django

I try to use django-uuslug, to manage unique and unicode slug with django. This project seems interesting, it is better to use an existing project to reinvent the wheel. However I have a question, I would to know if it's be possible to specify one column more, to make the slugify on the current object and the optionnal column. For example if we have a site column and want have slug unique per site not per table.
uuslug(self.title, instance=self, unique_per_column=self.site)
Otherwise is there a better way to manage slug in django or not.
If you have a look at the source code of uuslug, it is possible to do what you want like this:
uuslug(self.title, instance=self, filter_dict={'site': self.site})
this will cause uuslug to filter the queryset of instance's model to rows with the same value of site field before doing the uniqueness check on that queryset

How to filter autocompletion results in django grappelli?

We have a soft delete scheme where we just mark things as deleted and then filter the deleted ones out in various places. I'm trying to figure out how to filter the deleted ones out of the grapelli autocomplete suggestions.
In the end I went with this:
from grappelli.views.related import AutocompleteLookup
class YPAutocompleteLookup(AutocompleteLookup):
""" patch grappelli's autocomplete to let us control the queryset
by creating a autocomplete_queryset function on the model """
def get_queryset(self):
if hasattr(self.model, "autocomplete_queryset"):
qs = self.model.autocomplete_queryset()
else:
qs = self.model._default_manager.all()
qs = self.get_filtered_queryset(qs)
qs = self.get_searched_queryset(qs)
return qs.distinct()
It can be installed by overriding the relevant url:
url(r'^grappelli/lookup/autocomplete/$', YPAutocompleteLookup.as_view(), name="grp_autocomplete_lookup"),
Make sure this is ahead of Grappelli in your urls.
If your working with the Admin site, you should take advantage of the ModelAdmin.queryset function:
https://docs.djangoproject.com/en/1.5/ref/contrib/admin/#django.contrib.admin.ModelAdmin.queryset
As I found out, changing the default model manager to restrict the results is a bad idea, causing all kinds of nasty problems. For example: preventing syncdb, shell or shell_plus from running. Making it impossible to add the first record to a blank db. The exact errors depend upon what your restricting, but you are bound to get a few.
What is needed here is a way to tell Grappelli the name of the queryset manager to use. Passed in or a setting perhaps?
You can specify a simple (constant or related field) filter using ForeignKey.limit_choices_to. Grappelli grabs this value and sends it in the GET as param 'query_string'.
However, this might not be enough. I posted a request to the Grappelli repo I use to add a way to specify the record manger to use, or just automatically use the admin queryset (ModelAdmin.queryset).
My post is here:
https://github.com/sehmaschine/django-grappelli/issues/362
It looks like you can pass extra search params into the ajax autocompleter somehow. Likely a frontend hack needed.
https://github.com/sehmaschine/django-grappelli/blob/master/grappelli/views/related.py#L101
OR
You can make the default Manager for the models return an already filtered list, and have places that need to explicitly see deleted items remove that restriction.
This would likely make the default case much easier for you across the board.

django admin site - filtering available objects for user

I have models that belong to some 'group' (Company class). I want to add users, who will also belong to a one group and should be able to edit/manage/add objects with membership in associated group.
something like:
class Company()
class Something()
company = ForeignKey(Company)
user Microsoft_admin
company = ForeignKey(Company)
and this user should only see and edit objects belonging to associated Company in the Admin Interface.
How to acomplish that?
hey, maybe you can do something like this
There are a few different ways to do it. The magic words that you're looking for are "row level permissions". Search for that and "Django" and you should find what you're looking for.
Beyond a certain point though, it's easier to roll your own views. It all depends on your use case, and what exactly you're trying to achieve.
I'd say this has been satisfyingly answered in How can I implement a global, implicit filter in Django admin?

Django - alternative to subclassing User?

I am using the standard User model (django.contrib.auth) which comes with Django. I have made some of my own models in a Django application and created a relationship between like this:
from django.db import models
from django.contrib.auth.models import User
class GroupMembership(models.Model):
user = models.ForeignKey(User, null = True, blank = True, related_name='memberships')
#other irrelevant fields removed from example
So I can now do this to get all of a user's current memberships:
user.memberships.all()
However, I want to be able to do a more complex query, like this:
user.memberships.all().select_related('group__name')
This works fine but I want to fetch this data in a template. It seems silly to try to put this sort of logic inside a template (and I can't seem to make it work anyway), so I want to create a better way of doing it. I could sub-class User, but that doesn't seem like a great solution - I may in future want to move my application into other Django sites, and presumably if there was any another application that sub-classed User I wouldn't be able to get it to work.
Is the best to create a method inside GroupMembership called something like get_by_user(user)? Would I be able to call this from a template?
I would appreciate any advice anybody can give on structuring this - sorry if this is a bit long/vague.
First, calling select_related and passing arguments, doesn't do anything. It's a hint that cache should be populated.
You would never call select_related in a template, only a view function. And only when you knew you needed all those related objects for other processing.
"Is the best to create a method inside GroupMembership called something like get_by_user(user)?"
You have this. I'm not sure what's wrong with it.
GroupMembership.objects.filter( user="someUser" )
"Would I be able to call this from a template?"
No. That's what view functions are for.
groups = GroupMembership.objects.filter( user="someUser" )
Then you provide the groups object to the template for rendering.
Edit
This is one line of code; it doesn't seem that onerous a burden to include this in all your view functions.
If you want this to appear on every page, you have lots of choices that do not involve repeating this line of code..
A view function can call another function.
You might want to try callable objects instead of simple functions; these can subclass a common callable object that fills in this information.
You can add a template context processor to put this into the context of all templates that are rendered.
You could write your own decorator to assure that this is done in every view function that has the decorator.

Categories

Resources