Django raw_id_fields widget not showing search icon - django

I have the following code in my admin.py:
class UserManagedGroupAdmin(admin.ModelAdmin):
inlines = [MembershipInline]
search_fields = ('name', 'leader__username', )
list_display = ('__unicode__', 'leader', )
filter_horizontal = ('permissions', )
raw_id_fields = ('leader', )
admin.site.register(UserManagedGroup, UserManagedGroupAdmin)
The magnifying glass icon for searching doesn't appear in the admin page.
This is what I'm getting:
As you can see it's showing the unicode method of the model instead of the search icon I want.
Field 'leader' is a ForeignKey to User.
Could it be that django disables the search for ForeignKeys to User for security reasons, or am I doing something wrong?
The widget would be perfect for choosing users... I mean, I can't leave a huge select there with every user of my site.
Thanks.

I've found the problem thanks to this message in django-users.
I had to register in the admin the model to which the ForeignKey points to.
The search doesn't work without that.

Hi encounter the same issue but reason's a bit different.
To integrate the User and UserGroup with another app's admin (e.g. some_app)
I added below code to some_app/admin.py
class ProxyUser(User):
class Meta:
proxy = True
verbose_name = User._meta.verbose_name
verbose_name_plural = User._meta.verbose_name_plural
class ProxyGroup(Group):
class Meta:
proxy = True
verbose_name = Group._meta.verbose_name
verbose_name_plural = Group._meta.verbose_name_plural
admin.site.unregister(Group)
admin.site.unregister(User)
admin.site.register(ProxyGroup)
admin.site.register(ProxyUser, UserAdmin)
I think the unregister(...) will affect the other app's admin Globally!
That's another cause of missing search icon.

In the admin.py file add:
admin.site.register(YourModel)
This did the trick, Where YourModel is the model to be displayed with the magnifying glass

Related

Trouble displaying inline forms of a ModelAdmin

I am encountering what seems to me a weird bug when rendering Inline forms on the "Add" view of a ModelAdmin.
Here is a minimum example with Django version 2.2.4.
in models.py:
class MyModel(models.Model):
text = models.CharField(max_length=100)
class RelatedModel(models.Model):
parent = models.ForeignKey(MyModel, null=False, on_delete=models.CASCADE)
number = models.DecimalField(decimal_places=2, max_digits=10, null=False, blank=False)
in admin.py:
class RelatedModelInlineTabular(admin.TabularInline):
model = RelatedModel
show_change_link = False
fields = ("number", )
class TestMyModelCreate(admin.ModelAdmin):
fields = ['text', ]
inlines = [RelatedModelInlineTabular]
admin.site.register(MyModel, TestMyModelCreate)
Steps to replicate
Login to django admin website
open the "add" view for MyModel (i.e. navigate to the list of Models and click on the "Add new" button)
Expected result
The form displays an empty text field. Below that, an Inline form is displayed with 3 empty rows for potential related instances of RelatedModel
Actual result
The Inline form is displayed twice, each instance with its own 3 empty rows, as if I had specified it twice.
I attach a screenshot below of the actual page (Discount is the name of the related Model). I tried and I get the same result with both StackedInline and TabularInline.
Am I making some trivial error here that could explain what's happening? Or is this is a known bug? Thank you in advance to anyone that will help.

Django-mailer customizing admin area

