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()
`
Related
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.
I want to update user info with UserChangeForm and things go pretty well except for the ManyToManyField. When I render the page I can see that all user informations are displayed in correct order of each field like user's username will be in the username field but it's blank in manytomanyfield.
#model.py
class Department(models.Model):
name = models.CharField(max_length=100)
class CustomUser(AbstractUser):
username = None
email = models.EmailField(_('Email Address'), unique=True)
department = models.ManyToManyField(Department)
# some other fields
# forms.py
class EditUserForm(UserChangeForm):
class Meta:
model = CustomUser
fields = ['email', 'department', ..]
widgets = {'department': forms.CheckboxSelectMultiple()}
# view.py
def home(request):
template_name = "app/home.html"
edit_form = EditUserForm(instance=request.user)
if request.method == "POST":
edit_form = EditUserForm(request.POST, instance=request.user)
if edit_form.is_valid():
edit_form.save()
return JsonResponse({'success': True}, status=200)
else:
return JsonResponse({'error': edit_form.errors}, status=400)
return render(request, template_name, {'edit_form': edit_form})
# template
<form action="{% url 'home' %}" method="POST">
<div class="row">
{{edit_form.email}}
{{edit_form.first_name}}
{% for department in edit_form.department %}
<h6 id="checkbox">{{department.tag}} {{department.choice_label}}</h6>
{% endfor %}
</div>
</form>
here is the picture
As you can see the names and email are displaying inside the form field but why all checkboxes are empty? (Checkbox fields are department)
If you just want to render the field you don't need a for loop. You can just use {{edit_form.department}}. In case you need to modify each input field in CheckboxSelectMultiple you should loop through edit_form.department.field.choices.
For example:
{% for choice, value in edit_form.department.field.choices %}
<input type="checkbox" name="{{choice.instance.value}}" value="{{choice.instance.pk}}" id="id_{{choice.instance.value}}">
{% endfor %}
Note that this will work only in django 3.0 and newer.
you need pass the value and the name in the input in your template
{% for value, name in edit_form.fields.department.choices %}
<input type="checkbox" name="{{name}}" value="{{value}}" id="{{name}}">
{% endfor %}
recently I encountered a rather weird problem with my Django forms. I am currently working on my todo list project. Everything works fine, except that whenever I add a new task, its title seems to be saved in database with additional square brackets and quotes around it. It looks like one-element list, but it is a string. I kinda solved it by displaying the silced version of the string from the database, but it still shows for example while editing a task. Hope anyone has some idea what might be going on?
models.py:
from django.db import models
class Task(models.Model):
title = models.CharField(max_length=35)
completed = models.BooleanField(default=False)
created_date = models.DateTimeField(auto_now_add=True)
# added_by = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.CASCADE)
author = models.CharField(max_length=50, default='')
def __str__(self):
return self.title
forms.py:
from django import forms
from .models import *
class TaskForm(forms.ModelForm):
class Meta:
model = Task
fields = '__all__'
widgets = {
'title': forms.TextInput(attrs={'class': 'new_task_text', 'placeholder': 'Add new task'}),
}
class TaskEditForm(forms.ModelForm):
class Meta:
model = Task
fields = ['title', 'completed']
widgets = {
'title': forms.TextInput(attrs={'class': 'new_task_text'}),
}
views.py:
from django.shortcuts import render, redirect
from .forms import *
from django.contrib.auth.decorators import login_required
#login_required
def list_homepage(request):
tasks = Task.objects.filter(author=request.user.username)
for task in tasks:
if "['" and "']" in task.title:
task.title = task.title[2:-2] # CharField returns a string that is looking like one-element list. Have no idea why yet.
# try using form instead of modelform.
form = TaskForm()
if request.method == 'POST':
form = TaskForm({**request.POST, **{'author': request.user.username}})
if form.is_valid():
form.save()
else:
print(form.errors)
return redirect('/list/home')
context = {
'page_title': 'Todo list',
'tasks': tasks,
'form': form,
}
return render(request, 'tasks/list.html', context)
#login_required
def update_task(request, pk):
task = Task.objects.get(id=pk)
form = TaskEditForm(instance=task)
if request.method == 'POST':
form = TaskEditForm(request.POST, instance=task)
if form.is_valid():
form.save()
return redirect('../..')
context = {
'form': form,
'page_title': 'Update task',
}
return render(request, 'tasks/update_task.html', context)
#login_required
def delete_task(request, pk):
task = Task.objects.get(id=pk)
if request.method == 'POST':
task.delete()
return redirect('/list')
context = {
'page_title': 'Delete task',
'task': task,
}
return render(request, 'tasks/delete_task.html', context)
list.html:
{% extends 'tasks/base.html' %}
{% block content %}
<div class="new-task-column">
<form method="POST", action="#"> {% csrf_token %}
{{ form.title }}
<input class="submit" type="submit", value="Create task">
</form>
</div>
<div class="task-column">
{% for task in tasks %}
<div class="item-row">
<div class="task">
{% if task.completed == True %}
<s>{{ task }} </s>
{% else %}
{{ task }}
{% endif %}
</div>
<div class="del_upd_container">
<div class="single-upd-container"><a class="edit_button" href="/list/update_task/{{ task.id }}">Update</a></div>
<div class="single-del-container"><a class="edit_button" href="/list/delete_task/{{ task.id }}">Delete</a></div>
</div>
</div>
{% endfor %}
</div>
{% endblock content %}
update_task.html:
{% extends 'tasks/base.html' %}
{% block content %}
<div class="new-task-column">
<form method="POST"> {% csrf_token %}
<span class="update-task-layout">
{{ form }}
<input class="submit" type="submit" name="Update item">
</span>
</form>
</div>
{% endblock content %}
Thank you so much for any help, I really appreciate it!
Had the same problem, solved it by using the method dict() to transform request.POST's weird type (QueryDict) into a normal dict. The rest of the code, like the save() method for example, might need to be a bit adjusted.
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.
Ive tried to submit a model class using a view function but the form didn't submitted.
This The model class inside models.py file :
class Campaign(models.Model):
username = models.OneToOneField(User, unique=True)
title = models.CharField(max_length=200)
message = models.TextField()
link = models.CharField(max_length=200)
added= models.DateTimeField(auto_now_add=True)
and this its form inside forms.py :
class CampaignForm(forms.ModelForm):
class Meta:
model = Campaign
fields=('title','message')
Ive tried to submit this form using this function at views.py :
def Campaign(request):
form = CampaignForm(request.POST or None)
if request.method == 'POST':
if form.is_valid():
submit= Campaign(username=request.user)
submit.save()
context={
'form':form,
}
return render(request, 'campaigns.html',context)
And this is the html file :
{% extends "base.html" %}
{% block content %}
<form action="" method="POST" class="">
{% csrf_token %}
{{form.as_p}}
<input type="submit">
</form>
{% endblock content %}
You have to do action="#" in your form html because some browsers can not accept empty action values.
Also you have a mistake in this part of code:
submit= Campaign(username=request.user)
submit.save()
You have to get the form values into your object, you can do it this way:
submit = form.save(commit=False)
submit.username = request.user
submit.save()
Some browsers will fail to post if the action attribute is empty, try with
<form action="." method="POST">
Notice the dot ".", since you are using the same view to display the form and process it the dot it's ok.