Django formset not saving my files - python

So I have these two models Lecture and FileUpload. I want that the user to be able to add a lecture to a specific course and also upload multiple files for that lecture. Thing is that after I submit the form the information gets saved except for the uploaded files, so I am guessing something is wrong with my formset. Please have a look:
FileFormset = inlineformset_factory(Lecture, FileUpload, exclude=[])
def classroom(request):
if request.method == 'POST':
form1 = LectureForm(request.POST)
if form1.is_valid():
lecture = form1.save()
formset = FileFormset(request.POST, request.FILES, instance=lecture, prefix='files')
if formset.is_valid():
formset.save()
else:
print(formset.errors)
formset.save()
return redirect('courses:index')
else:
form1 = LectureForm()
formset = FileFormset()
context = {'teacher_data': TeacherData.objects.all(),
'teachers': Teacher.objects.all(),
'courses': Course.objects.all(),
'form1': form1,
'formset': formset,
}
return render(request, 'courses/classroom.html', context)
<form method="post" action="">
{% csrf_token %}
{{ form1.as_p }}
{{ formset.management_form }}
{% for form in formset %}
{{ form }} <br>
{% endfor %}
<br>
<button type="submit">Add Lecture</button>
</form>
class LectureForm(forms.ModelForm):
class Meta:
model = Lecture
fields = ('course', 'lecture_title', 'lecture_category', 'content')
class FileForm(forms.ModelForm):
class Meta:
model = FileUpload
fields = ('files',)
class Lecture(models.Model):
LECTURE_CHOICES = (
('Courses', 'Courses'),
('Seminars', 'Seminars'),
)
course = models.ForeignKey('Course', on_delete=models.CASCADE, default='', related_name='lectures',)
lecture_category = models.CharField(max_length=10, choices=LECTURE_CHOICES, default='Courses',)
lecture_title = models.CharField(max_length=100, blank=True, null=True)
content = models.TextField(blank=True, null=True)
def __str__(self):
return str(self.lecture_title)
class FileUpload(models.Model):
files = models.FileField(upload_to='documents', null=True, blank=True)
lecture = models.ForeignKey('Lecture', related_name='files', on_delete=None, default=None)
def __str__(self):
return str(self.files)

add enctype attribute to you from widget like,
<form method="post" action="" enctype= multipart/form-data>
Try this

Related

nothing is saved after updating form

I have a Candidat models and Experience_Pro models as shown below with fk relation between them .
i can register or login a candidat(user) and a profil page with firstname and lastname of that candidat shown, and a form for Experience_Pro for the user to add if he does have one .
but when i enter all the info in the Experience_Pro form and click update nothing is added to candidat
I don't know what i am missing but the form is showing with no errors and even after i update the profile no errors but nothing is saved to candidat
models.py
class Candidat(models.Model):
user = models.OneToOneField(User, on_delete=models.CASCADE)
experience_Pro = models.ForeignKey('Experience_Pro' ,on_delete=models.CASCADE,blank=True,
null=True,default='')
class Experience_Pro(models.Model):
annee_debut = models.IntegerField()
annee_fin = models.IntegerField()
description_exp_pro = models.TextField(null=True,blank=True)
forms.py
class UpdateCandidat(forms.ModelForm):
class Meta:
model=Candidat
fields=['experience_Pro']
class CreateExperience_Pro(forms.ModelForm):
class Meta:
model=Experience_Pro
fields='__all__'
views.py
#login_required
def profil(request):
exp_form = CreateExperience_Pro()
c_form = UpdateCandidat()
if exp_form.is_valid():
exp = exp_form.save()
candidat = c_form.save(commit=False)
candidat.save(experience_Pro=exp)
return redirect('profil')
context={
'exp_form':exp_form
}
return render(request ,'candidats/profil.html',context)
profil.html
<h1>Profil Candidat</h1>
<p>Prenom: {{ user.first_name }}</p>
<p>Nom: {{ user.last_name }}</p>
<p>Email: {{ user.email }}</p>
<form method="POST" action="">
{% csrf_token %}
{% comment %} {{ c_form }} {% endcomment %}
{{ exp_form }}
<input type="submit" value="Update">
</form>
You need to do some update:
#login_required
def profil(request):
if request.method == 'POST':
exp_form = CreateExperience_Pro(request.POST)
c_form = UpdateCandidat(request.POST)
if exp_form.is_valid() and c_form.is_valid():
exp = exp_form.save()
candidat = c_form.save()
return redirect('profil')
else:
context = {
'exp_form': exp_form,
'c_form': c_form,
}
return render(request, 'candidats/profil.html', context)
else:
exp_form = CreateExperience_Pro()
c_form = UpdateCandidat()
context = {'exp_form': exp_form, 'c_form': c_form}
return render(request, 'candidats/profil.html', context)