When using django mailer (https://github.com/pinax/django-mailer) I realized that the default tables added to the admin area (such as Message logs and Messages) did not add the message_log field which indeed is available if one looks at the tables that are added.
Since the error message is very valuable to me I wanted to add it, and simply added the "log_message" to the app's MessageLogAdmin like this:
class MessageLogAdmin(MessageAdminMixin, admin.ModelAdmin):
list_display = ["id", show_to, "subject", "message_id", "when_attempted", "result", "log_message"]
list_filter = ["result"]
date_hierarchy = "when_attempted"
readonly_fields = ['plain_text_body', 'message_id']
search_fields = ['message_id']
However, is there really no other way to customize the admin area for django-mailer other than modifying the source code? E.g through settings.py
No you can't do that via settings.py
If I understand correctly, you don't want to fork the app just to edit admin.py, but rather keep it in the requirements.txt file. In that case you could do something like:
class MyOwnMessageLogAdmin(MessageAdminMixin, admin.ModelAdmin):
list_display = ["id", show_to, "subject", "message_id", "when_attempted", "result", "log_message"]
list_filter = ["result"]
date_hierarchy = "when_attempted"
readonly_fields = ['plain_text_body', 'message_id']
search_fields = ['message_id']
admin.site.unregister(MessageLog)
admin.site.register(MessageLog, MyOwnMessageLogAdmin)

Model field missing in admin

The invoice_date field on one of my models is not showing up in my admin.
invoice_date = models.DateField(auto_now=True, auto_now_add=False, null=True, blank=True)
I've tried the following:
renaming the field
running makemigrations/migrations
restarting the server
deleting cookies
I can successfully write to the field and pull data from it, so it appears to be there and functioning as desired. I just can't see it in the admin.
I have no special code in my admin.py. I've just registered the model
admin.py
from userorders.models import UserCartItem
admin.site.register(UserCart)
Any suggestions are welcome! Thanks!
Accoring to Django's documentation:
As currently implemented, setting auto_now or auto_now_add to True will cause the field to have editable=False and blank=True set.
You can circumvent this by explicitly defining it on the ModelAdmin class:
from userorders.models import UserCartItem
class UserCartItemAdmin(admin.ModelAdmin):
list_display = ['invoice_date']
fields = ['invoice_date']
# if you want the field just to visible but not editable
# readonly_fields = ['invoice_date']
admin.site.register(UserCartItem, UserCartItemAdmin)
You could try something following-
from userorders.models import UserCartItem
class UserCartItemAdmin(admin.ModelAdmin):
list_display = ['field_name_1', 'field_name_2', 'invoice_date']
admin.site.register(UserCartItem, UserCartItemAdmin)

django admin edit model select/prefetch_related?

I have a Django website, with model Event, lets say:
class Event(models.Model):
home = models.ForeignKey('Team', related_name='%(class)s_home')
away = models.ForeignKey('Team', related_name='%(class)s_away')
...
class Team(models.Model):
name = models.CharField("team's name", max_length=100)
Using ForeignKeys for this was a bad idea, but anyway, how to make this usable in Django Admin page?
In admin edit event page, a ton of foreign keys is fetched for this:
http://127.0.0.1:8000/admin/event/event/116255/
It produces tons of selects like:
SELECT "event_team"."id", "event_team"."name" FROM "event_team" WHERE "event_team"."id" = 346;
and page dies. I was playing with these:
class EventAdmin(admin.ModelAdmin):
list_display = ('id', 'home', 'away', 'date_game', 'sport', 'result')
search_fields = ['home__name', 'away__name']
list_select_related = (
'home', 'away', 'league', 'sport', ...
)
def get_queryset(self, request):
return super(EventAdmin, self).get_queryset(request).select_related(*self.list_select_related)
admin.site.register(Event, EventAdmin)
But no luck.
The simplest, quickest way
It would be to add raw_id_fields on your ModelAdmin (Django ModelAdmin.raw_id_fields documentation) :
class EventAdmin(admin.ModelAdmin):
raw_id_fields = ("home", "away")
It would result in a inputText with the FK field ids in such as :
.
Loading will be fast as it won't populate a select list with ALL the teams.
You'll have the Django admin change_view of the Team ModelAdmin to select the teams, thanks to the browse icon.
A nicer way ?
A lot more elegant on the UX side of things, it requires you to know part of the name of the team: using an ajax autocomplete widget to represent your field.
You could use for example Django Autocomplete Light (DAL) quick tutorial by having a custom form for your admin and a autocompleteModelSelect2 for your home and away fields (with 2 differents QS in the ajax view).
It will produce a field looking like:
.
The tutorial of this link have all you need!
Or you can chose another third party plugin or build your own field/widget to produce a similar result.
I think #ppython's answer is the simplest and works perfectly but I ended up using autocomplete_fields instead of raw_id_fields. Achieving a more friendly approach, it has been available since Django 2.0.
Following the answer, it'll be something like this:
class EventAdmin(admin.ModelAdmin):
autocomplete_fields = ['home', 'away']
I found the problem, it was my mistake and I did not even mention it in question :(
So this is my model, but I did not mention important part if it:
class Event(models.Model):
home = models.ForeignKey('Team', related_name='%(class)s_home')
away = models.ForeignKey('Team', related_name='%(class)s_away')
merged = models.ForeignKey('Event', null='True', blank='True')
def __unicode__(self):
return str(self.id) + ": " + self.home.name + " - " + self.away.name
Problem was not with home or away, but with merged field, that fetched self.home.name and self.away.name for each event.
Replaced with
def __unicode__(self):
return 'Event id: {}'.format(self.id)
and added merged to list_select_related
fixed my problem. Thanks for help and sorry for incomplete question.

Preventing Django admin panel to show drop-down list in Inline display of ManyToMany relationships

I have a self-referencing model in Django 1.5 as shown below:
RELATIONSHIP_PARENT = 1
RELATIONSHIP_BLOCKED = 2
RELATIONSHIP_STATUSES = (
(RELATIONSHIP_PARENT, 'Parent'),
(RELATIONSHIP_BLOCKED, 'Blocked'),
)
class Message(models.Model):
content = models.CharField("Content", max_length=160, db_index=True)
relationships = models.ManyToManyField('self',
through='Relationship',
symmetrical=False,
related_name='related_to')
class Relationship(models.Model):
parent_message = models.ForeignKey(Message, related_name='parent_messages')
child_message = models.ForeignKey(Message, related_name='child_messages')
status = models.IntegerField(choices=RELATIONSHIP_STATUSES)
And I configured Django admin to show me Relationships as inline when viewing individual Message panel as below:
from django.contrib import admin
from demo.models import Message, Relationship
class RelationshipInline(admin.TabularInline):
model = Relationship
extra = 0
fk_name = 'parent_message'
class MessageAdmin(admin.ModelAdmin):
inlines = (RelationshipInline,)
admin.site.register(Message, MessageAdmin)
admin.site.register(Relationship)
I intend to store many messages (with a lot of parent-child connections among them) in the table. Whenever I view individual message via Admin panel, I see something like this:
As shown in the red circle, Django admin collects all messages in the database and display them as drop-down list in the menu. I have read through a few ways to prevent it and the closest that I found is Representing ManyToMany relation in the Admin Panel but when I tried putting raw_id_fields = ('parent_message', ) under RelationshipInline class, it doesn't seem to do anything.
If anyone can recommend me to a link or resource or just show me how to prevent Django from showing every entry/messages in the drop-down list, I would greatly appreciate the help. Thank you.
This should work.
class RelationshipFormSet(BaseInlineFormSet):
def get_queryset(self):
if not hasattr(self, '_queryset'):
criteria = {} #Your criteria here
qs = super(RelationshipFormSet, self).get_queryset().filter(**criteria)
self._queryset = qs
return self._queryset
class RelationshipInline(admin.TabularInline):
model = Relationship
extra = 0
fk_name = 'parent_message'
formset = RelationshipFormSet
The raw_id_fields should go in the admin class:
admin.py
class MessageAdmin(admin.ModelAdmin):
inlines = (RelationshipInline,)
raw_id_fields = ('parent_message', )