I am building a PollApp and I am stuck on a Problem..
I build a poll add feature for add images in the poll . BUT images are not adding in the Poll.
When i select images in field then save it redirect to the same page and saying "This field is required".
models.py
class ImageChoice(models.Model):
image_poll = models.ForeignKey(ImagePoll, on_delete=models.CASCADE)
choice_image = models.FileField()
views.py
def polls_add(request):
if request.method == 'POST':
form = ImagePollAddForm(request.POST)
if form.is_valid():
poll = form.save(commit=False)
poll.owner = request.user
poll.save()
new_choice1 = ImageChoice(poll=poll, image=form.cleaned_data['choice1']).save()
context = {
'form': form,
}
return render(request, 'add_poll.html', context)
forms.py
class ImagePollAddForm(forms.ModelForm):
choice1 = forms.FileField()
class Meta:
model = ImagePoll
fields = ['choice1']
When i try to upload images in each field then click to save then it is not uploading.
I also tried by adding request.FILES in form = ImagePollAddForm(request.POST) BUT it is showing ImageChoice() got an unexpected keyword argument 'poll' .
You use invalid field name, your model has image_poll field but not poll. And your model does not have image field but choice_image
ImageChoice(image_poll=poll, choice_image=form.cleaned_data['choice1']).save()
Related
I am doing an online classroom project in Django where I created a model named create_course which is accessible by teachers. Now I am trying to design this as the teacher who creates a class only he can see this after login another teacher shouldn't see his classes and how to add students into that particular class I created
the course model
class course(models.Model):
course_name = models.CharField(max_length=200)
course_id = models.CharField(max_length=10)
course_sec = models.IntegerField()
classroom_id = models.CharField(max_length=50,unique=True)
created_by = models.ForeignKey(User,on_delete=models.CASCADE)
here if I use "the created_by" field in forms it appears to be a drop-down menu where every user is showing but I want to automatically save the user who creates the object
views.py
def teacher_view(request, *args, **kwargs):
form = add_course(request.POST or None)
context = {}
if form.is_valid():
form.save()
return HttpResponse("Class Created Sucessfully")
context['add_courses'] = form
return render(request, 'teacherview.html', context)
forms.py
from django import forms
from .models import course
class add_course(forms.ModelForm):
class Meta:
model = course
fields = ('course_name', 'course_id', 'course_sec', 'classroom_id')
You can inject the logged in user to the .created_by of the .instance in the form, so:
from django.contrib.auth.decorators import login_required
from django.shortcuts import redirect
#login_required
def teacher_view(request, *args, **kwargs):
if request.method == 'POST':
form = add_course(request.POST, request.FILES)
if form.is_valid():
form.instance.created_by = request.user
form.save()
return redirect('name-of-some-view')
else:
form = add_course()
return render(request, 'teacherview.html', {'add_courses': form})
Note: It is normally better to make use of the settings.AUTH_USER_MODEL [Django-doc] to refer to the user model, than to use the User model [Django-doc] directly. For more information you can see the referencing the User model section of the documentation.
Note: You can limit views to a view to authenticated users with the
#login_required decorator [Django-doc].
Note: Usually a Form or a ModelForm ends with a …Form suffix,
to avoid collisions with the name of the model, and to make it clear that we are
working with a form. Therefore it might be better to use CourseForm instead of
add_course.
Note: Models in Django are written in PascalCase, not snake_case,
so you might want to rename the model from course to Course.
Note: In case of a successful POST request, you should make a redirect
[Django-doc]
to implement the Post/Redirect/Get pattern [wiki].
This avoids that you make the same POST request when the user refreshes the
browser.
In your view use commit=False to stop the form from saving until you add the created_by field.
def teacher_view(request, *args, **kwargs):
form = add_course(request.POST or None)
context = {}
if form.is_valid():
course = form.save(commit=False)
course.created_by = request.user
course.save()
return HttpResponse("Class Created Sucessfully")
context['add_courses'] = form
return render(request, 'teacherview.html', context)
I am building blogsite where authenticated user can add post. The form has three fields including 'user' field (which shows all the user list with a drop down option). The problem is authenticated user can also see other user name.
I have tried two solution
Exclude this field when rendering in template or
whatever the username is chosen the post post will be saved by the name of authenticated user
but the solution I want
'user' field will only show the name of the authenticated user and that will be submitted with title and description
class BlogForm(forms.ModelForm):
class Meta:
model = Blog
fields = '__all__'
view function
if fm.is_valid():
us = fm.cleaned_data['user']
ti = fm.cleaned_data['title']
ds = fm.cleaned_data['desc']
post = Blog(user=us, title=ti, desc=ds)
messages.success(request, 'Blog Created')
post.save()
{% csrf_token %}
{{form.user.label}}{{form.user}}<br><br>
{{form.title.label}}{{form.title}}
{{form.desc.label}} {{form.desc}}
in model form only include "title" and "desc" field so template not render "user" field, we can set user in views.py via dynamically
class BlogForm(forms.ModelForm):
class Meta:
model = Blog
fields = ('title','desc',)
#views.py here we can set user via dynamically user=request.user
if fm.is_valid():
ti = fm.cleaned_data['title']
ds = fm.cleaned_data['desc']
post = Blog(user=request.user, title=ti, desc=ds)
messages.success(request, 'Blog Created')
post.save()
In your Form class
def __init__(self, *args, **kwargs):
super(YourForm, self).__init__(*args, **kwargs)
self.fields['user'].disabled = True
initialise your form:
data = {'user': request.user}
fm = YourForm(initial=data)
next:
if fm.is_valid():
us = fm.cleaned_data['user']
ti = fm.cleaned_data['title']
ds = fm.cleaned_data['desc']
post = Blog(user=us, title=ti, desc=ds)
messages.success(request, 'Blog Created')
post.save()
Your form will get the user from request, so you do not have any dependency for user from form.
For my django project, I am using a custom user model, and this works just fine. I also have a page that lets a user edit their own profile, and this also works correctly.
I just added an ImageField field to my user model for an avatar image. However I am having trouble with letting the user update the image themselves. It works fine in the admin interface, but not my user form.
Here is the relevant part models.py
# Generates the path for uploaded avatar images
def upload_avatar_path(instance, filename):
ext = filename.split('.')[-1]
return 'user/{0}/avatar.{1}'.format(instance.username, ext)
# Users
class User(AbstractBaseUser):
"""
Custom user model for amvl.
"""
username = models.CharField(
unique=True,
max_length=50,
)
avatar = models.ImageField(
upload_to=upload_avatar_path,
default='user/default.png'
)
bio = models.TextField()
class ProfileUpdateForm(forms.ModelForm):
class Meta:
model = User
fields = ['avatar', 'bio']
As you can see, the form am using for a user to edit their profile is a ModelForm.
Here is the views.py
def profile_edit(request, profile):
# Check if logged in user is the same as the profile edit page
if request.user.username == profile:
profile = User.objects.get(username=request.user.username)
# If this is a form submission
if request.method == 'POST':
form = ProfileUpdateForm(request.POST, request.FILES)
if form.is_valid():
try:
update = ProfileUpdateForm(
request.POST,
request.FILES,
instance=profile,
)
update.save()
return HttpResponse("UPDATED")
except:
return HttpResponse('FAILED')
else:
form = ProfileUpdateForm(instance=profile)
context = {
'form': form,
}
return render(request, 'user/profile_edit.html', context)
else:
return HttpResponse("NOT ALLOWED")
Everything works correctly here, except for updating the avatar field. Interestingly, when I submit the form "UPDATED" is returned, indicating that it worked. But when I check, the avatar image is not updated, even if other fields are.
Other examples I've seen seem to suggest that I need to use request.FILES['avatar'] to save the record, but when I do, it returns "FAILED".
When I remove the try and except statements to view the debug info, its shows a MultiValueDictKeyError at /user/admin/edit/, "'avatar'". (When I use request.FILES['avatar'])
According to the Django documentation for file uploads, and since you’re working with a ModelForm, you should use:
if request.method == 'POST':
form = ProfileUpdateForm(request.POST, request.FILES)
if form.is_valid():
form.save()
return HttpResponseRedirect('/success/url/')
In case you’re not using a ModelForm…
…but you’re building one of your own, use:
if request.method == 'POST':
form = ProfileUpdateForm(request.POST, request.FILES)
if form.is_valid():
instance = User(avatar=request.FILES['avatar'])
instance.save()
return HttpResponseRedirect('/success/url/')
Now, if it still raises a MultiValueDictKeyError (I’m actually not sure of which to give to the key), try catching the exception to get the keys of request.FILES:
try:
instance = User(avatar=request.FILES['avatar'])
except MultiValueDictKeyError:
raise KeyError('Keys for `request.FILES` are {}'.format(request.FILES.keys()))
I've figured it out. It had nothing to do with my python code or Django, my HTML form was missing it's enctype="multipart/form-data" attribute.
I am on chapter 9 of Tango With Django:
http://www.tangowithdjango.com/book17/chapters/login.html#demo
Whenever I create a user, I get an error page on my browser as shown below:
IntegrityError at /rango/register/
rango_userprofile.user_id may not be NULL
Request Method: POST
Request URL: http://127.0.0.1:8000/rango/register/
Django Version: 1.7.1
Exception Type: IntegrityError
Exception Value:
rango_userprofile.user_id may not be NULL
Exception Location: C:\Python27\lib\site-packages\django\db\backends\sqlite3\base.py in execute, line 485
Python Executable: C:\Python27\python.exe
Python Version: 2.7.8
Python Path:
['C:\\Users\\Paul.Zovighian\\desktop\\tango\\tango_with_django_project',
'C:\\Python27\\lib\\site-packages\\pandas-0.14.1-py2.7-win32.egg',
'C:\\Python27\\lib\\site-packages\\pytz-2014.7-py2.7.egg',
'C:\\Windows\\system32\\python27.zip',
'C:\\Python27\\DLLs',
'C:\\Python27\\lib',
'C:\\Python27\\lib\\plat-win',
'C:\\Python27\\lib\\lib-tk',
'C:\\Python27',
'C:\\Python27\\lib\\site-packages',
'C:\\Python27\\lib\\site-packages\\win32',
'C:\\Python27\\lib\\site-packages\\win32\\lib',
'C:\\Python27\\lib\\site-packages\\Pythonwin']
Server time: Fri, 12 Dec 2014 16:50:14 +0000
I can see that there is an integrity error, but I am not sure why this is the message I get. If I try registering that user again, it won't let me because it says that that username already exists. So it's like, working for registering new users, but it just doesn't acknowledge the successful registration.
Here is my code:
models.py
from django.db import models
from django.template.defaultfilters import slugify
from django.contrib.auth.models import User
class Category(models.Model):
name = models.CharField(max_length=128, unique=True)
views = models.IntegerField(default=0)
likes = models.IntegerField(default=0)
slug = models.SlugField(unique=True)
def save(self, *args, **kwargs):
self.slug = slugify(self.name)
super(Category, self).save(*args, **kwargs)
def __unicode__(self):
return self.name
class Page(models.Model):
category = models.ForeignKey(Category)
title = models.CharField(max_length=128)
url = models.URLField()
views = models.IntegerField(default=0)
def __unicode__(self):
return self.title
class UserProfile(models.Model):
# This line is required. Links UserProfile to a User model instance.
user = models.OneToOneField(User)
# The additional attributes we wish to include.
website = models.URLField(blank=True)
picture = models.ImageField(upload_to='profile_images', blank=True)
# Override the __unicode__() method to return out something meaningful!
def __unicode__(self):
return self.user.username
views.py
from django.http import HttpResponse
from django.shortcuts import render
from rango.models import Category
from rango.models import Page
from rango.forms import CategoryForm
from rango.forms import PageForm
from rango.forms import UserForm, UserProfileForm
def index(request):
# Query the database for a list of ALL categories currently stored.
# Order the categories by no. likes in descending order.
# Retrieve the top 5 only - or all if less than 5.
# Place the list in our context_dict and dictionary which will be passed to the template engine.
category_list = Category.objects.order_by('-likes')[:5]
page_list = Page.objects.order_by('-views')[:5]
context_dict = {'categories': category_list, 'pages': page_list}
# Render the response and send it back!
return render(request, 'rango/index.html', context_dict)
def about(request):
context_dict = {'italicmessage': "I am italicised font from the context"}
return render(request, 'rango/about.html', context_dict)
def category(request, category_name_slug):
# Create a context dictionary which we can pass to the template rendering engine
context_dict = {}
try:
# Can we find a category name slug with the given name?
# If we can't, the .get() method raises a DoesNotExist exception.
# So the .get() method returns one model instance or raises an exception.
category = Category.objects.get(slug=category_name_slug)
context_dict['category_name'] = category.name
# Retrieve all the associated pages.
# Note that filter returns >= 1 model instance.
pages = Page.objects.filter(category=category)
# Adds our results list to the template context under name pages.
context_dict['pages'] = pages
# We also add the category object from the database to the context dictionary.
# We'll use this in the template to verify that the category exists.
context_dict['category'] = category
context_dict['category_name_slug'] = category_name_slug
except Category.DoesNotExist:
# We get here if we didn't find the specified category.
# Don't do anything - the template displayes the "no category message for us."
pass
# Go render the response and return it to the client.
return render(request, 'rango/category.html', context_dict)
def add_category(request):
# A HTTP POST?
if request.method == 'POST':
form = CategoryForm(request.POST)
# Have we been provided with a valid form?
if form.is_valid():
# save the new category to the database.
form.save(commit=True)
# Now call the index() view.
# The user will be shown the homepage.
return index(request)
else:
# The supplied form contained errors - just print them to the terminal.
print form.errors
else:
# If the request was not a POST, display the form to enter details.
form = CategoryForm()
# Bad form (or form details), no form supplied...
# Render the form with error messages (if any).
return render(request, 'rango/add_category.html', {'form': form})
def add_page(request, category_name_slug):
try:
cat = Category.objects.get(slug=category_name_slug)
except Category.DoesNotExist:
cat = None
if request.method == 'POST':
form = PageForm(request.POST)
if form.is_valid():
if cat:
page = form.save(commit=False)
page.category = cat
page.views = 0
page.save()
return category(request, category_name_slug)
else:
form = PageForm()
context_dict = {'form': form, 'category': cat, 'category_name_slug': category_name_slug}
return render(request, 'rango/add_page.html', context_dict)
def register(request):
# A boolean value for telling the template whether the registration was successful.
# Set to False initially. Code changes value to True when registration succeeds.
registered = False
# If it's a HTTP POST, we're interested in processing form data.
if request.method == 'POST':
# Attempt to grab information from the raw form information
# Note that we make use of both UserForm and UserProfileForm.
user_form = UserForm(data=request.POST)
profile_form = UserProfileForm(data=request.POST)
# If the two forms are valid...
if user_form.is_valid() and profile_form.is_valid():
# Save the user's form data to the database.
user = user_form.save()
# Now we hash the password with the set_password method.
# Once hashed, we can update the user object.
user.set_password(user.password)
user.save()
# Now we sort out the UserProfile instance.
# Since we need to set the user attribute ourselves, we set commit=False
# This delays saving the model until we're ready to avoid integrity problems.
profile = profile_form.save()
profile.user = user
# Did the user provide a profile picture?
# If so, we need to get it from the input form and put it in the UserProfile model.
if 'picture' in request.FILES:
profile.picture = request.FILES['picture']
# Now we save the UserProfile model instance.
profile.save()
# Update our variables to tell the template registration was successful.
registered = True
# Invalid form or forms - mistakes or something else?
# Print problems to the terminal.
# They'll also be shown to the user.
else:
print user_form.errors, profile_form.errors
# Not a HTTP POST, so we render our form using two ModuleForm instances.
# These forms will be blank, ready for user input.
else:
user_form = UserForm()
profile_form = UserProfileForm()
# Render the template depending on the context.
return render(request,'rango/register.html', {'user_form': user_form, 'profile_form': profile_form, 'registered': registered} )
forms.py
from django import forms
from django.contrib.auth.models import User
from rango.models import Page, Category, UserProfile
class CategoryForm(forms.ModelForm):
name = forms.CharField(max_length=128, help_text="Please enter the category name.")
views = forms.IntegerField(widget=forms.HiddenInput(), initial=0)
likes = forms.IntegerField(widget=forms.HiddenInput(), initial=0)
slug = forms.CharField(widget=forms.HiddenInput(), required=False)
# An inline class to provide additional information on the form.
class Meta:
# Provide an association between the ModelForm and a model
model = Category
fields = ('name',)
class PageForm(forms.ModelForm):
title = forms.CharField(max_length=128, help_text="Please enter the title of the page.")
url = forms.URLField(max_length=200, help_text="Please enter the URL of the page.")
views = forms.IntegerField(widget=forms.HiddenInput(), initial=0)
class Meta:
model = Page
exclude = ('category',)
# or specify the fields to include (.i.e. not include the category field)
#fields = ('title', 'url', 'views')
def clean(self):
cleaned_data = self.cleaned_data
url = cleaned_data.get('url')
# If url is not empty and doesn't start with 'http://', prepend 'http://'.
if url and not url.startswith('http://'):
url = 'http://' + url
cleaned_data['url'] = url
return cleaned_data
class UserForm(forms.ModelForm):
password = forms.CharField(widget=forms.PasswordInput())
class Meta:
model = User
fields = ('username','email','password')
class UserProfileForm(forms.ModelForm):
class Meta:
model = UserProfile
fields = ('website', 'picture')
I think I have all relevant files included here, but let me know if I could provide any other info to clear things up!
Thanks in advance
Your comment says "Since we need to set the user attribute ourselves, we set commit=False", but you don't actually do that. It should be:
profile = profile_form.save(commit=False)
In future, please cut your code down to the minimum that exhibits your problem: the error was occurring on register, you didn't need to show all the code relating to categories.
I implemented some ImageFields in my model and installed PIL (not the cleanest install). Things seem to work as I get an upload button in the admin and when I call the .url property in the view I get the string with the filename + its upload property.
The problem is that the file is not there, apparently it doesnt get uploaded once I save the model.
Any idea?
Thanks
Here's a sample of my code situation
models.py
class My_Model(models.Model):
[...]
image = models.ImageField(upload_to = 'images/my_models/main')
view.py
'image': query.my_model.image.url
result:
static/images/my_models/main/theimage.png
Make sure that you're binding request.FILES to the form when POSTing, and that the form is declared as multi-part in the template
Here's the view from one of my applications:
#login_required
def submit(request):
if request.method == 'POST':
(Photo.objects.count()+1, request.FILES['photo'].name.split(".")[1]), request.FILES['photo'])}
form = PhotoForm(request.POST, request.FILES)
if form.is_valid():
new = Photo(photo=request.FILES['photo'], name=request.POST['name'])
new.save()
return HttpResponseRedirect('/') # Redirect after POST
else:
form = PhotoForm()
return render_to_response('app/submit.html', {'form': form}, context_instance=RequestContext(request))
and the PhotoForm class:
class PhotoForm(forms.ModelForm):
class Meta:
model = Photo
fields = ('name', 'photo')