Django - objects.all() shows nothing

I'm trying to get a list of objects in Django from a model.
I just want to get the list of 'dht node' from the request user, but it shows nothing in the html file (as if the list was empty). The user that I'm using has 2 'dht nodes' and they're shown in the django admin.
I don't know what is wrong, because if I use the instruction "member.dht.create(...)" in the views function and a create a new 'dht node' like this, this is shown. Only 'dht nodes' that I enter by form do not show. Can be the form?
Thanks a lot, Here's my code:
Models.py
class Node(models.Model):
name = models.CharField(primary_key=True, null=False, max_length= 50)
description= models.CharField(default=None, null=False, max_length= 250)
topic=models.CharField(default=None, null=False, max_length= 50, unique=True)
def __unicode__(self):
return self.name
class dht(Node):
temp = models.IntegerField(default=None, null=True)
hum = models.IntegerField(default=None, null=True)
class UserProfile(User):
uid = models.CharField(default=None, null=False, max_length= 250)
dht = models.ManyToManyField(dht, blank=True)
def __unicode__(self):
return self.user.username
Views.py -dht list-
#login_required(login_url = '/web/login')
def listDhtSensor(request):
member = request.user.userprofile
list = member.dht.all()
return render(request, 'web/listDhtSensor.html', {'list':list})
Html -listDhtSensor.html-
{% block content %}
{% for dht in list %}
{{ dht.name }}
{{ dht.topic }}
{% endfor %}
{% endblock %}
Forms.py
class newDHTSensorForm(forms.ModelForm):
class Meta:
model = dht
field = ['name',
'description',
'topic',]
labels = {'name': 'Name' ,
'description': 'Description',
'topic': 'Topic',}
exclude = ['temp', 'hum']
Views.py -dht form-
#login_required(login_url = '/web/login')
def newDHTSensor(request):
if request.method == "POST":
form = newDHTSensorForm(request.POST)
if form.is_valid():
post = form.save(commit=False)
post.save()
return redirect('/web/dhtDetail')
else:
form = newDHTSensorForm()
return render(request, 'web/newDhtSensor.html', {'form': form})
Html -newDhtSensor.html-
{% block content %}
<div class="boxReg">
<form method="post">
{% csrf_token %}
<h2>{{ form.name.errors.as_text }}</h2>
<p><label for="id_name">Name:</label> <input class="barraForm" type="text" name="name" maxlength="150" autofocus="" required="" id="id_name"></p>
<p><label for="id_description">Description:</label> <input class="barraForm" type="text" name="description" maxlength="150" id="id_description"></p>
<h2>{{ form.topic.errors.as_text }}</h2>
<p><label for="id_topic">Topic:</label> <input class="barraForm" type="text" name="topic" maxlength="254" id="id_topic"></p>
<div class="boxButtonReg">
<button class="buttonReg" type="submit">Save</button>
</div>
</form>
</div>
{% endblock %}
It shows nothing because you did not link you dht objects to that UserProfile, so if you later query for the dhts for that UserProfile, evidently the list is empty. You should add it to the dht relation, like:
#login_required(login_url = '/web/login')
def newDHTSensor(request):
if request.method == "POST":
form = newDHTSensorForm(request.POST)
if form.is_valid():
post = form.save()
request.user.userprofile.dht.add(post)
return redirect('/web/dhtDetail')
else:
form = newDHTSensorForm()
return render(request, 'web/newDhtSensor.html', {'form': form})
Note that you first need to save the post, so you should omit the commit=False aprameter.

Django - filter drop down choices based on user group

