Django ModelForm - Get value from ManyToManyField - python

I need to get the selected value(s) of year from the PreceptorForm. I can get the internal_tel using post.internal_tel but I can't do that with year because it's a ManyToManyField. I need something like preceptor.year.add(post.year) but it gives me an error. What is the best way to do it?
models.py
class Year(models.Model):
year_number = models.IntegerField(choices=YEAR_CHOICES)
division = models.CharField(choices=DIVISION_CHOICES, max_length=1)
def getStudents(self):
results = Student.objects.filter(year=self)
return results
def __str__(self):
return "{}-{}".format(self.year_number, self.division)
class Preceptor(models.Model):
user = models.OneToOneField(settings.AUTH_USER_MODEL, on_delete = models.CASCADE)
internal_tel = models.IntegerField(blank=True)
year = models.ManyToManyField(Year,blank=True,related_name='preceptores')
def getYear(self):
results = self.year.all()
return results
def __str__(self):
return "{} {}".format(self.user.first_name, self.user.last_name)
forms.py
class PreceptorForm(ModelForm):
class Meta:
model = Preceptor
fields = '__all__'
exclude = ['user']
views.py
def register_user(request):
if request.method == "POST":
form = PreceptorForm(request.POST)
username = request.POST['username']
password = request.POST['password']
sec_pass = request.POST['sec_password']
email = request.POST['email']
first_name = request.POST['first_name']
last_name = request.POST['last_name']
if form.is_valid():
if password == sec_pass:
user = User.objects.create_user(username, email, password)
user.is_active = True
user.first_name = first_name
user.last_name = last_name
user.save()
print "form"
post = form.save(commit=False)
post.user = user
preceptor = Preceptor(user=user,internal_tel=post.internal_tel)
preceptor.save()
preceptor.year.add(post.year)
preceptor.save()
return redirect('/')
else:
form = PreceptorForm()
return render(request, 'register.html', {'form': form})
I'm having this error at preceptor.year.add(post.year):
< Preceptor: 'name' > needs to have a value for field "id" before this many-to-many relationship can be used.

Related

Create #login_required like function for used Form(Modelform). So that User can't access confidential url without login-by typing just url?

I know that I can use #login_required but it is only used when we store user in User But in my case I stored model in form So it is not working for me. Also my created user is not getting authenticated when I use user.is_authenticated So I need custom login_required decorator which can be use to stop anyone from accessing direct url (confidential URl which are only accessed when you Login).
forms.py
class usrForm(forms.ModelForm):
password = forms.CharField(initial=123)
class Meta:
model = Person
fields = ('first_name','last_name','username','email','password','position')
def __init__(self, *args, **kwargs):
super(usrForm,self).__init__(*args,**kwargs)
self.fields['position'].empty_label = "Select"
class usrChange(forms.ModelForm):
class Meta:
model = Person
fields = ('username','password')
widgets= {
'password' : forms.PasswordInput(),
}
class loginForm(forms.ModelForm):
class Meta:
model = Person
fields = ('username','password')
widgets= {
'password' : forms.PasswordInput(),
}
models.py
class Position(models.Model):
title = models.CharField(max_length=50)
def __str__(self):
return self.title
class Person(models.Model):
first_name = models.CharField(max_length=50,default='')
last_name = models.CharField(max_length=50,default='')
username = models.CharField(max_length=50,default='')
password = models.CharField(max_length=50,default='')
email = models.EmailField(max_length=50)
position = models.ForeignKey(Position, on_delete=models.CASCADE)
def __str__(self):
return self.username
views.py
def user_list(request):
context = {'user_list' : Person.objects.all()}
return render(request, "usr_list.html", context)
def user_chnged_list(request):
form = usrForm(request.POST)
if form.is_valid():
form.save()
context = {'user_list' : Person.objects.all()}
return render(request, "usr_list.html", context)
def user_form(request, id=0):
if request.method == "GET":
if id ==0:
form = usrForm(initial={'password': 123}) # register
else:
auser = Person.objects.get(pk=id)
form = usrForm(instance=auser) #update
return render(request, "usr_form.html",{'form': form})
else:
if id == 0:
form = usrForm(request.POST , initial={'password': 123}) # register
else:
auser = Person.objects.get(pk=id) #update
form = usrForm(request.POST,instance=auser)
if form.is_valid():
form.save()
return redirect('login')
def user_delete(request,id):
auser = Person.objects.get(pk=id)
auser.delete()
return redirect('list')
def user_login(request):
form = loginForm()
if request.method == 'POST':
form = loginForm(data=request.POST)
if form.is_valid():
username=form.cleaned_data.get('username')
password=form.cleaned_data.get('password')
i = Person.objects.filter(username=username,password=password).exists()
user = {'user_list' : Person.objects.filter(username=username,password=password)}
if i == True:
j = Person.objects.filter(username=username, position_id = 1).exists()
if j == True:
return redirect('list')
return render(request,"usr_wlc.html", user )
else:
messages.error(request, 'Invalid username or password!')
context = {'form':form}
return render(request,'usr_login.html',context)
def user_detail(request,id):
auser = Person.objects.get(pk=id)
form = usrChange(request.POST,instance=auser)
if form.is_valid():
form.save()
return redirect('login')
def user_logout(request):
return redirect('/')
def user_change(request,id):
auser = Person.objects.get(pk=id) #update
form = usrChange(request.POST,instance=auser)
return render(request, "usr_chnge.html",{'form': form})

