django ManyToManyField save [duplicate] - django

This question already has answers here:
Saving Many To Many data via a modelform in Django
(2 answers)
Closed 4 years ago.
There's form with many fields (Date, Char, Text, Image, URL...) and they works fine. I mean values are submitted to DB as they must. But when I added ManyToManyField, it didn't save the value of this MultipleChoice form to DB. Any ideas why?
models.py:
class EventTag(models.Model):
tags = models.CharField(max_length=300)
def __str__(self):
return self.tags
class Article(models.Model):
source = models.CharField(max_length=100)
source_img = models.ImageField(default='default.png', blank=True)
#other fields
event_tags = models.ManyToManyField(EventTag, blank=True)
forms.py:
class CreateArticle(forms.ModelForm):
class Meta:
model = models.Article
fields = ['source', 'source_img', 'event_tags', ]
views.py:
def article_create(request):
if request.method == 'POST':
form = forms.CreateArticle(request.POST, request.FILES)
if form.is_valid():
instance = form.save(commit=False)
instance.author = request.user
instance.save()
return redirect('articles:list')
else:
form = forms.CreateArticle()
return render(request, 'articles/article_create.html', { 'form': form })

after save your form you must call form.save_m2m(). your view must be like this:
def article_create(request):
if request.method == 'POST':
form = forms.CreateArticle(request.POST, request.FILES)
if form.is_valid():
instance = form.save(commit=False)
instance.author = request.user
instance.save()
form.save_m2m()
return redirect('articles:list')
else:
form = forms.CreateArticle()
return render(request, 'articles/article_create.html', { 'form': form })

Related

how to upload multiple images properly

I have a simple model which has four different fileFields for uploading different files and images.
this is my models:
class DocumentInfo(models.Model):
id = models.AutoField(primary_key=True)
certificate = models.FileField(upload_to="documents", null=True)
id_card = models.FileField(upload_to="documents", null=True)
service_certificate = models.FileField(upload_to="documents", null=True)
educational_certificate = models.FileField(upload_to="documents", null=True)
users need to simply upload some images in four individual fields so, I created a simple form and passed it to views like this:
class DocumentForm(forms.ModelForm):
class Meta:
model = DocumentInfo
fields = ['certificate','id_card','service_certificate','educational_certificate']
views.py:
def document_info(request):
if request.method == 'POST':
form = DocumentForm(request.POST, request.FILES)
if form.is_valid():
form.instance.user = request.user
form.save()
return redirect('document')
if 'delete' in request.GET:
return delete_item(DocumentInfo, request.GET['id'])
else:
form = DocumentForm()
documents = DocumentInfo.objects.filter(user=request.user)
context = {
'form': form,
'documents': documents,
}
return render(request, 'reg/documents.html', context)
it works just fine at first but I cant reupload anything! the uploaded image neither gets saved the second time around nor deleted. what am I doing wrong?
try this.
views.py
def document_info(request):
documents = DocumentInfo.objects.filter(user=request.user).order_by('-pk')
if request.method == 'POST':
if documents:
form = DocumentForm(request.POST, request.FILES,instance=documents[0])
else:
form = DocumentForm(request.POST, request.FILES)
if form.is_valid():
if not documents:
form.instance.user = request.user
form.save()
return redirect('document')
else:
if documents:#if the user already has a document.
form = DocumentForm(instance=documents[0])
else:
form = DocumentForm()
context = {
'form': form,
'documents': documents,
}
return render(request, 'reg/documents.html', context)

Issues Saving Django ModelForms with m2m Relations