i am trying to filter a forms drop down list based on a users group
To find the user group i am using a custom templatetag
template tag
from django import template
register = template.Library()
#register.filter(name='in_group')
def in_group(user,group_name):
try:
group=Group.objects.get(name=group_name)
except Group.DoesNotExist:
return False
return group in user.groups.all()
task.html
{% load group_check %}
<form method="post">
{% csrf_token %}
{% if user.is authenticated %}
{% if requset.user|in_group:'DEVELOPER' %}
#...DO SOMETHING
{{ form.as_p }}
<button type="submit">add task</button>
</form>
models
GOALS_TYPE= (('DT','Daily Task'),
('WT','Weekly Task'),
('V','Verified'),
('D','Done'),
)
class GoalStatus(models.Model):
title = models.CharField(max_length=254, null=True)
task_id=models.IntegerField(default=1,null=False)
description =models.CharField(max_length=254)
verified_by=models.ForeignKey('ScrumyUser', on_delete= models.CASCADE, null=True)
status=models.CharField(choices=GOALS_TYPE, max_length=2, default='DT')
def __str__(self):
return self.title
the template for the form is based on the forms.py
forms.py
class ChangeTaskForm(forms.ModelForm):
class Meta:
model = GoalStatus
fields = ('title', 'task_id','description','status', 'verified_by')
views.py
def move_goals(request,pk):
if request.method == 'POST':
form = ChangeTaskForm(request.POST)
if form.is_valid():
return HttpResponseRedirect('/index/')
else:
form = ChangeTaskForm()
return render(request, 'oderascrumy/task.html', {'form': form})
urls.py
path('task/<pk>/', views.move_goals, name='move_goals')
so for example if the user is in group "developer", the drop down choices for status will be only verified and done
You can do like below
views.py
def move_goals(request,pk):
if request.method == 'POST':
form = ChangeTaskForm(request.POST, user=request.user)
if form.is_valid():
return HttpResponseRedirect('/index/')
else:
form = ChangeTaskForm(user=request.user)
return render(request, 'oderascrumy/task.html', {'form': form})
forms.py
class ChangeTaskForm(forms.ModelForm):
def __init__(self, *args, **kwargs):
user = kwargs.pop('user', None)
super(ChangeTaskForm, self).__init__(*args, **kwargs)
if user.groups.filter(name='DEVELOPER').exists():
self.fields['status'].choices = (('V','Verified'), ('D','Done'),)
class Meta:
model = GoalStatus
fields = ('title', 'task_id','description','status', 'verified_by')
template.html
<form method="post">
{% csrf_token %}
{{ form.as_p }}
<button type="submit">add task</button>
</form>
I think no need of template tag for this.

Django save only first form of formset

I've looked through every similar question (and tried them), but still couldn't find answer.
I have two models:
class Project(models.Model):
author = models.ForeignKey(settings.AUTH_USER_MODEL, default=1)
name = models.CharField(max_length=120, verbose_name = "Название проекта")
url = models.URLField(max_length=120, unique=True, verbose_name = "Полный адрес сайта")
robots_length = models.CharField(max_length=5, default=0)
updated = models.DateTimeField(auto_now=True, auto_now_add=False)
timestamp = models.DateTimeField(auto_now=False, auto_now_add=True)
def __unicode__(self):
return self.name
def __str__(self):
return self.name
def get_absolute_url(self):
from django.urls import reverse
return reverse('projects:detail', args=[str(self.id)])
class ProjectPage(models.Model):
page_project = models.ForeignKey(Project, on_delete=models.CASCADE)
page_url = models.URLField(verbose_name = "Адрес страницы")
page_title = models.CharField(max_length=300, blank=True, verbose_name = "meta-title",default="")
page_description = models.CharField(max_length=300, blank=True, verbose_name = "meta-description",default="")
page_h1 = models.CharField(max_length=300, blank=True, verbose_name = "Заголовок h1",default="")
def __unicode__(self):
return self.page_url
def __str__(self):
return self.page_url
For each model there is a form:
class ProjectFormUpdate(forms.ModelForm):
class Meta:
model = Project
fields = [
"name",
"url",
]
widgets = {
'name': forms.TextInput(attrs={'placeholder': 'Произвольное название'}),
}
class ProjectPageForm(forms.ModelForm):
class Meta:
model = ProjectPage
fields = [
'page_project',
'page_url',
'page_title',
'page_description',
'page_h1',
]
widgets = {
'page_project': forms.HiddenInput()
}
In views.py I have:
def projects_update(request, proj=None):
instance = get_object_or_404(Project, id=proj)
form = ProjectFormUpdate(request.POST or None, instance=instance)
formset_f = modelformset_factory(ProjectPage, form=ProjectPageForm, extra=3)
formset = formset_f(queryset=ProjectPage.objects.filter(page_project__id=proj), initial =[{'page_project': proj}])
if request.method == 'POST':
formset = formset_f(request.POST)
for formset_form in formset:
if formset_form.is_valid() and formset_form.has_changed():
formset_form.save()
if form.is_valid():
form.save()
context = {
'title': "Редактируем проект - "+instance.name,
'form': form,
'formset': formset,
'instance': instance,
}
return render(request, "projects_update.html", context)
And, finaly, html
<form method="POST" action="" class="create-form">
{{ formset.management_form }}
{% csrf_token %}
<div class="row">
<div class="col-lg-6 offset-lg-3 col-md-10 offset-md-1 col-xs-10 offset-xs-1 form-bg">
<h2>Общие данные</h2>
{{ form|crispy}}
<input type="submit" class="btn btn-success" value="Обновить проект" />
</div>
</div>
{% for formset_form in formset %}
<div class="row form-container">
<div class="col-lg-6 offset-lg-3 col-md-10 offset-md-1 col-xs-10 offset-xs-1 form-bg">
<h3>Страница {{forloop.counter}}</h3>
{{ formset_form|crispy}}
</div>
</div>
{% endfor %}
</form>
What I am trying to achieve is: when user enters a page, he gets a form with project name and project URL already filled in. So, he can correct them.
Below, I want to show a filled in form for every page allready created for this project and several empty forms for creating new.
What happens is all initial data is displayed correctly, but when I fill several empty forms - only first empty form is saved each time.
Here is how it was solved:
Included errors properly.
Saw that second to last form lack required field (hiddenInput)
Made changes in view so it looks like:
formset_f = modelformset_factory(ProjectPage, form=ProjectPageForm, extra=3)
formset = formset_f(queryset=ProjectPage.objects.filter(page_project__id=proj), initial =[{'page_project': proj}, {'page_project': proj}, {'page_project': proj}])
Initial values now match number of extra forms - every form got it's own foreign key.
Probably there is a better solution, but the the problem is found and solved for me!
My problem was that when I tried to render every form of the formset manually I added an unneded <form></form> html element
wrong:
{ form.management_form }}
{% for form in formset %}
<form class="form-class">
{{form.name}}
</form>
right:
{ form.management_form }}
{% for form in formset %}
<div class="form-class">
{{form.name}}
</div>
After that change my forms were recognized correctly.

