Ответ 1
…
if form.is_valid():
client_mod = form.save(commit=False)
client_mod.save()
for groupe in form.cleaned_data.get('groupes'):
clientgroupe = ClientGroupe(client=client_mod, groupe=groupe)
clientgroupe.save()
…
На данный момент, когда я пытаюсь сохранить данные m2m, он просто умирает и говорит, что я должен использовать ClientGroupe Manager... так что пропало?
class Groupe(models.Model):
nom = models.CharField(max_length=1500, blank=True)
class Client(models.Model):
nom = models.CharField(max_length=450, blank=True)
prenom = models.CharField(max_length=450, blank=True)
groupes = models.ManyToManyField(Groupe, null = True, blank = True, through='ClientGroupe')
class ClientGroupe(models.Model):
client = models.ForeignKey(Client)
groupe = models.ForeignKey(Groupe)
dt = models.DateField(null=True, blank=True) # the date the client is using its group free rental rate
class Meta:
db_table = u'clients_groupes'
def modifier(request, id):
client = Client.objects.get(id=id)
form = ClientForm(instance = client)
dict = {
"form": form
, "instance" : client
}
if request.method == "POST":
form = ClientForm(request.POST, instance = client)
if form.is_valid():
client_mod = form.save()
id = client_mod.id
return HttpResponseRedirect(
"/client/%(id)s/?err=success" % {"id" : id}
)
else:
return HttpResponseRedirect(
"/client/%(id)s/?err=warning" % {"id" : id}
)
return render_to_response(
"client/modifier.html"
, dict
, context_instance=RequestContext(request)
)
ИЗМЕНИТЬ
и здесь код ClientForm:
class ClientForm(ModelForm):
class Meta:
model = Client
РЕДАКТИРОВАТЬ № 2: здесь сообщение об ошибке:
AttributeError at /client/445/
Cannot set values on a ManyToManyField which specifies an intermediary model. Use ClientGroupe Manager instead.
Request Method: POST
Request URL: http://localhost/client/445/
Exception Type: AttributeError
Exception Value: Cannot set values on a ManyToManyField which specifies an intermediary model. Use ClientGroupe Manager instead.
Exception Location: C:\Python25\lib\site-packages\django\db\models\fields\related.py in __set__, line 574
Python Executable: C:\xampp\apache\bin\apache.exe
Python Version: 2.5.2
…
if form.is_valid():
client_mod = form.save(commit=False)
client_mod.save()
for groupe in form.cleaned_data.get('groupes'):
clientgroupe = ClientGroupe(client=client_mod, groupe=groupe)
clientgroupe.save()
…
Если вы используете метод сохранения прямо сейчас, Django попытается сохранить с помощью менеджера (который Django не разрешает). К сожалению, поведение, которое вы хотите, немного сложнее, чем по умолчанию ModelForm
. Что вам нужно сделать, это создать набор форм.
Прежде всего, вам нужно будет изменить параметры вашего ClientForm
, чтобы он не отображал атрибут groupes
.
class ClientForm(ModelForm):
class Meta:
model = Client
exclude = ('groupes',)
Затем вы должны изменить представление для отображения набора форм:
from django.forms.models import inlineformset_factory
def modifier(request, id):
client = Client.objects.get(id=id)
form = ClientForm(instance = client)
# Create the formset class
GroupeFormset = inlineformset_factory(Client, Groupe)
# Create the formset
formset = GroupeFormset(instance = client)
dict = {
"form": form
, "formset" : formset
, "instance" : client
}
if request.method == "POST":
form = ClientForm(request.POST, instance = client)
formset = GroupeFormset(request.POST, instance = client)
if form.is_valid() and formset.is_valid():
client_mod = form.save()
formset.save()
id = client_mod.id
return HttpResponseRedirect(
"/client/%(id)s/?err=success" % {"id" : id}
)
else:
return HttpResponseRedirect(
"/client/%(id)s/?err=warning" % {"id" : id}
)
return render_to_response(
"client/modifier.html"
, dict
, context_instance=RequestContext(request)
)
И, очевидно, вы также должны настроить свой шаблон для рендеринга набора форм.
Если вам нужны другие советы по наборам форм, см. следующие статьи:
Вероятно, вам нужно удалить поле ManyToMany из своей модели клиента или же тщательно исключить его из своей формы. К сожалению, виджет по умолчанию для поля ManyToMany не может правильно заполнить модель ClientGroupe (даже если отсутствующее поле dt было установлено как autonow = True). Это то, что вам нужно будет либо вырваться в другую форму, либо обработать ваше мнение.
При сохранении формы вы сохраняете объект Client. Теперь, если вы хотите назначить клиента группе, вы должны сделать это:
clientgroupe = ClientGroupe.objects.create(client=client_instance, groupe=groupe_instance, dt=datetime.datetime.now())
где client_instance и groupe_instance выполняются с вашим клиентом и группой.
Я предоставляю альтернативное решение из-за проблем, с которыми я столкнулся при вызове form_valid:
class SplingCreate(forms.ModelForm):
class Meta:
model = SplingModel
fields = ('Link', 'Genres', 'Image', 'ImageURL',)
def save(self, commit=True):
from django.forms.models import save_instance
if self.instance.pk is None:
fail_message = 'created'
else:
fail_message = 'changed'
fields = set(self._meta.fields) - set(('Genres',))
instance = save_instance(self, self.instance, fields,
fail_message, commit, construct=False)
genres = self.cleaned_data.get('Genres')
for genre in genres:
SplingGenreModel.objects.get_or_create(spling=instance, genre=genre)
return instance
Я скопировал логику из djangos forms/models.py, мое поле Genres - многоголосие с промежуточной таблицей - я исключаю его из save_instance, а затем сохраняю его отдельно.