Django - saving formset with ManyToMany - python

I've got the following problem. Once I try to save edited objects (details below), I'm getting error:
MultiValueDictKeyError at /apps/edit/1/
"Key 'application2server_set-0-id' not found in <QueryDict: {u'application2server_set-MAX_NUM_FORMS': [u''], u'name': [u'application1'], u'repository': [u'1'], u'application2server_set-INITIAL_FORMS': [u'2'], u'application2server_set-TOTAL_FORMS': [u'5'], u'csrfmiddlewaretoken': [u'bmEPdLCloNHKR0qUmwdhdmQ4aDKHV2CT'], u'servers': [u'1', u'2']}>"
Below are models and forms used:
class Server(models.Model):
host = models.CharField(max_length=100)
user = models.CharField(max_length=20)
root_directory = models.CharField(max_length=200)
class Repository(models.Model):
host = models.CharField(max_length=100)
user = models.CharField(max_length=20)
class Application(models.Model):
name = models.CharField(max_length=100)
repository = models.ForeignKey(Repository)
servers = models.ManyToManyField(Server, through='Application2Server', null=True, blank=True)
class Application2Server(models.Model):
application = models.ForeignKey(Application)
server = models.ForeignKey(Server)
tag = models.CharField(max_length=100)
deployment_date = models.DateTimeField(auto_now=True, blank=True)
class ServerForm(ModelForm):
class Meta:
model = Server
class RepositoryForm(ModelForm):
class Meta:
model = Repository
class ApplicationForm(ModelForm):
class Meta:
model = Application
class Application2ServerForm(ModelForm):
class Meta:
model = Application2Server
exclude = ('application', 'server', 'tag')
View used to save the date:
def app_edit(request, id):
application = get_object_or_404(Application, pk=id)
Application2ServerFormSet = inlineformset_factory(Application, Application2Server)
if request.method == 'POST':
form = ApplicationForm(request.POST, instance=application)
formset = Application2ServerFormSet(request.POST, instance=application)
if form.is_valid() and formset.is_valid():
saved_application = form.save()
formset.save()
return HttpResponseRedirect(reverse(
'proj.views.app_show',
args=(saved_application.pk,)
))
else:
form = ApplicationForm(instance=application)
formset = Application2ServerFormSet(instance=application)
return render(request, 'app_edit.html', {'form': form, 'formset': formset})
and template to generate the HTML and form itself:
<h1>App edit view</h1>
{% extends "base.html" %}
{% block container %}
<form method="post">{% csrf_token %}
<table>
{{ formset.management_form }}
{{ form.as_table }}
<tr><th></th><td><input type="submit" value="Save changes" /></td></tr>
</table>
</form>
{% endblock %}
Any help will be much appreciated! Thank you!

You need to render each form in the formset as well in the template.
Update your template to something like this (where you are rendering formset) :
<form method="post" action="">
{{ formset.management_form }}
<table>
{% for form in formset %}
{{ form.as_table }}
{% endfor %}
</table>
</form>
Reference: Formset in templates

Related

Image from an ImageField ModelForm not uploading into the server

