Django - Какой хороший способ справиться со многими людьми с помощью промежуточной таблицы в формах и представлениях - PullRequest
1 голос
/ 05 октября 2010

Предположим, у меня есть следующие модели -

class Item(models.Model):
    name = models.CharField(max_length=150)
    value = models.DecimalField(max_digits=12,decimal_places=2)

class Organization(models.Model):
    name = models.CharField(max_length=150)
    items = models.ManyToManyField(Item, through='Customizable')

class Customizable(models.Model):
    organization = models.ForeignKey(Organization)
    item = models.ForeignKey (Item)
    value = models.DecimalField(max_digits=12,decimal_places=2)

Чаще всего, когда items "назначены" на organization, они будут иметь то же значение, что и первоначально записанные в связанныхItem объект.Но в некоторых случаях элемент, присвоенный организации, может иметь переопределенный value (отсюда и промежуточная модель).Поскольку переопределение исходного значения происходит редко (но это случается), я хочу позволить пользователю просто выбрать нужные items из списка Item экземпляров, чтобы назначить их экземпляру организации.После этого у пользователя будет возможность переопределить отдельные значения позже после массового присвоения.

Итак, у меня есть следующая простая ModelForm -

class AssignItemsForm(forms.ModelForm):
    items = forms.ModelMultipleChoiceField(queryset=Item.objects.all(),required=False,widget=forms.CheckboxSelectMultiple)
    class Meta:
        model = Organization
        exclude = ('name',)

Теперь, так как у меня есть модель throughпростая form.save () не будет работать.Мне нужно (i) сохранить Customizable экземпляров, соответствующих элементам, выбранным пользователем, и (ii) убедиться, что сохраненные Customizable экземпляры имеют правильные value, взятые из соответствующих value, взятых из itemэкземпляр, связанный с Foreignkey.

Я пытаюсь обработать его в представлении (но мой разум заблокирован) -

def assign_items(request, oid):
    organization = Organization.objects.get(id=oid)
    if request.method == 'POST':
        form = AssignItemsForm(data=request.POST, instance=organization)
        if form.is_valid():
            current_organization = form.save(commit=False)
            #
            #placeholder to save Customizable instances here
            #
            return HttpResponseRedirect(reverse('redirect-someplace-else'))
    else:
        form = AssignItemsForm(instance=organization,)
    return render_to_response("assign_items.html", {"form": form,}, context_instance=RequestContext(request))

Ответы [ 3 ]

1 голос
/ 05 октября 2010

Вы должны будете использовать save_m2m метод:

def assign_items(request, oid):
    organization = Organization.objects.get(id=oid)
    if request.method == 'POST':
        form = AssignItemsForm(data=request.POST, instance=organization)
        if form.is_valid():
            current_organization = form.save(commit=False)

            current_organization.save()

            form.save_m2m()

            return HttpResponseRedirect(reverse('redirect-someplace-else'))
    else:
        form = AssignItemsForm(instance=organization,)
    return render_to_response("assign_items.html", {"form": form,}, context_instance=RequestContext(request))

Смотрите здесь для получения дополнительной информации:

http://docs.djangoproject.com/en/dev/topics/forms/modelforms/#the-save-method

0 голосов
/ 26 ноября 2016

Переопределить метод save в ModelForm.Таким образом, вам не придется повторяться, если вам нужно использовать форму в нескольких местах.

См. Этот ответ для более подробной информации:

https://stackoverflow.com/a/40822731/2863603

0 голосов
/ 05 октября 2010

Я бы подошел к этому по-другому. У вас есть посредническая модель для вашего м2. Следовательно, я бы сказал, что эта модель-посредник должна быть подкреплена AssignItemsForm. Поэтому я бы изменил это следующим образом:

# forms.py
class AssignItemsForm(forms.ModelForm):
    value = forms.DecimalField(max_digits=12, decimal_places=2, required = False)

    class Meta:
        model = Customizable

Далее, вопрос разрешения пользователям выбирать другое значение. Для этого я сделал поле value модели необязательным (required = False). Затем я проверяю, предоставил ли пользователь явное значение. Если нет, то я предполагаю, что должно использоваться значение по умолчанию Item. Для этого я переопределяю clean метод формы:

    def clean(self):
        super(AssignItemsForm, self).clean()
        value, item = self.cleaned_data.get('value'), self.cleaned_data.get('item')
        if not value:
            value = item.value
        self.cleaned_data['value'] = value
        return self.cleaned_data

И, наконец, я проверил это в админке.

# admin.py
from app.forms import AssignItemsForm

class CAdmin(admin.ModelAdmin):
    form = AssignItemsForm

admin.site.register(Item)
admin.site.register(Organization)
admin.site.register(Customizable, CAdmin)

Таким образом, вы можете продолжать использовать form.save(), тем самым избегая пользовательских манипуляций в представлении. Вам придется немного изменить свое представление, чтобы убедиться, что организация автоматически выбрана для назначения элементов.

# views.py
def assign_items(request, oid):
    organization = Organization.objects.get(id=oid)
    if request.method == 'POST':
        form = AssignItemsForm(data=request.POST.copy())
        form.save()
    else:
        form = AssignItemsForm(initial = {'organization': organization})
    ...
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...