Как изменить значения в m2m-поле в форме? (Django)
У меня есть 2 модели в моем models.py
. Это Doctor и Specialty:
class Doctor(models.Model):
name = CharField(max_length=255)
specialties = ManyToManyField('Specialty', related_name='doctors')
mc_id = CharField(max_length=255, unique=True)
class Specialty(models.Model):
name = CharField(max_length=255)
mc_id = CharField(max_length=255, unique=True)
def __str__(self):
return self.name
При создании нового экземпляра доктора через интерфейс администратора (шаблон change_form.html
) я вижу поля модели Doctor, которые я должен заполнить данными. Среди этих полей есть поле специальности ("Cpeциальности"), которое является m2m полем и содержит имена (как я установил __str__(self)
метод в модели Specialty для возврата self.name
) для specialties, которые были ранее добавлены в Specialty
модель ( см. скрин).
А я хочу видеть в этом списке не только названия специальностей, но и значения поля mc_id модели Specialty, но сделать это за счет чего-то подобного - не мое дело:
class Specialty(models.Model):
name = CharField(max_length=255)
mc_id = CharField(max_length=255, unique=True)
def __str__(self):
return self.name + '(' + self.mc_id + ')'
Я думал, что смогу сделать это через переопределение метода formfield_for_manytomany()
в моей модели администратора (связанной с моделью Doctor
) в admin.py
:
@admin.register(Doctor)
class DoctorAdmin(admin.ModelAdmin):
def formfield_for_manytomany(self, db_field, request, **kwargs):
if db_field.name == "specialties":
queryset = Specialty.objects.all()
for specialty in queryset:
specialty.name += '(' + {specialty.mc_id} + ')'
return super().formfield_for_manytomany(db_field, request, **kwargs)
Это не сработало. Я хотел бы знать, как я могу решить мою проблему. Спасибо заранее.
Просто используйте format() в моделях
def __str__(self):
return '{} {}'.format(self.name, self.mc_id)
Я думаю, что перезапись метода label_from_instance
в поле формы может сработать для вас.
class SpecialtyModelMultipleChoiceField(forms.ModelMultipleChoiceField):
def label_from_instance(self, obj):
obj.name + '(' + obj.mc_id + ')'
class DoctorModelForm(forms.ModelForm):
specialties = SpecialtyModelMultipleChoiceField(
Specialty.objecs.all
# ....
)
class Meta:
model = Doctor
fields = '__all__'
@admin.register(Doctor)
class DoctorAdmin(admin.ModelAdmin):
form = DoctorModelForm
# ....
Я хотел бы поделиться альтернативной реализацией отличной идеи Тонио
Я думаю, что это может быть полезно в ситуациях, когда # fields.py
class SpecialtyModelMultipleChoiceField(forms.ModelMultipleChoiceField):
def label_from_instance(self, obj):
obj.name + '(' + obj.mc_id + ')'
# admin.py
class BaseAdmin(admin.ModelAdmin):
def get_form(self, request, obj=None, **kwargs):
form = super().get_form(request, obj, **kwargs)
# some logic
return form
@admin.register(Doctor)
class DoctorAdmin(BaseAdmin):
def formfield_for_manytomany(self, db_field, request, **kwargs):
if db_field.name == "specialties":
queryset = Specialty.objects.all().filter(mc_id=request.user)
kwargs.update({'queryset': queryset})
return super().formfield_for_manytomany(db_field, request, **kwargs)
def get_form(self, request, obj=None, **kwargs):
form = super().get_form(request, obj, **kwargs)
if request.user.is_superuser:
form.base_fields['specialties'] = SpecialtyModelMultipleChoiceField(Specialty.objects.all())
return form
DoctorAdmin
наследуется от некоторой базовой модели, например BaseAdmin
, и эта базовая модель также имеет переопределенный метод get_form()
. Но здесь в случае запроса суперпользователя queryset формируется дважды, поэтому ответ Тонио определенно лучше.