Django multi-form save - django

I already tried nearly everything I could find regarding this, but I am pretty sure I am just one small suggestion away from solving my issue.
I am trying to save to forms that I generated using the forms method of Django at the same time. These forms have a ForeignKey relationship.
My model:
class Publisher(models.Model):
company = models.CharField(max_length=255)
address1 = models.CharField(max_length=255)
address2 = models.CharField(max_length=255)
city = models.CharField(max_length=255)
zipcode = models.CharField(max_length=10)
email = models.EmailField(max_length=255)
firstname = models.CharField(max_length=255)
lastname = models.CharField(max_length=255)
tc = models.BooleanField()
timestamp = models.DateTimeField(auto_now=True)
def __unicode__(self):
return self.company
class PublisherQuestions(models.Model):
referal = models.TextField()
updates = models.BooleanField()
publisher = models.ForeignKey(Publisher)
preferredCommunication = models.ForeignKey(PublisherCommunication)
def __unicode__(self):
return self.publisher
class PublisherForm(ModelForm):
class Meta:
model = Publisher
class PublisherQuestionsForm(ModelForm):
class Meta:
model = PublisherQuestions
exclude = ('publisher')
and my view:
def register(request):
if request.method == 'POST':
form = PublisherForm(data = request.POST)
formQuestions = PublisherQuestionsForm(data = request.POST)
if form.is_valid() and formQuestions.is_valid():
publisher = form.save()
formQuestions.publisher = publisher
formQuestions.save()
return HttpResponseRedirect('/thanks/')
So, what I try to do, is to save the second form "formQuestions" with the foreign key publisher against the publisher_id from the PublisherForm.
Unfortunately MySQL / Django is giving me the following error.
Column 'publisher_id' cannot be null
This might be a complete newbie question and yes there has been many people asking nearly the same, but none of the solutions worked for me.
Thanks for your help, as always appreciated!

You can try the following to check whether you get the same error or not:
publisher = form.save()
questions = formQuestions.save(commit=False)
questions.publisher = publisher
questions.save()
With commit=False you get the Model without saving it to the database.
https://docs.djangoproject.com/en/dev/topics/forms/modelforms/#the-save-method
In fact it is the Model you want to manipulate, adding the Publisher and not the form.
If you need to access the data from the form I think you should use for example this:
https://docs.djangoproject.com/en/dev/ref/forms/api/#accessing-clean-data
How I understood it is that you have a ModelForm and not a Model, so if you want to manipulate the Model you first need to create it, or at least it is the cleanest way of manipulating Model data. Otherwise you can manipulate the Form data but it is another story, you want to choose the raw data or the clean data etc.

Related

How to save multiple django form in one page with one submit button

i'm new when developing django. I have some question after days by days finding the answer. Here the go.
What i want is making ajax form that handle 2 model form, with 1 submit button
I can already saved the data in each form, but got problem in foreign key field got None instead
Here we go my model:
class ModelA(models.Model):
name = models.CharField(max_length=100, blank=True)
info = models.CharField(max_length=200, blank=True)
def __str__(self):
return self.name
class ModelB(models.Model):
xmodel = models.ForeignKey(to=ModelA, on_delete=models.CASCADE, related_name='modelX', blank=True, null=True)
no_1 = models.CharField(max_length=150, blank=True)
no_2 = models.CharField(max_length=150, blank=True)
Form Class:
class ModelAForm(forms.ModelForm):
class Meta:
model = ModelA
fields = '__all__'
class ModelBForm(forms.ModelForm):
class Meta:
model = ModelB
exclude = ('xmodel',)
View class:
def AddData(request):
tpl = 'add.html'
if request.method == 'POST':
mdla = ModelAForm(request.POST)
mdlb = ModelBForm(request.POST)
if mdla.is_valid():
obj = mdla.save()
if mdlb.is_valid():
mdlb.save(commit=False)
mdlb.xmodel=obj
mdlb.save()
else:
mdla = ModelAForm()
mdlb = ModelbForm()
In TPL i'm using ajax to send, it can save model a and model b, but in modelb xmodel (foreign key) it got None when check in adminpanel.
Which i do wrong, how to make it happen when handling the forms?
For people that got something like me, using 2 form.
i've solved my problem with this logic.
Create object manually
Initiatite form with instance new object
save
for above problem:
def AddData(request):
tpl = 'add.html'
if request.method == 'POST':
mdla = ModelAForm(request.POST)
if mdla.is_valid():
obj = mdla.save()
newObj = ModelB.objects.create(xmodel=obj)
mdlb = ModelBForm(request.POST, instance=newObj)
if mdlb.is_valid():
mdlb.save()
else:
mdla = ModalAForm()
mdlb = ModalBForm
This is solution i get, if anyone could do better please tell me. Thankx

How to filter a Django model based on requirement from another model?