Django Saving A Model With Form + Current User Data

I'm writing my first app in django and i have encountered a problem. I'm trying to make a booking system. I'm trying to save the reservation model. It works just fine while the user is logged out. But once i click submit while logged in nothing really happens. The site simply reloads. Can anyone point out what I'm doing wrong?
That's my model code:
class Profile(models.Model):
user = models.OneToOneField(User, on_delete = models.CASCADE)
name = models.CharField(max_length = 100)
surname = models.CharField(max_length = 100)
phone = models.CharField(max_length = 9)
class Reservation(models.Model):
reservationID = models.AutoField(primary_key = True)
name = models.CharField(max_length = 100)
surname = models.CharField(max_length = 100)
phone = models.CharField(max_length = 9)
email = models.EmailField()
bookIn = models.DateField('Book in date', default = timezone.now)
bookOut = models.DateField('Book out date', default = timezone.now)
roomType = models.ForeignKey(Room_type, on_delete = models.CASCADE)
My form:
class Booking(forms.ModelForm):
class Meta:
model = Reservation
fields = ('name', 'surname', 'phone', 'email', 'roomType', 'bookIn', 'bookOut',)
widgets = {
'bookIn': forms.DateInput(attrs={'class': 'datepicker'}),
'bookOut': forms.DateInput(attrs={'class': 'datepicker'})
}
And my view:
form = Booking()
if request.method == 'POST':
form = Booking(request.POST)
if form.is_valid():
if request.user.is_authenticated:
reservation = Reservation()
guest = Profile.objects.get(user=request.user)
reservation.name = guest.name
reservation.surname = guest.surname
reservation.phone = guest.phone
reservation.email = guest.user.email
reservation.bookIn = form.cleaned_data.get('bookIn')
reservation.bookOut = form.cleaned_data.get('bookOut')
reservation.roomType = form.cleaned_data.get('roomType')
reservation.save()
else:
reservation = form.save()
reservation.save()
n = reservation.pk
return redirect('bookSuccess', n)
return render(request, 'hotel/bookRoom.html', {'form' : form})
I am assuming your form is not validating for some reason, and you need to catch it to see what might be going wrong. So you can update your view like this:
form = Booking(request.POST or None)
if request.method == 'POST':
if form.is_valid():
if request.user.is_authenticated:
reservation = form.save(commit=False)
# optimized the code
guest = Profile.objects.get(user=request.user)
reservation.name = guest.name
reservation.surname = guest.surname
reservation.phone = guest.phone
reservation.email = request.user.email
reservation.save()
else:
reservation = form.save() # removed duplicate save
n = reservation.pk
return redirect('bookSuccess', n)
return render(request, 'hotel/bookRoom.html', {'form' : form})
Update
You don't need to put null true and blank true in the model fields. You can pass the user data from view to form. and if the user is authenticated then pop the fields which is not necessary for authenticated user. Like this:
class Booking(forms.ModelForm):
def __init__(self, *args, **kwargs):
user = kwargs.pop('user')
super(Booking, self).__init__(*args, **kwargs)
if user.is_authenticated:
self.fields.pop('name') # or make them required false like this: self.fields['name'].required = False
self.fields.pop('surname')
# other fields unnecessary for authenticated user
# rest of the code
And use this form in view like this:
form = Booking(request.POST or None, user=request.user)