I'm trying to use Django ModelForms to allow teachers to schedule weekly classes with students. However, whenever I save a new instance of the weekly class from the modelform the m2m relations (students and teachers) are not saved.
I've looked pretty extensively in the Django documentation and tried everything to remedy this including setting commit=False on the save method and then using the save_m2m method. No dice.
Here's my code
models.py
class WeeklyClass(models.Model):
status = models.CharField(
max_length=1,
choices=STATUS_CHOICES,
default="A")
students = models.ManyToManyField(
Profile,
limit_choices_to=models.Q(is_teacher=False),
related_name='student_weekly_classes',)
teachers = models.ManyToManyField(
Profile,
limit_choices_to=models.Q(is_teacher=True),
related_name='teacher_weekly_classes',)
class Meta:
verbose_name = 'Class'
verbose_name_plural = 'Classes'
ordering = ["-created"]
forms.py
class WeeklyClassForm(ModelForm):
class Meta:
model = WeeklyClass
fields = [
"status",
"students",
"teachers",
"weekday",
"duration_hours",
"hour",
"minute"]
views.py
#login_required
def new_weekly_class(request):
if request.method == "POST":
form = WeeklyClassForm(request.POST)
if form.is_valid():
form.save()
return redirect(reverse(
"weekly_class_list",
kwargs={"username": request.user.username}))
else:
form = WeeklyClassForm()
return render(
request,
"weekly_classes/new_weekly_class.html",
{"form": form})
form.save() does not directly save the many to many instances so after saving the form.save() also call form.save_m2m() to save manytomay relationship.
#login_required
def new_weekly_class(request):
if request.method == "POST":
form = WeeklyClassForm(request.POST, request.FILES)
if form.is_valid():
form.save()
form.save_m2m()
return redirect("weekly_class_list", kwargs={"username": request.user.username})
else:
form = WeeklyClassForm()
template = "weekly_classes/new_weekly_class.html"
context = {"form": form}
return render(request, template, context)
for reference: https://docs.djangoproject.com/en/dev/topics/forms/modelforms/#the-save-method

Django - How to Save ImageField Even if Form is Not Valid

I have a fairly standard model and form. I have some mandatory fields with an ImageField. When the user choose an image and doesn't field the mandatory fields, the image isn't saved and the user needs to 're-upload' it again.
As the row in the database already exists (because this form is part of a 'wizard'), I don't mind saving the picture in the database even if all the form isn't valid with all the mandatory data.
This is what I have right now in my view, which works when you fill all the mandatory fields:
def my_view(request):
instance = MyModel.objects.get(user=request.user)
form = MyForm(instance=instance)
if request.POST:
form = MyForm(request.POST, request.FILES, instance=instance)
if form.is_valid():
new_instance = form.save(commit=False)
if request.FILES and request.FILES['photo']:
uploaded_photo = request.FILES['photo']
new_instance.photo = uploaded_photo
new_instance.save()
return HttpResponseRedirect(reverse('new_url'))
return render_to_response('current_template.html', locals(), context_instance=RequestContext(request))
Here's what I tried to save the picture in DB even if the other fields aren't filled, but I get the error Django Upload Error - Upload a valid image (either not an image or corrupted):
def my_view(request):
instance = MyModel.objects.get(user=request.user)
form = MyForm(instance=instance)
if request.POST:
form = MyForm(request.POST, request.FILES, instance=instance)
if request.FILES and request.FILES['photo']:
uploaded_photo = request.FILES['photo']
instance.photo = uploaded_photo
instance.save()
if form.is_valid():
new_instance = form.save()
return HttpResponseRedirect(reverse('new_url'))
return render_to_response('current_template.html', locals(), context_instance=RequestContext(request))
Here's my form (fairly simple):
class MyForm(ModelForm):
first_name = forms.CharField(label='First Name', max_length=50, required=True)
last_name = forms.CharField(label='Last Name', max_length=50, required=True)
photo = forms.ImageField(required=False)
def __init__(self, *args, **kwargs):
super(MyForm, self).__init__(*args, **kwargs)
class Meta:
model = MyModel
fields = ('first_name','last_name', 'photo')
Here's my model (again very simple):
class MyModel(models.Model):
first_name = models.TextField(max_length=50)
last_name = models.TextField(max_length=50)
photo = ImageField(upload_to=get_photo_path,null=True,blank=True)
This is how I made it work. Notice that there's no 'request.FILES' as a parameter for the constructor of the form in the 'else' when the form is not valid. This is what made Django display the error message.
if form.is_valid():
instance = form.save(commit=False)
if request.FILES and request.FILES['photo']:
instance = save_photo(instance, request.FILES['photo'])
instance.save()
return HttpResponseRedirect(reverse('url'))
else:
if request.FILES and request.FILES['photo']:
instance = save_photo(instance, request.FILES['photo'])
form = InstanceForm(request.POST, instance=instance)

