Using django-autocomplete-light in grappelli in a stackedinline form - python

I'm trying to use django-autocomplete-light in a grappelli admin page within a StackedInline.
When used on fields in the main model, autocomplete-light fields work perfectly fine.
However in inlines they are non-functional. All I get is a gray X, that doesn't remove the model, and no field to enter text into:
And in dynamically added inlines, I can't even click into the field!:
My code:
In admin.py
class ServiceInline(MembershipInline):
model = models.Service
form = forms.MembershipInlineFormFactory(models.Service)
In forms.py
class ServiceAutocompleteForm(autocomplete_light.ModelForm):
class Meta:
fields='__all__'
model = models.Service
autocomplete_fields = ['person','position']

So it turns out this is an issue with the generated CSS, where a float in grappelli is covering the actual autocomplete inputs. This can be fixed with the following CSS rule (as long as this is included in a file used by the admin site):
.autocomplete-light-widget {
z-index:10;
}

Related

Django InlineModelAdmin not displaying inlineformset correctly

I'm developing a Django application in which a lot of models have foreign keys and m2m relationships. This results in many ModelChoiceField being displayed in the Django admin for my models. To make model choice more bearable, I installed the django-select2 app in my project.
I have been trying to implement select2 in the inline forms the admin site displays when editing related objects, but the form doesn't render the ModelSelect2Widget (it renders a simple select; it doesn't even include the select2 library).
What I tried was creating a ModelForm in forms.py overriding the relevant fields widgets, then, using inlineformset_factory, had a variable holding the factory class. Lastly, in admin.py, added my custom inline formset using the formset property of the InlineModelAdmin class.
forms.py
class FichaTecnicaForm(forms.ModelForm):
class Meta:
model = models.FichaTecnica
exclude = ('pelicula',)
widgets = {
'responsable': ModelSelect2Widget,
'cargo': ModelSelect2Widget,
'pais': ModelSelect2Widget
}
FichaTecnicaInline = inlineformset_factory(models.Pelicula, models.FichaTecnica, form=FichaTecnicaForm)
admin.py
class FichaTecnicaInline(admin.TabularInline):
model = models.FichaTecnica
formset = forms.FichaTecnicaInline
extra = 0
# Some other code here
# This is where the inlines are invoked
class PeliculaAdmin(admin.ModelAdmin):
inlines = [
FichaTecnicaInline,
# some other inlines, not relevant...
]
I was expecting that the inline form set would display the select2 widget for the model choice, but instead it displays a standard select widget.
Thank you very much in advance for you help!
I think there is an error in your code where your FichaTecnicaInline class is overwritten by your admin class definition.
Maybe the formset class created by inlineformset_factory, which uses your custom form is being overwritten by defaults from admin.TabularInline. I think the first thing to try is giving them different names.

Django autocomplete fields do NOT work when using a horizontal filter on a many to many field

I am using django's auto complete light to make a custom form. In this model there is another field which I would like to apply a horizontal filter to. However whenever I apply the filter, the autocomplete forms do not work anymore.
#admin.register(model)
class modelAdmin(VersionAdmin):
form = autoCompleteForm
filter_horizontal = ('many_to_many_field',)
Open to any solutions, I have searched around and cannot seem to find any other similar problem.
For anyone who has the same problem as me. How I got around this problem was I made my own custom widget using autocomplete-light for the many to many field. This still allows to select multiple but allows for a smaller field, its the same size as a charField.
from dal import autocomplete
class many_to_many_field_Autocomplete(autocomplete.Select2QuerySetView):
def get_queryset(self):
qs = *custom query if needed*
#search option
if self.q:
qs = qs.filter(name__icontains=self.q)
return qs
Then add the widget to the urls.py file,
urlpatterns = [
url(
r'^model-autocomplete/$',
many_to_many_field_Autocomplete.as_view(),
name='model-autocomplete',
),
]
Then add the custom widget to that field inside of the form class
class VersionForm(forms.ModelForm):
class Meta:
model = model_name
fields = '__all__'
widgets = {
'many_to_many_field_name': autocomplete.ModelSelect2Multiple(url='model-autocomplete'),
}

Displaying foreign model fields in django admin as editable

I have a Django Model with a Foreign key:
class Library:
name=models.CharField()
class Book:
title=models.CharField()
library=models.ForeignKey(Library)
models.py
class BookAdmin(admin.ModelAdmin):
extra = 0
fields = ['title', 'library__name'] # library__name not found
admin.site.register(Book, BookAdmin)
admin.py
In the admin, I want to display Book and show an editable field for Library.name in the Book view (not the other way around with inlines):
> Book
* Title: "Foo"
* Library Name: "Bar"
As readonly, it's easy (just creating a method in Book model returning the library name value) but I cannot make it work for editable fields, I tried using fields=('title','library.name') and fields=('title','library__name') without success
You need an inline model admin:
https://docs.djangoproject.com/en/dev/ref/contrib/admin/#inlinemodeladmin-objects
try to use related_name in models like that
library=models.ForeignKey(Library, related_name="library")
then use fields=('title','library__name') and it should work.