uploading files from form

I have a ModelForm that I'm using to upload files with and it doesn't want to work. I had it working yesterday but I'm not sure what was done to make it stop all of a sudden.
Here's my ModelForm:
class UserForm(forms.ModelForm):
description = forms.CharField(max_length=500, widget=forms.Textarea(attrs={'cols': 80, 'rows': 5}))
class Meta:
model = UserProfile
exclude = {'user', 'description'}
Here's the Model:
def get_image_path(instance, filename):
return os.path.join('images', str(instance.id), filename)
def get_video_path(instance, filename):
return os.path.join('videos', str(instance.id), filename)
def get_randfile_path(instance, filename):
return os.path.join('randfile', str(instance.id), filename)
class UserProfile(models.Model):
user = models.OneToOneField(User)
description = models.CharField(max_length=500, blank=True, null=True)
photo = models.FileField(upload_to=get_image_path, blank=True, null=True)
video = models.FileField(upload_to=get_video_path, blank=True, null=True)
rand_file = models.FileField(upload_to=get_randfile_path, blank=True, null=True)
def photo_name(self):
return os.path.basename(self.photo.name)
def video_name(self):
return os.path.basename(self.video.name)
Here's the View:
def detail(request, user_id):
user = get_object_or_404(User, pk=user_id)
userprofile = get_object_or_404(UserProfile, user=user)
year = datetime.now().year
userform = UserForm()
delvid = Del_Video()
if request.method == 'POST':
userform = UserForm(request.POST, request.FILES, instance=user)
delvid = Del_Video(request.POST)
if userform.is_valid():
userprofile.description = request.POST.get('description', userprofile.description)
userprofile.photo = request.FILES.get('photo', userprofile.photo)
userprofile.video = request.FILES.get('video', userprofile.video)
userprofile.rand_file = request.FILES.get('rand_file', userprofile.rand_file)
userprofile.save()
else:
messages.add_message(request, messages.INFO, 'Invalid Form')
userform = UserForm()
if delvid.is_valid():
if request.POST['Delete']:
userprofile.video.delete()
else:
delvid = Del_Video()
context = {'user': user, 'year': year, 'userform': userform, 'userprofile': userprofile, 'delvid': delvid}
return render(request, 'users/detail.html', context)
And here is the form in the template:
<div class="row">
<div class="col-md-4">
<h4>Update User:</h4>
{% if userform.errors %}
<h6>{{ userform.errors }}</h6>
{% endif %}
{% if messages %}
{% for message in messages %}
<h5>{{ message }}</h5>
{% endfor %}
{% endif %}
<form action="{% url 'users:detail' user.id %}" method="post" enctype="multipart/form-data" data-ajax="false">
{% csrf_token %}
{{ userform.as_p }}
<input type="submit" value="Update">
</form>
</div>
</div>

Categories