I'd like to retrieve all my contacts from my Contact model excluding those listed on my DoNotContact model. Is the following the most efficient way to do that: contacts = Contact.objects.filter(dont_contact=False) Wondering if this is going to take long to process, is there a more efficient way?
class Contact(models.Model):
email = models.CharField(max_length=12)
first_name = models.CharField(max_length=50)
last_name = models.CharField(max_length=50)
audience = models.ForeignKey(Audience, on_delete=models.CASCADE)
def dont_contact(self):
try:
get_object_or_404(DoNotContact, email=self.email)
return True
except:
return False
def __str__(self):
return self.email
class DoNotContact(models.Model):
email = models.CharField(max_length=12)
#views.py
def send_email(request):
if request.method == "POST":
contacts = Contact.objects.filter(dont_contact=False)
Kwargs used model queryset filter methods are resolved into database columns. dont_contact here is a method and doesn't exist as a column in Contact model so calling Contact.objects.filter(dont_contact=False) will raise a FieldError.
For current implementation of your models you can do following
dont_contacts = DoNotContact.objects.values('email')
contacts = Contact.objects.exclude(email__in=dont_contacts)
A better solution with higher performance is to remove DoNotContact and add a BooleanField to Contact which handles your requirement.

How database data can be updated by id - Django

Hi guys im new in django and I want to update my database.
I have my form and my model that create correctly all the data in my database.
When this was created the performance field gets default value 0 and the created field gets the creation date.
Everything up to this moment is perfect.
I have this model and this view:
models.py
from django.contrib.auth.models import User
class Model(models.Model):
user = models.ForeignKey(User, on_delete=models.CASCADE)
id = models.AutoField(primary_key=True)
performance = models.FloatField(default=0)
created = models.DateTimeField(auto_now_add=True, null=True)
class Meta:
ordering = ['-created']
views.py
def form_x(request):
user = request.user
form = XForm(request.POST or None)
if form.is_valid():
performance = form_data.get('performance')
obj = Model.objects.create(user=user,
performance=performance,)
return redirect('form')
else:
form = TForm()
return render(request, 'funciones/btc.html', {'form':form})
My question:
How can i update the performance field searching by id, AUTOMATICALLY after 1 min
once the POST request has been sent?
i dont know whats better if use a function update view or a Class Update View
What you recommend?
Thank you so much!

Django - having trouble saving filtered object

For my first Django project I'm trying to make an app that lets users create lists of media (books, movies, etc.) with various fields describing each object (title, author, etc.), and I'm having trouble figuring out how to get it to save. That is to say that nothing happens when the form is submitted. Can someone tell me what I'm doing wrong? Sorry if this is a bit of a noob question; it seems like I'm missing something really basic here. (I'm using basic HTML forms instead of ModelForms because for some media types I want to ignore certain fields - e.g. "author" for movies - but if there is an easy way to do that using ModelForms, I'm all ears.)
from views.py:
def editbook(request,list_owner,pk):
book_list = Item.objects.all().filter(item_creator=list_owner).filter(category='book').order_by('type','name')
item_to_edit = Item.objects.get(pk=pk)
if request.method == 'POST':
item_to_edit.save()
return render_to_response('books.html', {'booklist': book_list, 'listowner': list_owner}, RequestContext(request))
else:
form=EditItem()
return render_to_response('editbook.html', {'listowner': list_owner, 'item_to_edit': item_to_edit}, RequestContext(request))
from models.py:
CATEGORY_CHOICES = (
('book','book'),
('tv','tv'),
('movie','movie'),
('game','game'),
('music','music'),
)
class Item(models.Model):
item_creator = models.CharField(max_length=30) # user name goes here
category = models.CharField(max_length=5, choices=CATEGORY_CHOICES)
name = models.CharField(max_length=70)
created = models.DateTimeField(auto_now_add=True)
modified = models.DateTimeField(auto_now=True)
artist = models.CharField(max_length=70, blank=True)
type = models.CharField(max_length=50, blank=True)
progress = models.CharField(max_length=10, blank=True)
finished = models.BooleanField(default=False)
rating = models.IntegerField(default=0, blank=True, null=True)
comment = models.CharField(max_length=140, blank=True)
def __unicode__(self):
return self.name
There is, of course, a way to only use some fields in a modelform: as fully documented in Using a subset of fields on the form, you can use the fields or exclude attributes in the form's Meta class.
However you'll still need, as szaman points out, to pass the POST data to the form and check for validity, and in addition you'll need to pass in the instance paramater as you're updating an existing instance.
What I see is that you get object from database and when form is submitted than just saving the object, but you don't update any field so you cannot see changes in db. Try to do:
if request.method == "POST":
form = MyForm(request.POST)
logging.info("form.is_valid() %s" % form.is_valid())
if form.is_valid():
item_to_edit.name = form.cleaned_data['name']
item_to_edit.save()
...

How to save a ManyToMany relationship from a ModelForm in Django