django: ForeignKeyField limit_choices_to "parents pk"?

I've a model (Parent model):
class Post(models.Model):
image = models.ImageField(upload_to='%Y/%m/%d')
title = models.CharField(max_length=200)
width = models.DecimalField(max_digits=3, decimal_places=0)
height = models.DecimalField(max_digits=3, decimal_places=0)
year = models.PositiveIntegerField()
def __str__(self):
return self.title
and another model (Child model):
class Addimg(models.Model):
post = models.ForeignKey('Post', null=True)
addimg = models.ImageField(upload_to='%Y/%m/%d')
def __str__(self):
return self.post
My Addimg Form:
class AddimgForm(forms.ModelForm):
class Meta:
model = Addimg
fields = ('post', 'addimg', 'width', 'height',)
views.py using the form:
def addimg(request, pk):
if request.method == "POST":
form = AddimgForm(request.POST, request.FILES)
post = get_object_or_404(Post, pk=pk)
if form.is_valid():
addimg = form.save(commit=False)
addimg.addimg = request.FILES['addimg']
addimg.save()
return redirect('blog.views.detail', pk=post.pk)
else:
form = AddimgForm()
return render(request, 'blog/edit.html', {'form': form})
And my Problem is that when I create a "Child model" my post field returns all instances of allready created Post models as choices. What I want is that it automatic only displays the one Post it is related to without choices. Is ForeignKey the right model for that?
Any Ideas how this could work. thanks
ForeignKey field is translated into ModelChoiceField inside a Django ModelForm. If you inspect that class you will notice that this type of field has an queryset attribute required. By default Django provides the full set of objects. You can override this inside your form __init__ method by providing the parent object the form will need.
Consider the following example code:
def addimg(request, pk):
post = get_object_or_404(Post, pk=pk)
if request.method == "POST":
form = AddimgForm(request.POST, request.FILES, post=post)
#...
else:
form = AddimgForm(post=post)
return render(request, 'blog/edit.html', {'form': form})
class AddimgForm(forms.ModelForm):
class Meta:
model = Addimg
fields = ('post', 'addimg', 'width', 'height',)
def __init__(self, *args, **kwargs):
post = kwargs.pop('post')
super(AddimgForm, self ).__init__(*args, **kwargs)
self.fields['post'].queryset = Post.objects.filter(id=post.id)
What you want to do is create a Many-to-one relationship. For example,
post = models.ForeignKey('Post', null=True)
This means you can filter on it for example,
Addimg.objects.filter(post=Post)
or
Post.objects.get(pk=1)
Post.addimg_set.filter(xyz=etc)
Read more here: https://docs.djangoproject.com/en/1.8/topics/db/examples/many_to_one/

ModelForm not saving data

It is not saving up the data:
# Models
class Comment(models.Model):
created = models.DateTimeField(auto_now_add=True)
author = models.CharField(max_length=60)
body = models.TextField()
# Forms
class CommentForm(ModelForm):
class Meta:
model = Comment
#Views.py
def add_comment(request):
if request.method == 'POST':
form = CommentForm(request.POST)
if form.is_valid():
save_it = form.save()
save_it.save()
comment = form.cleaned_data["body"]
return render(request, 'task-result.html', {
'form': form, 'comment': comment,
})
else:
form = CommentForm()
return render(request, 'Task-form.html', {
'form': form,
})
AS you may see, I am not only trying to save comment's data to database but also and print it comment out. So where is my mistake?