Add two form fields in Django - python

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.

Related

Django save form with foreign key

I am currently trying to create a form where users get to fill in their details after creating an account. The idea is that every user, after registration, gets redirected to this form page to fill it out. To achieve this, i'm using foreign keys.However it doesn't save to database.
models.py
class User(AbstractUser):
pass
def __str__(self):
return self.username
class Detail(models.Model):
user = models.ForeignKey(User, on_delete=models.CASCADE, null=False, default="")
first_name = models.CharField(max_length=200, default="")
last_name = models.CharField(max_length=255, default="")
class Meta:
verbose_name_plural = "Detail"
def __str__(self):
return self.first_name+ " "+self.last_name
forms.py
class Details(forms.ModelForm):
class Meta:
model = Detail
fields = "__all__"
widgets={
"user": forms.TextInput()
}
views.py
def details(request):
if request.method =="POST":
form = Details(request.POST)
if form.is_valid():
detail = form.save(commit=False)
detail.user = request.user
detail.first_name = detail.first_name.lower()
detail.last_name = detail.last_name.lower()
detail.save()
return redirect("admin:index")
else:
form = Details(initial={"user":request.user.username})
return render(request, "details.html", {"form":form})
You need to exclue user field from ModelForm like this
form.py
class Details(forms.ModelForm):
class Meta:
model = Detail
fields = "__all__"
exclude =["user"]
views.py
def details(request):
if request.method =="POST":
form = Details(request.POST)
if form.is_valid():
detail = form.save(commit=False)
detail.user = request.user
detail.first_name = detail.first_name.lower()
detail.last_name = detail.last_name.lower()
detail.save()
return redirect("admin:index")
else:
form = Details()
return render(request, "details.html", {"form":form})

Django ModelForm - Get value from ManyToManyField

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.

Python Django forms replaces old inputs

I am currently trying to impliment a registration form but everytime I test it out, the new registrant replaces the old registration. So I am unable to have more than one user at a time.
any help would be great because I do not know what to do. Thanks.
My views:
def register_page(request):
if request.method == 'POST':
form = RegistrationForm(request.POST)
if form.is_valid():
cd = form.cleaned_data
new_user = bitcoinUser(first_name=cd['first_name'],
last_name=cd['last_name'],
phone_number=cd['phone_number'])
new_user.save()
my models:
class bitcoinUser(models.Model):
first_name = models.CharField(max_length=100)
last_name = models.CharField(max_length=100)
phone_number = models.IntegerField(primary_key=True)
I honestly don't know why that didn't work (I think it is because you are saving the object 'new_user' and not the form), but i will recommend the way that i do forms in Django:
models.py:
from django.forms import ModelForm
class Bitcoinuser(models.Model):
first_name = models.CharField(max_length=36)
last_name = models.CharField(max_length=36)
phone = models.IntegerField(primary_key=True)
def __str__(self):
return self.name
class BitcoinuserForm(ModelForm):
class Meta:
model = Bitcoinuser
fields = ['first_name', 'last_name', 'phone']
views.py:
from .models import BitcoinuserForm
def get_bitcoinuser(request):
if request.method == 'POST':
form = BitcoinuserForm(request.POST)
if form.is_valid():
first_name = form.cleaned_data['first_name']
last_name = form.cleaned_data['last_name']
phone = form.cleaned_data['phone']
form.save()
return HttpResponseRedirect('/database/')
else:
form = BitcoinuserForm()
return render(request, 'appname/get_bitcoinuser.html', {'form': form})
It's simple, straigthfoward and works fine.

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.

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