Django - duplicate key value violates unique constraint

In my Django project i create an app to have additional information about registered users. So my model looks like this:
class UserProfile(models.Model):
class Meta:
verbose_name_plural = u'User Profile'
user = models.OneToOneField(User)
birthday = models.DateField(blank=True, null=True)
avatar = models.ImageField(upload_to='media/profile/avatar', blank=True, null=True)
name = models.CharField(blank=True, null=True, max_length=20)
surname = models.CharField(blank=True, null=True, max_length=50)
phone = models.CharField(blank=True, null=True, max_length=12)
def __unicode__(self):
return '%s' % self.user
Here is my registration form:
class RegistrationForm(ModelForm):
username = forms.CharField(label=(u'Username'))
email = forms.EmailField(label=(u'Email'))
password = forms.CharField(label=(u'Password'), widget=forms.PasswordInput(render_value=False))
password1 = forms.CharField(label=(u'Password'), widget=forms.PasswordInput(render_value=False))
class Meta:
model = UserProfile
exclude = ('user',)
fields = ('username', 'email', 'password', 'password1')
def clean_email(self):
email = self.cleaned_data['email']
try:
User.objects.get(email=email)
except User.DoesNotExist:
return email
raise forms.ValidationError("User with same email already exist, please change your email")
And here is view of my registration form:
def UserProfileRegistration(request):
if request.user.is_authenticated():
return HttpResponseRedirect('/profile/')
if request.method == 'POST':
form = RegistrationForm(request.POST)
if form.is_valid():
user = User.objects.create_user(username=form.cleaned_data['username'], email=form.cleaned_data['email'], password=form.cleaned_data['password'])
user.save()
user_profile = UserProfile(user=user)
user_profile.save()
return HttpResponseRedirect('/profile/')
else:
return render(request, 'profiles/registration.html', {'form':form})
else:
form = RegistrationForm()
context = {'form':form}
return render (request, 'profiles/registration.html', context)
In user profile i create modelform where user can fill the fields from UserProfile model:
class ExtraProfileDataForm(ModelForm):
name = forms.CharField(label=(u'Enter your name'))
surname = forms.CharField(label=(u'Enter your surname'))
phone = forms.CharField(label=(u'Enter your phone'))
birthday = forms.DateField(label=(u'Enter birthday'))
avatar = forms.ImageField(label=(u'Enter avatar'))
class Meta:
model = UserProfile
fields = ('name', 'surname', 'phone', 'birthday', 'avatar')
def __init__(self, *args, **kwargs):
super(ExtraProfileDataForm, self).__init__(*args, **kwargs)
for key in self.fields:
self.fields[key].required = False
This is the view of the model form:
#login_required
def UserFullDataForm(request):
if request.method == 'POST':
form = ExtraProfileDataForm(request.POST)
if form.is_valid():
profile_user = request.user
user_profile = UserProfile(user=profile_user)
user_profile.name = form.cleaned_data['name']
user_profile.surname = form.cleaned_data['surname']
user_profile.phone = form.cleaned_data['phone']
user_profile.birthday = form.cleaned_data['birthday']
user_profile.avatar = form.cleaned_data['avatar']
user_profile.save()
return HttpResponseRedirect('/profile/')
else:
return render(request, 'profiles/extra_profile.html', {'form':form})
else:
form = ExtraProfileDataForm()
context = {'form':form}
return render (request, 'profiles/extra_profile.html', context)
But when I fill this form I got the error:
duplicate key value violates unique constraint "profiles_userprofile_user_id_key" DETAIL: Key (user_id)=(23) already exists.
On the traceback i see that error in this line user_profile.save(). As i understand it happens because this script create new item with same id but not update it. What i have to change on my code to update existing item but not to create. Thank you.
You need to use get_or_create, which will return an existing item if it was found; otherwise create a new instance of the model.
In your user profile update view:
user_profile, created = UserProfile.objects.get_or_create(user=profile.user)
Now, instead of creating a new profile each time - you are updating if a profile for that user already exists.

Add two form fields in Django