I'm not sure to save my ManyToMany relationship. I found my exact problem in this thread: Django embedded ManyToMany form, except instead of Sales and Products models, I have models that make up a movie.
I tried the solution, but I receive a syntax error. I don't understand how Django should link the EquipmentModel, LightModel, and ActorModel to the ManyToMany relationship in MovieModel. So far (before trying the other thread's solution), the CharFields that are displayed on the form for LightModel, EquipmentModel, and ActorModel are not linked to the ManyToManyField in MovieModel. So when I save the forms and try to access a particular Movie's actors, all I see is a blank list. The solution from the other thread seems to make sense since it tries to link the models to the ManyToMany relationship in MovieModel, but I don't understand how Django knows which MovieModel to add to (how does it get the correct movieID?).
On a side note, is there a way to check for duplicate movies when the user presses the 'Submit' button on the form? I want to avoid creating duplicates.
views.py:
def add_movie(request, movieID=""):
if request.method == "POST":
form = MovieModelForm(request.POST)
eform = EquipmentModelForm(request.POST)
lform = LightModelForm(request.POST)
aform = ActorModelForm(request.POST)
print 'checking form'
print request.POST.items()
if form.is_valid() and eform.is_valid() and lform.is_valid() and aform.is_valid():
print 'form is valid'
movie_to_add = form.save()
e = eform.save()
l = lform.save()
a = aform.save()
movie_to_add.actors.add(a)
movie_to_add.lights.add(l)
movie_to_add.equipments.add(e)
# return HttpResponseRedirect('/data')
else:
# code for create forms ....
return render_to_response('add_movie.html', {'form':form, 'eform':eform,'lform':lform, 'aform':aform,}, context_instance=RequestContext(request))
Other code that may help:
forms.py
class LightModelForm(forms.ModelForm):
class Meta:
model = LightModel
class ActorModelForm(forms.ModelForm):
class Meta:
model = ActorModel
class EquipmentModelForm(forms.ModelForm):
class Meta:
model = EquipmentModel
class MovieModelForm(forms.ModelForm):
class Meta:
model = MovieModel
fields = ("title", "rank")
models.py
class EquipmentModel(models.Model):
equip = models.CharField(max_length=20)
class ActorModel(models.Model):
actor = models.CharField(max_length=20)
class LightModel(models.Model):
light = models.CharField(max_length=20)
class MovieModel(models.Model):
rank = models.DecimalField(max_digits=5000, decimal_places=3)
title = models.CharField(max_length=20)
equipments = models.ManyToManyField(EquipmentModel, blank=True, null=True)
actors = models.ManyToManyField(ActorModel, blank=True, null=True)
lights = models.ManyToManyField(LightModel, blank=True, null=True)
def __str__(self):
return self.title
Edit: removed unnecessary init and fields thanks to DTing
Edit2: Fixed!
There is a whole lot of stuff going wrong here in addition to what spulec said.
Your models.py look okay.
class EquipmentModel(models.Model):
equip = models.CharField(max_length=20)
class ActorModel(models.Model):
actor = models.CharField(max_length=20)
class LightModel(models.Model):
light = models.CharField(max_length=20)
class MovieModel(models.Model):
rank = models.DecimalField(max_digits=5000, decimal_places=3)
title = models.CharField(max_length=20)
equipments = models.ManyToManyField(EquipmentModel, blank=True, null=True)
actors = models.ManyToManyField(ActorModel, blank=True, null=True)
lights = models.ManyToManyField(LightModel, blank=True, null=True)
def __str__(self):
return self.title
You don't need to override the __init__ method on forms if you are not changing anything on init. You also don't need to be explicit about the fields if you want to include them all.
class LightModelForm(forms.ModelForm):
class Meta:
model = LightModel
class ActorModelForm(forms.ModelForm):
class Meta:
model = ActorModel
class EquipmentModelForm(forms.ModelForm):
class Meta:
model = EquipmentModel
class MovieModelForm(forms.ModelForm):
class Meta:
model = MovieModel
fields = ("title", "rank")
your view doesn't really make sense unless for every movie you are trying to add you also want to:
add a new movie to the db using the submitted post data
create one actor object and add to db
create one light object and add to db
create one equipment object and add to db
take those three objects and add them to another movie's m2m relationships.
This other movie is some movie that you pulled from the urlconf and passed to your view, not the one you just created.
This all seems a little strange.
what i think you want to do is create all the equipment, actors and lights objects so they are in your db already, and use the default m2m formfield widget to select them when adding a movie.
so:
forms.py
class MovieModelForm(forms.ModelForm):
class Meta:
model = MovieModel
urls.py:
url(r'^add_movie/$', add_movie)
views.py:
def add_movie(request):
if request.method=='POST':
form = MovieModelForm(request.POST)
if form.is_valid():
form.save()
return HttpResponse('success')
else:
form = MovieModelForm()
context = {'form':form }
return render_to_response('some_template.html', context,context_instance=RequestContext(request))
you could combine adding actors, lights, and equipment into the same form but that's a bit much for me to write out right now.
As far as modifying your original code to add those lights, actors, and equipment to the movie you just created, you could do this:
if form.is_valid() and eform.is_valid() and lform.is_valid() and aform.is_valid():
new_movie = form.save()
e = eform.save()
l = lform.save()
a = aform.save()
new_movie.actors.add(a)
new_movie.lights.add(l)
new_movie.equipments.add(e)
Change it to:
movie_to_add = get_object_or_404(MovieModel, id=movieID)