Django admin - remove "add another" button for a self-referential field

I have a Django project that includes a model class with an optional self-referential ForeignKey field. A partial snippet:
class Site(models.model):
name = models.CharField(max_length=100)
parent_site = models.ForeignKey('self', null=True, blank=True)
I'm using the Django admin site to create new objects. For this class' admin form I'd like to disable the "Add another..." button next to the parent_site field (i.e. when you're creating a new site, you can't open the popup to create another new site as the parent).
I can't remove has_add_permission from the user, as they need it to be in the current add view. I don't mind removing the function from both add and change views, but limiting removal to the add view would be helpful.
I haven't been able to work out how to use the Inline field classes to achieve this, or formfield_for_foreignkey, or a custom ModelForm. Anyone got a solution more elegant than using JavaScript on a customised form template?
no css hacks add to admin class:
max_num=0
or try this in admin.py ( for older django versions):
class MODEL_ADMIN(admin.ModelAdmin):
class Media:
css = {'all': ('css/no-addanother-button.css',)}

Django inline link to model editing

I know this issue has been asked more than once, but as Django is evolving with new version, I'll ask the question again :
I am using the model User (Django User, not in my models.py) and create another model with a Foreign key to User.
models.py :
class Plan(models.Model):
user = models.ForeignKey(User)
I can simply display every Plan in my user by doing this in admin.py :
class PlanInline(admin.TabularInline):
model = Plan
extra = 0
class MyUserAdmin(UserAdmin):
ordering = ('-date_joined', 'username')
inlines = [PlanInline,]
admin.site.unregister(User)
admin.site.register(User, MyUserAdmin)
But things are about to get more tricky. I want to add a model that has a foreign key pointing to Plan :
class Order(models.Model):
plan = models.ForeignKey('Plan')
And I want to be able to see all Orders for each Plan. As of today, it is impossible to have nested inlines in Django Admin (without editing the HTML, which I want to avoid) :
User
-> Plan 1
-> Order 1
-> Order 2
-> Plan 2
-> Order 3
So my idea is to display in the User Admin only A LINK for each plan, to the page to edit Plans, and put Orders as inline :
class OrderInline(admin.TabularInline):
model = Order
extra = 0
class PlanAdmin(admin.ModelAdmin):
inlines = [OrderInline,]
admin.site.register(Plan, PlanAdmin)
The question is, how do I display a link to a Plan in my User Admin?
class MyUserAdmin(UserAdmin):
ordering = ('-date_joined', 'username')
??? LINK ????
I saw some solutions on this topic : Django InlineModelAdmin: Show partially an inline model and link to the complete model, but they are a bit "dirty' as they make us write HTML and absolute path into the code.
Then I saw this ticket on Djangoproject : https://code.djangoproject.com/ticket/13163. It seems exactly what I'm looking for, and the ticket is "fixed". So I tried adding like in the fix show_change_link = True :
class PlanInline(admin.TabularInline):
model = Plan
extra = 0
show_change_link = True
class MyUserAdmin(UserAdmin):
ordering = ('-date_joined', 'username')
show_change_link = True
inlines = [UserProfileInline, PlanInline]
But it doesn't work (and I have no log or error).
Is there any way to do this in a clean way?
Update for django 1.8
show_change_link = True
https://github.com/django/django/pull/2957/files
I suggest adding a custom PlanInline method that returns the link and see if it helps. Something along these lines:
from django.utils.safestring import mark_safe
from django.core.urlresolvers import reverse
class PlanInline(TabularInline):
model = Plan
readonly_fields = ('change_link',)
...other options here...
def change_link(self, obj):
return mark_safe('Full edit' % \
reverse('admin:myapp_plan_change',
args=(obj.id,)))
Basically all we do here is create the custom method that returns a link to the change page (this specific implementation is not tested, sorry if there is any parse error but you get the idea) and then add it to the readonly_fields as described here: https://docs.djangoproject.com/en/dev/ref/contrib/admin/#django.contrib.admin.ModelAdmin.readonly_fields
A couple of notes for the change_link method: You need to replace 'myapp' in the view name with your actual application name. The mark_safe method just marks the text as safe for the template engine to render it as html.

Categories

Resources