I have two CharFields in my forms.py FirstName and LastName and a CharField FullName in my models.py file.
How do I add the two (FirstName and LastName) and store them as FullName?
I tried doing it in forms.py (not working), so the only other option is to change it after the POST request in views.py but am unsure how to alter its contents.
models.py
class UserProfile(models.Model):
FullName = models.CharField(max_length=10)
balance = models.IntegerField(default=2000)
def __unicode__(self):
return self.user.FullName
forms.py
class UserProfileForm(forms.ModelForm):
FirstName = forms.CharField()
LastName = forms.CharField()
balance = forms.IntegerField(initial=2000,help_text="")
def clean(self):
cleaned_data = self.cleaned_data
url = cleaned_data.get('url')
if url and not url.startswith('http://'):
url = 'http://' + url
cleaned_data['url'] = url
return cleaned_data
class Meta:
model = UserProfile
fields = ('FullName', 'balance')
views.py
def index(request):
context = RequestContext(request)
game_list = Game.objects.all()
context_dict = {'games': game_list}
profile_form = UserProfileForm()
if request.method == 'POST':
profile_form = UserProfileForm(data=request.POST)
context_dict = {'games': game_list, 'profile_form':profile_form}
print profile_form
if profile_form.is_valid():
profile = profile_form.save(commit=False)
profile.save()
registered = True
else:
print profile_form.errors
return render_to_response('/', context_dict, context)
Probably the easiest way is to override the save method of the form, populating the instance fullname field
class UserProfileForm(forms.ModelForm):
FirstName = forms.CharField()
LastName = forms.CharField()
balance = forms.IntegerField(initial=2000,help_text="")
def clean(self):
cleaned_data = self.cleaned_data
url = cleaned_data.get('url')
if url and not url.startswith('http://'):
url = 'http://' + url
cleaned_data['url'] = url
return cleaned_data
def save(self, commit=True):
profile = super(UserProfileForm, self).save(commit=False)
profile.set_fullname(self.cleaned_data["FirstName"], self.cleaned_data["LastName"])
if commit:
profile.save()
return profile
class Meta:
model = UserProfile
fields = ('balance')
then in the UserProfile model you will have a set_fullname method to implement that logic as you want, for example:
class UserProfile(models.Model):
# various things ...
def set_fullname(self, f_name, l_name):
self.FullName = f_name + ' ' + l_name
Also I'm ignoring the view part, because I think it is just a stub and need big improvements.

Django- display manytomanyfield form in template and post to the base

