The default django 1.0.2 ManyToManyField widget (a multi-select) is difficult to use when there are a lot of things in the select box. Is there another widget available that gives a comma separated list of id's in a textarea? If this is not available what do I need to do to write one, and have it show up on ModelForm.as_p() and in the admin site?
If there are no existing widgets that do what you want (and I don't think there are) then you'll need to write your own. Unfortunately, the Django documentation doesn't show you how to do this, but it's not hard to figure out by looking at the source-code forms/widgets.py copying an existing widget and modifying it.
I believe setting raw_id_fields on the manytomanyfield actually outputs a TextInput widget with a comma-separated list of ids.
You may just override this in admin.py, in the corresponding ModelForm and force a TextArea widget on it.
In the Admin you can use filter horizontal and/or filter vertical:
class MyModelAdmin(admin.ModelAdmin):
filter_horizontal = ['many_to_many_field_name']
filter_horizontal = ['another_many_to_many_field_name']
doc
Related
The Django docs say you can add a form to the admin UI:
class ArticleAdmin(admin.ModelAdmin):
form = MyArticleAdminForm
I want a custom editing UI for a special field in my model, where I display multiple widgets. (It's not exactly the same, but an analogy might be an old-school hex editor widget, where you want fine editing control on a big blob of information.) Perhaps I could break the multiple values into multiple database objects and use an InlineAdmin, but I have app-specific reasons to not do that.
I thought I'd use a Form object with some custom fields, but Django says it must be a ModelForm:
<class 'myapp.admin.MyAdmin'>: (admin.E016) The value of 'form' must inherit from 'BaseModelForm'.
Is it possible to display multiple widgets (basically a very custom form) for a single model value in Django admin?
EDIT: It looks like MultiWidget might work? I'm gonna look into that. Also, this question is related. That suggests I should just change the widget on the field.
The answer was to make a MultiWidget, overriding:
__init__ to set up the widgets
decompress and value_from_datadict to unpack and pack the field value
template_name to render my own template
get_context to make the context for the template
Hopefully this is a simple fix, although I haven't found anything through searching.
I am using this code in admin.py to make my manytomany field appear as checkboxes in admin.
class MyModelAdmin(admin.ModelAdmin):
formfield_overrides = {
models.ManyToManyField: {'widget': CheckboxSelectMultiple},
}
But, I have about 10 choices, which is annoying as a vertical list. Is there a way to get the checkboxes to display horizontally or even more flexibly as 2 columns of five choices (or some other arbitrary look)?
I discovered through another search that this can be done by modifying the widget multiple_input.html file. not the best solution, but it worked
I'm working with Django Forms. In my model, i have a ManyToMany relationship between class X and class Y and Django shows a very annoying MultipleChoice control to edit this relationship. I would like to add a filter so editing the X object the user can filter the Y objects by name while he writes the name to finally select them
Some idea about how to do this in Django?
By default, a ManyToManyField in a Django Model will be represented by a ModelMultipleChoiceField in the ModelForm, which itself uses a SelectMultiple widget. This widget uses the default browser <select multiple="multiple"> element, which results in your "annoying" multiple choice control.
So in order to replace it, you should override the ModelMultipleChoiceField in your form to pass it your own widget (which would subclass SelectMultiple and override the template used):
my_field = forms.ModelMultipleChoiceField(queryset=Y.objects.all(), widget=MySelectMultiple)
However, many people have already done this kind of thing, so it's probably easier to use a package that has a nice multiple choice widget to your liking.
A very popular jquery module on the front-end is select2. If you want to use it, there are some django packages that already support it, popular ones are django-autocomplete-light and django-select2
I'm using CreateView and UpdateView directely into urls.py of my application whose name is dydict. In the file forms.py I'm using ModelForm and I'm exluding a couple of fields from being shown, some of which should be set when either creating or updating. So, as mentioned in the title, update part works but create part doesn't which is obvious because required fields that I have exluded are sent empty which is not allowed in my case. So the question here is, how should I do to fill exluded fields into the file forms.py so that I don't have to override CreateView?
Thanks in advance.
Well, you have to set your required fields somewhere. If you don't want them to be shown or editable in the form, your options are to set them in the view (by using a custom subclass of CreateView) or if appropriate to your design in the save method of the model class. Or declare an appropriate default value on the field in the model.
It would also work to allow the fields into the form, but set them to use HiddenInput widgets. That's not safe against malicious input, so I wouldn't do that for purely automated fields.
You cannot exclude fields, which are set as required in the model definition. You need to define blank=True/null=True for each of these model fields.
If this doesn't solve your issue, then please show us the model and form definitions, so we know exactly what the code looks like.
How can I change the default widget for DateField instances in Django ADMIN?
I am aware of how to do this for a ModelForm - How do you change the default widget for all Django date fields in a ModelForm? - by providing formfield_callback that checks the field type and then provides a form field with the new widget.
However, some of my ModelAdmin's may already have a custom ModelForm, some haven't. I don't want to provide/change a ModelForm wherever there's a date field (that's the point).
A custom ModelAdmin which could be used for subclassing would be ok, though. How can a ModelAdmin change the date fields of its form, independent of whether a custom ModelForm has been provided or not?
Maybe a ModelAdmin with get_form() calling its super then setting the form's formfield_callback? Seems a little convoluted, not sure about the timing, and also then there's three things to be aware of if any ModelAdmin needs further customization...
P.S.: I'm asking this after https://stackoverflow.com/questions/8484811/jquery-datepicker-in-django-admin was erroneously closed for being an "exact duplicate" of the above-mentioned ModelForm question. I hope the difference is now clear.
Btw my personal motivation is the year navigation of django admin's default datepicker. Really bad for birthdays... :-) yes there's a three-year old ticket https://code.djangoproject.com/ticket/9388
I was able to customize the default date widget in the Django admin. I followed two tutorials (from Simple is Better than Complex and Django Custom Widget)
Write a custom widget in a file called widgets.py inside your Django app
from django.forms import DateInput
class CustomDatePickerInput(DateInput):
template_name = "app_name/widgets/custom_datepicker.html"
class Media:
css = {
"all": (
"https://cdnjs.cloudflare.com/ajax/libs/datepicker/0.6.5/datepicker.min.css",
)
}
js = (
"https://code.jquery.com/jquery-3.4.1.min.js",
"https://cdnjs.cloudflare.com/ajax/libs/datepicker/0.6.5/datepicker.min.js",
"https://cdnjs.cloudflare.com/ajax/libs/datepicker/0.6.5/i18n/datepicker.es-ES.min.js",
)
Notice that the CSS and JS files that you may need should be added in the internal Media class as shown in the code above. In this case it is adding styles for the custom date picker.
Define the template for your widget, for more date picker's options see here, put this file in app_name/templates/app_name/widgets/custom_datepicker.html or make sure that this template matches the value of template_name in your custom widget:
{% load i18n %}
{% include "django/forms/widgets/input.html" %}
{% get_current_language as LANGUAGE_CODE %}
<script>
$(function () {
const DATE_PICKER_OPTIONS = {
'en-us': {
format: 'yyyy-mm-dd',
language: ''
},
'es': {
format: 'dd/mm/yyyy',
language: 'es-ES'
}
};
let options = DATE_PICKER_OPTIONS['{{ LANGUAGE_CODE }}'];
$("input[name='{{ widget.name }}']").datepicker({
format: options.format,
language: options.language
});
});
</script>
You need to indicate what widget to use in date field when registering your model in the Django admin (use formfield_overrides)
#admin.register(YourModel)
class YourModelAdmin(admin.ModelAdmin):
formfield_overrides = {models.DateField: {"widget": CustomDatePickerInput}}
Once this is completed, you will have a custom widget for dates in the Django admin. Keep in mind that this is just a guide, you can go further by reviewing the two tutorials I indicated.
Note: the implementation of this widget is also supporting internationalization.
ModelAdmin can only change the widget of the form it renders, so it would be difficult to override the widgets of a custom form passed to it - at least I can't think of a clean way to do it.
I can see a few options for you, depending on how/what you want to customize.
Modify the javascript that does the magic for the widget. This seems easy enough if your change can be handled there. Simply provide your own js/calendar.js and js/admin/DateTimeShortcuts.js the same way you would override the admin's templates. This has the added bonus of being upgrade friendly; since you are not modifying the django code base; also the change would be immediate for all forms that use the widget.
Customize the built-in django widget to do what you want. This has the benefit of instantly working without any modifications of your existing code, but is not upgrade friendly unless you are careful about patching sources. The source is at django.contrib.admin.widgets
Provide your own custom widget - but then you are back to the problem of going through the code and manually overriding all widget instances with your custom one.
Use something like grappelli and modify the templates/js to do what you want. Added bonus here is that you'll get lots of other functionality for free (like the ability to have a dashboard, if you plug it in with django-admin-tools).
django uses jquery extensively in their admin and they have their own jquery namespace (django.jQuery); so if you plan on doing some custom widgets make sure you use the right namespace to avoid strange problems.