I have a situation again, when I do a form.save(), my form saves only the parent table, it does not save the intermediary table which is required for Many-To-Many relationships.
My models.py look like this
class Platform(models.Model):
id = models.AutoField(primary_key=True)
description = models.TextField(blank=True)
annotation_file_archived_location = models.FileField(upload_to='msrb/platform')
anntation_file_hashsum = models.TextField()
annotation = models.TextField(unique=True)
def __unicode__(self):
return self.annotation
class Meta:
managed = True
db_table = 'platform'
class Dataset(models.Model):
dataset_id = models.TextField(primary_key=True)
title = models.TextField(blank=True, null=True)
taxonomy = models.ForeignKey('Organism', blank=True, null=True)
citation = models.TextField(blank=True, null=True)
summary = models.TextField(blank=True, null=True)
contributor = models.TextField(blank=True, null=True) # This field type is a guess.
submitted = models.DateField(blank=True, null=True)
last_updated = models.DateField(blank=True, null=True)
author = models.ForeignKey('Users', db_column='author', blank=True, null=True)
platforms = models.ManyToManyField(Platform,through='DatasetPlatform')#,through_fields=('Platform:platform','dataset'))
class Meta:
managed = True
db_table = 'dataset'
class DatasetPlatform(models.Model):
id = models.IntegerField(primary_key=True)
platform = models.ForeignKey(Platform, null=False)
dataset = models.ForeignKey(Dataset,null=False)
class Meta:
managed = False
db_table = 'dataset_platform'
Forms.py
class DatasetForm(forms.ModelForm):
dataset_id = forms.CharField(required=True,help_text="dataset_id")
title = forms.CharField(required=True,help_text="title")
taxonomy = forms.ModelChoiceField(queryset=Organism.objects.all(),empty_label=None,help_text='Taxonomy')
citation = forms.CharField(required=True,help_text="citation")
summary = forms.CharField(required=True,help_text="summary")
contributor = forms.CharField(help_text="contributor (separated by comma)")
submitted = forms.DateField(initial = datetime.now,required=True,help_text="Submitted date")
last_updated = forms.DateField(initial = datetime.now,required=True,help_text="Last Updated date")
platform = forms.ModelMultipleChoiceField(queryset=Platform.objects.all(),help_text="Choose the platforms this dataset belongs to")
class Meta:
model = Dataset
fields = ('dataset_id','title','taxonomy','citation','summary','contributor','submitted','last_updated','platform')# Add author later ,'author')
views.py
def add_dataset(request):
context_dict = {}
if request.method == 'POST':
form = DatasetForm(request.POST)
if form.is_valid():
print "------------------------------------------------------------------------------"
print form.cleaned_data['platform']
form.save()
print "------------------------------------------------------------------------------"
return HttpResponseRedirect('/msrb/')
else:
print form
print form.errors
else:
form = DatasetForm()
context_dict['form'] = form
template = get_template('msrb/add_dataset.html')
context = RequestContext(request,context_dict)
return HttpResponse(template.render(context))
I have tried saving the data using
form.save(commit=True)
form.save_m2m()
form.cleaned_data gives the proper output. I am not sure what am I missing here as I dont get an error message from django too.
EDIT I have a workaround for the problem, but I am not sure if this is the best solution. If I can get a better solution, I will be greatful.
def add_dataset(request):
context_dict = {}
if request.method == 'POST':
form = DatasetForm(request.POST)
if form.is_valid():
print form.cleaned_data['platform']
f = form.save()
for p in form.cleaned_data['platform']: <--- Added
d = DatasetPlatform(dataset = f,platform = p) <--- Added
d.save() <--- Added
return HttpResponseRedirect('/msrb/')
else:
print form
print form.errors
else:
form = DatasetForm()
context_dict['form'] = form
template = get_template('msrb/add_dataset.html')
context = RequestContext(request,context_dict)
return HttpResponse(template.render(context))
The save method is an inherited method from models. Model which is executed to save an instance into a particular Model. Whenever one tries to create an instance of a model either from admin interface or django shell, save() function is run.
Does Django objects create call save? Creating objects To create an object, instantiate it using keyword arguments to the model class, then call save() to save it to the database. This performs an INSERT SQL statement behind the scenes. Django doesn't hit the database until you explicitly call save() .
It looks through all the class attributes of your model, and any that are instances of a Field subclass it moves into a fields list. That list is assigned as an attribute of the _meta object, which is a class attribute of the model. Thus you can always get to the actual Field objects via MyModel.
Django is not able (well, refuses) to automatically save m2m relations with a custom through model. Saving the form data uses direct assignment to the ManyToManyField
, which will not work as explained here.
If removing the custom through model is an option, I'd do that. Granted, it will have to be managed = True
, but it greatly simplifies use of the field. You're not saving any extra data in the relationship, so it might be an option.
Otherwise, you have already found the only workaround. Each time you want to manipulate the m2m relationship, you'll have to manually create, alter and delete the DatasetPlatform
instances. Again, this is explained in further detail in the relevant documentation.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With