People, please help me :)
I have 2 class :
In first we can sign to the edition - name, surname, phone, mail.
In second we can display form with number edition and users who sign to sth edition.
I want display only 'publish' number edition in template.
In page we can choice edition (drop-down list /multiple), write name etc and save to this edition..
I know I write awfully, but maybe U understand..
models:
class Signup(models.Model):
name = models.CharField(max_length=30, verbose_name='Imię',)
surname = models.CharField(max_length=30, verbose_name='Nazwisko', blank=True, null=True)
phone = models.CharField(max_length=20, verbose_name='Numer telefonu', blank=True, null=True)
mail = models.EmailField(verbose_name="Email", max_length=254, blank=True, null=True)
home = models.CharField(max_length=40, verbose_name='Miejsce zamieszkania', blank=True, null=True)
nr_edition = models.ManyToManyField('Edition', verbose_name='Edycja', blank=True, null=True,)
class Meta:
verbose_name = "Uczestnik"
verbose_name_plural = "Uczestnicy"
def __unicode__(self):
return u'%s %s' % (self.name, self.surname)
class PublishedEditManager(models.Manager):
def get_query_set(self):
return super(PublishedEditManager, self).get_query_set().filter(published=True)
class Edition(models.Model):
name_edit = models.CharField('Nazwa edycji', max_length=100)
slug = models.SlugField('Odnośnik', unique=True, max_length=100)
# new_user = formset_factory(ContactForm)
published = models.BooleanField('Opublikowany', blank=True)
objects = models.Manager()
published_edition = PublishedEditManager()
class Meta:
verbose_name = "Numer edycji"
verbose_name_plural = "Numery edycji"
def __unicode__(self):
return self.name_edit
def get_absolute_url(self):
return u'%s' % self.name_edit
forms
class ContactForm(forms.Form):
name = forms.CharField()
surname = forms.CharField()
phone = forms.CharField()
mail = forms.EmailField()
nr_edition = forms.ModelMultipleChoiceField
def is_valid(self):
vf = forms.Form.is_valid(self)
for f in self.errors:
self.fields[f].widget.attrs.update({'class': 'errorlist'})
return vf
def clean(self):
cleaned_data = super(ContactForm, self).clean()
return cleaned_data
ContactFormSet = formset_factory(ContactForm)
view
def about_alfa(request):
c = {}
c['about_alfa'] = True
c['request'] = request
if request.method == 'POST': # If the form has been submitted...
form = ContactForm(request.POST, request.FILES) # A form bound to the POST data
ContactFormSet = formset_factory(ContactForm)
if form.is_valid(): # All validation rules pass
name = form.cleaned_data['name']
surname = form.cleaned_data['surname']
phone = form.cleaned_data['phone']
mail = form.cleaned_data['mail']
nr_edition = form.cleaned_data['nr_edycji']
id_model = Signup.objects.create(
name=name,
surname=surname,
phone=phone,
mail=mail,
nr_edycji=nr_edition
)
c['form'] = form
c['send']= True
# print sendimage
text = u'Imię: %s \n' \
u'Nazwisko: %s \n' \
u'Telefon: %s \n' \
u'Mail: %s \n' % (name, surname, phone, mail)
html = u'<p>Imię: <strong>%s</strong></p>' \
u'<p>Nazwisko: <strong>%s</strong></p>' \
u'<p>Telefon: <strong>%s</strong></p>' \
u'<p>Mail: <strong>%s</strong></p>' % (name, surname, phone, mail)
sendMailTemplate(['dp#asd.pl'], 'Nowa osoba zapisała się ne Alfe.', text, html, copy=False,
)
return render(request, 'about_alfa.html', c)
else:
c['form'] = form
return render(request, 'about_alfa.html', c)
else:
c['form'] = ContactForm()
return render_to_response('about_alfa.html', c, context_instance=RequestContext(request))
Edit
models
Nothing change
forms
I delete first part and this is result:
class ContactForm(forms.ModelForm):
class Meta:
model = Signup
nr_edition = forms.ModelMultipleChoiceField(queryset=Edition.objects.all())
def save(self):
signup = forms.ModelForm.save(self)
for edition in self.cleaned_data['nr_edition']:
signup.edition_set.add(edition)
def clean(self):
cleaned_data = super(ContactForm, self).clean()
return cleaned_data
ContactFormSet = formset_factory(ContactForm)
view
I delete almost all and :
def about_alfa(request):
c = {}
c['about_alfa'] = True
c['request'] = request
if request.method == 'POST': # If the form has been submitted...
form = ContactForm(request.POST, request.FILES) # A form bound to the POST data
ContactFormSet = formset_factory(ContactForm)
if form.is_valid():
form.save()
return render_to_response('about_alfa.html', c, context_instance=RequestContext(request))
Edit 2
I have no errors but i dont see any field in template (only submit^^).. ?
Use ModelForm with ModelMultipleChoiceField:
class ContactForm(forms.ModelForm):
class Meta:
model = Signup
nr_edition = forms.ModelMultipleChoiceField(queryset=Edition.objects.all())
def save(self):
signup = forms.ModelForm.save(self)
for edition in self.cleaned_data['nr_edition']:
signup.edition_set.add(edition)
And in your view you just save the form:
if form.is_valid():
form.save()
and in template:
<form action="{% url "viewname" %}" method="post">{% csrf_token %}
{{ form.as_p }}
<input type="submit" value="Submit" />
</form>
Edit:
To use formset with ModelForm, you must use modelformset_factory, see docs, not formset_factory
ContactFormSet = modelformset_factory(Signup, form=ContactForm)
Also, you are instantiating ContactForm, you must instead instantiate ContactFormSet with request.POST..
So the view will be like this:
def about_alfa(request):
c = {}
c['about_alfa'] = True
c['request'] = request
ContactFormSet = modelformset_factory(Signup, form=ContactForm)
if request.method == 'POST':
formset = ContactFormSet(request.POST, request.FILES)
if formset.is_valid():
formset.save()
else:
c['form'] = formset
else:
c['form'] = ContactFormSet()
return render_to_response('about_alfa.html', c, context_instance=RequestContext(request))

Categories

Resources