The dropdown list appears correctly in the html, However I am unable to figure out why I run into the same error time after time when I try to submit / .
"Select a valid choice. That choice is not one of the available choices."
the problem context
I have two models defined in Django. One CourseModel database to hold all the offered courses and one registration database to link a course to a user.
models.py
from django.db import models
# Create your models here.
class CourseModel(models.Model):
course = models.CharField(max_length=100)
date = models.DateField(max_length=100)
time = models.TimeField()
location = models.CharField(max_length=100)
datetime = models.DateTimeField()
class RegistrationModel(models.Model):
name = models.CharField(max_length=100)
adress = models.CharField(max_length=100)
city = models.CharField(max_length=100)
email = models.EmailField(max_length=100)
course = models.ForeignKey('self', on_delete=models.CASCADE)
def __str__(self):
return self.name
I use modelForm to create a registration form, where the user can subscribe for a course from a dropdown list.
forms.py
from django.forms import ModelForm, RegexField
from home.models import RegistrationModel, CourseModel
from django import forms
import datetime
class RegistrationForm(ModelForm):
def __init__(self, *args, **kwargs):
super(RegistrationForm, self).__init__(*args, **kwargs)
self.fields['course'].queryset = CourseModel.objects.exclude(date__lt=datetime.datetime.today()).values_list('datetime', flat=True)
self.fields['course'].empty_label = None
class Meta:
model = RegistrationModel
fields = '__all__'
views.py
from django.shortcuts import render, redirect
from home.forms import RegistrationForm
from .models import CourseModel
import datetime
def home(request):
return render(request, 'home/home.html')
def registration(request):
if request.method == 'POST':
form = RegistrationForm(request.POST)
crs = request.POST.get('course')
print(crs)
if form.is_valid():
cleanform = form.save(commit=False)
cleanform.course = crs
cleanform.save()
return redirect('home')
else:
form = RegistrationForm()
return render(request, 'home/registration.html', {'form': form})
In the RegistrationForm's __init__() method, your self.fields['course'].queryset = ...values_list('datetime', flat=True) returns datetime instances. See values_list() docs.
I believe this may cause the issue. I guess the queryset should return CourseModel instances, based on the Django docs:
ForeignKey is represented by django.forms.ModelChoiceField, which is a ChoiceField whose choices are a model QuerySet.
Also, your RegistrationModel.course field has a foreign key to 'self' instead of the CourseModel. Not sure if that is what you want.
Other examples of setting the field queryset can be found here.
Related
So i have a Car model. And every car is submitted is assigned to a user. Also every user has his own dashboard where they can submit cars (Only for logged in users).
from django.db import models
from django.contrib.auth.models import User
class Car(models.Model):
user = models.ForeignKey(User,on_delete=models.CASCADE,null=True)
model_car= models.CharField(max_length=200)
description = models.TextField()
car_image = models.ImageField(null=True, blank=True)
date_created = models.DateTimeField(auto_now_add=True)
This is my forms.py where i create cars. And then i render this form to the frontend.
from django import forms
from django.forms import ModelForm
from tasks.models import Car
class CreateCarForm(ModelForm):
class Meta:
model=Car
fields='__all__'
exclude = ('user',)
Views.py
def create_car(request):
form = CreateCarForm()
if request.method=="POST":
form = CreateCarForm(request.POST,request.FILES)
if form.is_valid():
form.save()
messages.success(request,'Car was Created')
return redirect('create_car')
context={'form':form}
return render(request, 'dashboard/create_car.html',context)
Now it just creates a car instance, but with no selected user. What i would like to do is to create this Car instance, but in the user field, to auto assign the current logged-in user username.
How can i achieve this?
You can set the .user instance of the Car instance wrapped in the CreateCarForm:
from django.contrib.auth.decorators import login_required
#login_required
def create_car(request):
form = CreateCarForm()
if request.method=='POST':
form = CreateCarForm(request.POST,request.FILES)
if form.is_valid():
form.instance.user = request.user
form.save()
messages.success(request,'Car was Created')
return redirect('create_car')
context={'form':form}
return render(request, 'dashboard/create_car.html', context)
This Is models.py
from django.db import models
class RegisterForm(models.Model):
fname = models.CharField(max_length=100)
lname = models.CharField(max_length=100)
pno = models.CharField(max_length=100)
email = models.EmailField(max_length=200)
pass1 = models.CharField(max_length=100)
pass2 = models.CharField(max_length=100)
This is my Views.py
from django.shortcuts import render
from .models import RegisterForm
# Create your views here.
def registerView(request):
if request.method=='POST':
fm = RegisterForm(request.POST)
if fm.is_valid():
fname = fm.cleaned_data['fname']
lname = fm.cleaned_data['lanme']
pno = fm.cleaned_data['pno']
email = fm.cleaned_data['email']
pass1 = fm.cleaned_data['pass1']
pass2 = fm.cleaned_data['pass2']
reg = RegisterForm.save(fname = fname,lname=lname,pno=pno,email=email,pass1=pass1,pass2=pass2)
reg.save()
fm = RegisterForm()
else:
fm = RegisterForm()
return render(request, 'register.html', {})
Request Method: POST
Request URL: http://127.0.0.1:8000/
Django Version: 3.2
Exception Type: AttributeError
Exception Value: 'RegisterForm' object has no attribute 'is_valid'
Exception Location: H:\Django\authetication\users\views.py, line 7, in registerView
You created a model, not a form.
Now you need to create forms.py in-app
from django import forms
from .models import Profile
class ProfileForm(forms.ModelForm):
class Meta:
model = Profile
fields = '__all__'
You can use all for all fields in the model but you can put only chosen fields in the form via tuple ('field_name', 'field_name')
Your RegisterForm is a model, not a model form, hence RegisterForm(request.POST) makes no sense, and your RegisterForm has no .is_valid(…) method. A model deals with storing data in the database, whereas a form will receive, validate and clean data.
It looks like you want to define a profile, so you can implement a Profile model:
# app_name/models.py
from django.db import models
class Profile(models.Model):
fname = models.CharField(max_length=100)
lname = models.CharField(max_length=100)
pno = models.CharField(max_length=100)
email = models.EmailField(max_length=200)
pass1 = models.CharField(max_length=100)
pass2 = models.CharField(max_length=100)
and then define a ModelForm based on that model:
# app_name/forms.py
from django import forms
class ProfileForm(forms.ModelForm):
class Meta:
model = Profile
fields = '__all__'
Then in the view you can work with:
from django.shortcuts import render
from .forms import ProfileForm
def registerView(request):
if request.method == 'POST':
form = ProfileForm(request.POST)
if form.is_valid():
form.save()
return redirect('name-of-some-view')
else:
form = ProfileForm()
return render(request, 'register.html', {'form': form})
You however should probably make modifications to your model: only use one field where you store the password, and likely the password should be hashed to prevent a data leak in case data of your database got stolen. Django already has a user model, and thre documentation has a section named Customizing authentication in Django. That can help you define a model for a user, and register that user.
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.
I am new to Django and using this project to learn it. I am able to save the Journal record but the many to many relationship does not work.
This 'create' view displays the correct form including the multi-select box with all of the cryptos listed (from Crypto model). When submitting the form the many-to-many records do not save but the Journal saves fine.
I have found a bunch of different answers to this, some are for python 2.7, but this is the simplest method based on the [Django documentation][1]. Any help is greatly appreciated.
Also, the relationship works fine in the Admin section, so I am thinking it has something to do with the Forms and/or the View & saving.
models.py
from django.db import models
from crypto.models import Crypto as CryptoModel
class Journal(models.Model):
title = models.CharField(max_length=200, help_text='Journal Title', blank=False, null=False)
content = models.TextField(max_length=2000, help_text='Journal Content (HTML OK)', blank=False, null=False)
crypto_id = models.ManyToManyField(CryptoModel, blank=True)
created = models.DateTimeField(help_text='Created', auto_now_add=True, null=True)
def __str__(self):
return self.title ## String for representing the Model object, usually name field or title
forms.py
from django.forms import ModelForm, ModelMultipleChoiceField, widgets
from journal.models import Journal as JournalModel
from crypto.models import Crypto as CryptoModel
class JournalForm(ModelForm):
# select multiple items box
cryptos = ModelMultipleChoiceField(widget=widgets.SelectMultiple(attrs={'size': 30}), queryset=CryptoModel.objects.all())
class Meta:
model = JournalModel
fields = [
"title",
"content",
]
labels = {
'title': 'Journal Title',
}
required = [
"title", # same as model
"content", # same as model
]
views.py
from journal.forms import JournalForm
from django.utils import timezone
from django.http import HttpResponse, HttpResponseRedirect
from django.shortcuts import render, redirect, get_object_or_404
from journal.models import Journal as JournalModel
def Create(request):
if request.method == "POST":
form = JournalForm(request.POST) # form instance
context = {'form': form} # if errors, keep the form data on next page load
journal = form.save(commit=False) # False needed for many-to-many
journal.title = form.cleaned_data["title"]
journal.content = form.cleaned_data["content"]
journal.created = timezone.now()
journal.save() # save the form journal data, now we have a PK
form.save_m2m() # save the 'form' using ManytoMany method
return HttpResponseRedirect('/journal/')
form = JournalForm()
context = {'form': form}
return render(request, 'journal/create.html', context)
models.py 2
from django.db import models
from crypto.models import Crypto
class Journal(models.Model):
title = models.CharField(max_length=200, help_text='Journal Title', blank=False, null=False)
content = models.TextField(max_length=2000, help_text='Journal Content (HTML OK)', blank=False, null=False)
crypto_id = models.ManyToManyField(Crypto, blank=True)
created = models.DateTimeField(help_text='Created', auto_now_add=True, null=True)
def __str__(self):
return self.title ## String for representing the Model object, usually name field or title
forms.py 2
from django.forms import ModelForm, ModelMultipleChoiceField, widgets
from journal.models import Journal
from crypto.models import Crypto
class JournalForm(ModelForm):
# select multiple items box
cryptos = ModelMultipleChoiceField(widget=widgets.SelectMultiple(attrs={'size': 30}), queryset=Crypto.objects.all())
class Meta:
model = JournalModel
fields = [
"title",
"content",
"cryptos",
]
views.py 2
from journal.forms import JournalForm
from django.utils import timezone
from django.http import HttpResponse, HttpResponseRedirect
from django.shortcuts import render, redirect, get_object_or_404
from journal.models import Journal
def Create(request):
if request.method == "POST":
form = JournalForm(request.POST) # form instance
context = {'form': form} # if errors, keep the form data on next page load
journal = form.save(commit=False) # False needed for many-to-many
journal.created = timezone.now()
journal.save() # save the form journal data, now we have a PK
journal.crypto_id.set(form.cleaned_data.get("cryptos")) # must be after "save"
form.save_m2m() # save the 'form' using ManytoMany method
return HttpResponseRedirect('/journal/')
form = JournalForm()
context = {'form': form}
return render(request, 'journal/create.html', context)
hope this solve your problem just but this line after save your journal instance
journal.crypto_id.set(form.cleaned_data.get("cryptos"))
You've called your model and form fields different things; Django can't know they relate to the same field. The form name - crypos - is the correct one, you should rename your model field to that.
Also, you haven't specified the field in the fields list, so Django won't even try to set it on the model.
Note that in your view you don't need to set title or content, that's what form.save does for you already.
Thank you abdullah, adding "journal.crypto_id.set(form.cleaned_data.get("cryptos"))" to the VIEW fixed the issue.
An additional note is that this must be places after the 'journal' form is saved but before the many to many is saved.
I updated the "models.py 2", "forms.py 2" and "views.py 2" section above. This is the working code.
you are always welcome.
yes but it after journal.save().
and set don't need to call save() from form.
I have looked at a lot of different places but none of their solutions work. This is most likely to do them being for older versions of django or my own stupidity. So I am making a blog type of app that for some reason is called reviews instead of blog... anyway I need to automatically fill up an author field with the username of the logged in user. Here is my models.py:
from django.db import models
from django.contrib.auth.models import User
#vars
# Create your models here.
class reviews(models.Model):
title = models.CharField(max_length=100)
author = models.ForeignKey(User, on_delete=models.PROTECT,)
body = models.TextField()
date = models.DateTimeField(auto_now_add=True, blank=True)
and forms.py:
from django import forms
from django.forms import ModelForm
from .models import reviews
from django.contrib.auth.decorators import login_required
class CreatePost_form(ModelForm):
class Meta:
model = reviews
exclude = ['author']
fields = ['title', 'body',]
and views:
from django.shortcuts import render, render_to_response
from .forms import CreatePost_form
from django.http import HttpResponseRedirect
# Create your views here.
def reviewlist(request):
return render
def index(request, ):
return render(request, template_name="index.html")
def CreatePost(request):
form = CreatePost_form(request.POST)
if form.is_valid():
form.save()
return HttpResponseRedirect('/reviews/succesfulpost')
return render(request, "reviews/CreatePostTemplate.html", {'form':form})
def succesfulpost(request):
return render(request, "reviews/succesfulpost.html")
def CreatePost(request):
form = CreatePost_form(request.POST)
if form.is_valid():
form.save(commit=False)
form.author = request.user
form.save()
return HttpResponseRedirect('/reviews/succesfulpost')
As simple as that. Rather than actually saving and committing the data, you simply save without committing then you're able to change the value of the excluded field.
I am trying to make a user registration form in django.
I browsed through many links but I am still confused. I am making some sill mistake please point it out.
here is my code:
models.py
from django.db import models
from django.db.models.signals import post_save
from django.contrib.auth.models import User
class UserProfile(models.Model):
mobile = models.CharField(max_length = 20, null=False)
address = models.CharField(max_length = 200)
user = models.OneToOneField(User, unique=True)
def create_user_profile(sender, instance, created, **kwargs):
if created:
UserProfile.objects.create(user=instance)
post_save.connect(create_user_profile, sender=User)
forms.py
from django import forms
from django.contrib.auth.models import User
from django.contrib.auth.forms import UserCreationForm
class CustomerRegistrationForm(UserCreationForm):
mobile = forms.CharField(max_length = 20)
address = forms.CharField(max_length = 200)
class Meta:
model = User
fields = ('username','email','mobile','address','password1','password2')
view.py
from django.shortcuts import render_to_response
from django.http import HttpResponseRedirect
from django.template import RequestContext
from django.core.context_processors import csrf
from neededform.forms import CustomerRegistrationForm
def register(request):
print "I am in register function"
if request.method == 'POST':
if request.method == 'POST':
form = CustomerRegistrationForm(request.POST)
if form.is_valid():
f = form.save()
return HttpResponseRedirect('/registered/')
else:
args = {}
args.update(csrf(request))
args['form'] = CustomerRegistrationForm()
return render_to_response('User_Registration.html', args ,context_instance = RequestContext(request))
what I am thinking is that when I do a form.save() in views.py, django should create the user in auth_user table and must insert the values (i.e mobile and address ) in the UserProfile table also.
but what happening is that it is inserting data in auth_user table correctly but in the UserProfile table only id and user_id coloumns are filled, mobile and address both remains empty.
What am I doing wrong ? What else must be done ?
Thank you.
Take a look at the following:
def create_user_profile(sender, instance, created, **kwargs):
if created:
UserProfile.objects.create(user=instance)
You create a UserProfile object which only has its user attribute set!
I don't think that using signal is the best approach to your problem since it's not easy to pass the mobile and address from your form to the Profile creation point. Instead you can override the save() method of your CustomerRegistrationForm where you'd first save the user and then create the profile. Something like this:
class CustomerRegistrationForm(UserCreationForm):
# rest code ommited
def save(self, commit=True):
user = super(CustomerRegistrationForm, self).save()
p = UserProfile.objects.get_or_create(user=user )
p[0].mobile = self.cleaned_data['mobile']
p[0].address = self.cleaned_data['address']
p[0].save()
return user