Django InlineModelAdmin not displaying inlineformset correctly - python

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.

Related

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'),
}

django admin panel numbering every form in formset

how can i add numeration to every form in formset in django admin panel. I need next number for every new added form
class QuestionAnswerInline(admin.TabularInline):
model = QuestionAnswer
formset = SetTestQuestionAnswerFormSet
fields = ('question_answer_text','right_mark')
class QuestionAdmin(admin.ModelAdmin):
fieldsets = [
...
]
inlines = [QuestionAnswerInline]
A couple of ways to do that:
Override edit view template for this specific admin class and add enumeration within template with {{ forloop.counter }}. This is probably easyest way of doing this
Override formset class in your admin to provide counter for all the inline forms. You need to do quite abit of magic to achieve that, but that is also possible. Basically you extend the inline admin class get_formset method to create the forms, provide the counter data and then non-editable field to display that data.

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

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;
}

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 User Profile - Forms

Django 1.4
Sorry if this is a silly question i am fairly new to Django.
I am attempting to link a user and a profile together via the inbuilt auth profile system. All the examples of this i can find do not use a class based view, which is something i would really like to use.
Basically i would like a form that combines the Profile and the User allowing me to create both at the same time. If possible i would like to use the same form to Edit/Create the User + Profile.
I have created a model for the profile: Profile
Created forms:
class UserForm(forms.ModelForm):
class Meta:
model = User
class ProfileRegisterView(FormView):
template_name = 'profile-register-form.html'
form_class = UserForm
success_url = '/account/created/'
Adding the profile to the user model does not seem to include it within the UserForm:
AUTH_PROFILE_MODULE = "creative_profile.Profile"
The 2nd alternative i have tried was to define individual forms in forms.py however the form_class attribute only accepts one form model..
Any pointers help would be great, thanks
One possible solution is to include the Profile fields in your UserForm and override the save() method to populate the Profile fields.
The save() method will have to include a get_or_create() call for the Profile model if you're not using a post_save signal to create it. If you are using a post_save signal to create the Profile model, you're going to have to make sure the User is being saved first before calling the get_profile() method.
I do it in more simple way (i suggest). Just use django build in. In urls.py I added (r'^login/$','django.contrib.auth.views.login'). In settings.py add LOGIN_URL='/login/' and to MIDDLEWARE_CLASSES add 'django.contrib.auth.middleware.AuthenticationMiddleware'. Copy registration/login.html template locally if you want to change it. After such manipulations you will have ability to login as user. Forgot, you also should import from django.contrib.auth.models User and Group.

Categories

Resources