Hi so I am new to Django and one of the things I'm trying to do is make a simple gallery application. Somehow I can't add images through the server via the forms if I use a Model Form although I can do it using a plain form. I've tried a lot of the stuff in here and also tried some Youtube stuff but it didn't still work.
Here is my models.py
from django.db import models
from django.urls import reverse
from django.core.validators import validate_image_file_extension
from django.core.files.storage import FileSystemStorage
fs = FileSystemStorage(location='/media')
class FavoriteImages(models.Manager):
def get_queryset(self):
return super().get_queryset().filter(favorite=True)
# Create your models here.
class Photo(models.Model):
name = models.CharField(max_length=120, null=True)
photo = models.ImageField(storage=fs, upload_to='media/', validators=[validate_image_file_extension])
date_uploaded = models.DateTimeField(auto_now=True)
favorite = models.BooleanField(default=False, blank=False)
slug = models.SlugField(null=True, blank=True)
gallery = models.Manager()
gallery_favorites = FavoriteImages()
class Meta:
ordering = ['-date_uploaded']
My Views.py
from PIL import Image
def image_new(request, *args, **kwargs):
Image.init()
form = PhotoForm(data=request.POST, files=request.FILES)
if request.method == 'POST':
form = PhotoForm(request.POST, request.FILES)
if form.is_valid():
form.save()
redirect('../all')
context = {
'form': form
}
return render(request, "form.html", context)
My forms.py
class PhotoForm(forms.ModelForm):
name = forms.CharField(label='',widget=forms.TextInput(attrs={'class':'form-control', 'placeholder':'Title'}))
photo = forms.ImageField(widget=forms.FileInput(attrs={'class':'form-control'}))
favorite = forms.BooleanField(label='Mark as Favorite',widget=forms.CheckboxInput(attrs={'class':'form-check-input'}))
class Meta:
model = Photo
fields = ['name',
'photo',
'favorite']
my .html
{% extends "base.html" %}
{% block content %}
{% if form.is_multipart %}
<form enctype="multipart/form-data" method="post">
This form is a multipart.
{% else %}
<form method="post">
{% endif %}
{% csrf_token %}
{% if form.media %}
{{ form.media }}
{% endif %}
{{ form.as_p }}
<input type="submit" class="btn btn-primary" value="Save"/>
</form>
{% endblock %}
I've placed this in the settings:
MEDIA_URL = 'media/'
MEDIA_ROOT = os.path.join(BASE_DIR, 'media')
Something I noticed:
The media folder (root) remains empty, but Model.photo has an url. (not null)
How do I modify my form so that the image gets posted?
EDIT: I fixed it by changing the widget of the ImageField. I don't know why it works now, but it does. Thanks for all the help
Why all those {% if %} in the template? I think it's unecessary. I would write it as follows,
{% extends "base.html" %}
{% block content %}
<form enctype="multipart/form-data" method="post">
{% csrf_token %}
{{ form.as_p }}
<button type="submit" class="btn btn-primary" value="Save"></button>
</form>
{% endblock %}
Your form can also be simplified as such,
class PhotoForm(forms.ModelForm):
name = forms.CharField(label='',widget=forms.TextInput(attrs={'class':'form-control', 'placeholder':'Title'}))
photo = forms.ImageField()
favorite = forms.BooleanField(label='Mark as Favorite',widget=forms.CheckboxInput(attrs={'class':'form-check-input'}))
'''
You don't need the Meta class when inheriting from forms.ModelForm. I think the widgets aren't necessary, unless you need to style with CSS specifics.
Your view can also be simplified quite a bit. You don't need PIL Image unless you are modifying your image.
I would write like this,
def image_new(request, *args, **kwargs):
form = PhotoForm()
if request.method == 'POST':
form = PhotoForm(request.POST, request.FILES)
if form.is_valid():
form.save()
redirect('../all')
context = {
'form': form
}
return render(request, "form.html", context)
Django will take care of saving the image to your media folder and assigning it to the ImageField in the model.

Django queryset in view isn't returning anything to the html template

I want to show all posts of a specific user in their profile page but only their profile information is being displayed but not the posts.
My initial code was simply trying to loop through the posts in the template like this:
{% for post in user.posts.all %}
{% endfor %}
But it didn't work. So I tried this next.
views.py
user = get_object_or_404(User, username=username)
post = Post.objects.filter(created_by=user.id)
context = {
'user': user,
'post': post
}
return render(request, 'users/profile.html', context)
profile.html
<div class="user-profile">
<img class="rounded-circle account-img" src="{{ user.profile.image.url }}">
{{ user.username }}
{{ user.email }}
</div>
<div class="user-post-model">
{% for post in posts %}
<img class="rounded-circle post-img" src="{{ post.created_by.profile.image.url }}">
{{ post.title }}
{{ post.content|safe }}
{{post.tag}}
{{ post.created_by }}
{{ post.created_at|naturaltime}}
{% endfor %}
</div>
It didn't work either
I also tried using a ListView to post the posts. It worked but instead of showing the specific user's profile information it showed the logged in user's profile information but the specific user's posts.
like this:
def profile(request, username):
user = get_object_or_404(User, username=username)
context = {
'user': user
}
return render(request, 'users/profile.html', context)
class UserPostListView(ListView):
model = Post
template_name = 'users/profile.html'
context_object_name = 'posts'
def get_queryset(self):
user = get_object_or_404(User, username=self.kwargs.get('username'))
return Post.objects.filter(created_by=user).order_by('-created_at')
This is the post model
class Post(models.Model):
title = models.CharField(max_length=255)
content = RichTextField(blank=True, null=True, max_length=30000)
created_at = models.DateTimeField(default=timezone.now)
created_by = models.ForeignKey(User, on_delete=models.CASCADE)
tag = models.CharField(max_length=255, default='uncategorised')
class Meta:
ordering = ('-created_at',)
def __str__(self):
return self.title + ' | ' + str(self.created_by)
def get_absolute_url(self):
return reverse("post-detail", kwargs={"pk": self.pk})
What is wrong?
To loop over the related Post objects to User, use _set (Django Docs).
So in your case user.post_set:
{% for post in user.post_set.all %}
{{ post.title }}
{% endfor %}

How to auto-fill fields while updating django forms?

I am creating a to-do app in django and while updating a task, i want to auto-fill the fields with previous data. Where am i messing up?
This is my views.py for the same:-
task = get_object_or_404(ToDoList, id=id)
if request.method == "POST":
form = UpdateTaskForm(request.POST)
if form.is_valid():
task.description = form.cleaned_data['description']
task.save()
form.save()
return redirect(reverse('list'))
else:
form = UpdateTaskForm(instance=task)
context = {
'form':form,
'task':task,
}
return render(request, 'TaskList/update.html', context)
and this is my forms.py:-
class Meta:
model = ToDoList
fields = ['title', 'description', 'due_date', 'completed']
here is my template file:-
{% load crispy_forms_tags %}
{% block title %} Updating task {% endblock %}
{% block content %}
<form method="post">
{% csrf_token %}
{{ form|crispy }}
<button type="submit" class="btn btn-success" value="Submit"> Save </button>
</form>
{% endblock %}
and here is my models.py:-
from django.utils import timezone
# Create your models here.
class ToDoList(models.Model):
title = models.CharField(max_length=120)
description = models.TextField(help_text='Explain your task!', blank=True)
created_date = models.DateTimeField(default=timezone.now())
due_date = models.DateTimeField(default=timezone.now())
completed = models.BooleanField(default=False)
#Author foreign key
def __str__(self):
return self.title
If you are updating an instance you must also pass the same instance in the POST method also, so after
if request.method == "POST": add form = UpdateTaskForm(request.POST,instance=task)
I guess you are using crispy forms, so according to this question here They are rendering the forms using {% crispy form %} instead of the way you have done as {{ form|crispy }} maybe that is the issue.

form.is_valid() is returning False when using ModelForm

I am creating a form using ModelForm to let the users upload a file along with a description . The is_valid() function isn't returning true and I am really confused. I have searched and there are many questions with same title as mine but they don't solve my problem.
here is forms.py:
class PostForm(forms.ModelForm):
document = forms.FileField(widget=forms.FileInput)
class Meta:
model = FeedModel
fields = ['description', 'document']
Here is models.py:
class FeedModel(models.Model):
description = models.CharField(max_length=255, blank=True)
document = models.FileField()
like = models.IntegerField(default=0)
dateTime = models.DateTimeField(auto_now=True, auto_created=True)
user = models.ForeignKey(User, on_delete=models.CASCADE, default=0)
def get_absolute_url(self):
u=self.user
return reverse('home:feed',u.primary_key)
Here is views.py:
class PostView(CreateView):
form_class = PostForm
template_name = 'home/feedModel_form.html'
def get(self, request, *args, **kwargs):
form=self.form_class(None)
return render(request, self.template_name, {'form':form })
def post(self, request, *args, **kwargs):
logger = logging.getLogger(__name__)
form=self.form_class(request.POST)
if form.is_valid():
user=request.user
self.object=form.save(commit=False)
self.object.user=user
self.object.save()
logger.error("voila")
redirect({'home:feed'}, user.id)
return render(request, self.template_name, {'form':form })
def feedview(request, user_id):
user = User.objects.get(pk=user_id)
return render(request, 'home/feed.html', {'user': user})
Here is feedModel_form.html:
{% extends 'home/navbar.html' %}
{% block body %}
<div class="form">
<form action="" method="post" enctype="multipart/form-data">
{% csrf_token %}
{% include 'home/form.html' %}
<button type="submit" class="button button-block" `
name="reg_btn">Post</button>`
</form>
</div>
{% endblock %}
Here is form.html:
{% for field in form %}
<div class="field-wrap">
<label>
{{ field.label_tag }}<span class="req">*</span>
</label>
<div>{{ field }}</div>
</div>
{% endfor %}
To see why the form isn't valid, you should check form.errors.
One error will be because you have not passed request.FILES to the form.
form=self.form_class(request.POST, request.FILES)
There may be other errors as well. If you used {{ form }} in your template, Django would include the errors automatically. Since you are rendering the fields manually, it's up to you to include the errors.
The key problem here is that you have overridden post. That means that you're missing out on lots of the code from CreateView.
In your case, it looks like you could remove the post method, and simply override form_valid instead.
def form_valid(self, form):
self.object=form.save(commit=False)
self.object.user=user
self.object.save()
# Note that you had {'home:feed'} here which was incorrect
return redirect('home:feed', user_id)
Your document field expects an uploaded file and is required. In order for the form to actually get the file, you have to also pass it the uploaded file in views.py:
form = self.form_class(data=request.POST, files=request.FILES)

data is not inserting in database when I click submit button

I have created my first app in Django (1.10.5) / Python 3.4. I have a login page and a register page. Which is working fine.
I can create new user and login with that id. Now after the login I want user to fill a form with some information and click on submit. And the information should get stored in the database.
So I created a model first : Model.py
class UserInformation(models.Model):
firstName = models.CharField(max_length=128)
lastName = models.CharField(max_length=128)
institution = models.CharField(max_length=128)
institutionNumber = models.CharField(max_length=128)
cstaPI = models.CharField(max_length=128)
orchidNumber = models.CharField(max_length=128)
This has created a table in the DB.
forms.py
class UserInformationForm(ModelForm):
class Meta:
model = UserInformation
fields = '__all__'
views.py
def home(request):
form = UserInformationForm()
variables = { 'form': form, 'user': request.user }
return render(request,'home.html',variables)
home.html
{% extends "base.html" %}
{% block title %}Welcome to Django{% endblock %}
{% block head %}Welcome to Django{% endblock %}
{% block content %}
<p> Welcome {{ user.username }} !!! Logout<br /><br /> </p>
<form method="post" action=".">{% csrf_token %}
<table border="0">
{{ form.as_table }}
</table>
<input type="submit" value="Submit" style="position:absolute"/>
</form>
{% endblock %}
But when I click on submit button, It does not insert data into my table.
here is the answer, we need to use the request.POST
def home(request):
if request.method == 'POST':
form = UserInformationForm(request.POST)
form.save()
return HttpResponseRedirect('/home/')
else:
form = UserInformationForm()
variables = { 'form': form, 'user': request.user }
return render(request,'home.html',variables)
the first: you need add urls.py to you app
the second: you need to change your views.py to lool like this
`
info = UserInformation()
lastName = request.POST.get('lastName')
...
info.save()
`

Categories

Resources