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

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))

Related

Django: store variables in database and pass them between different modules

In my model I'm trying to calculate my user age and create for them an id code and I want this information to be saved in my database, but "age" and "id_code" fields are missing in my database. If I change the name of the function age and id variable are not computed at all.
**accounts.models**
class UserInformation(models.Model):
name = models.CharField(max_length=250)
lastname = models.CharField(max_length=250)
phone = models.CharField(max_length=250)
birthday = models.DateField()
age = models.CharField(max_length=2)
id = models.CharField(max_length=250)
def __str__(self):
self.name + '_' + self.lastname + '_' + str(self.birthday.year)
def age(self):
age = datetime.now().year - int(self.birthdate.year)
return age
def id_code(self):
id_code = self.name + '_' + self.lastname + '_' + int(self.birthday.year)
return id_code
**accounts.forms.py**
class UserInformationForm(forms.ModelForm):
class Meta:
model = UserInformation
fields = ('name', 'lastname', 'birthday', 'phone')
**accounts.views.py**
def add_information(request):
if request.method == 'POST':
form = UserInformationForm(request.POST, request.FILES)
if form.is_valid():
form.instance.user = request.user
form.save()
return redirect('home')
else:
form = UserInformationForm()
return render(request, 'add_information.html', {'form': form})
I've also an another models file in another app where I've two quiz for my user. I'd like to save in my database with answers also the id code created in the other models file and use the userinformation answer to create the string name to use in the database but it gives me error "'ImportError: cannot import name 'name' from 'accounts.models' " even if I've imported the modules:
**question.models.py**
from accounts.models import name
class QuestionOne(models.Model):
question_1a = models.CharField(max_length=250, choices=point)
question_2a = models.CharField(max_length=250, choices=point)
question_3a = models.CharField(max_length=250, choices=point)
id_code = models.CharField(max_length=250)
def __str__(self):
return self.name + '_question_1'
class QuestionTwo(models.Model):
question_1b = models.CharField(max_length=250, choices=point)
question_2b = models.CharField(max_length=250, choices=point)
question_3b = models.CharField(max_length=250, choices=point)
id_code = models.CharField(max_length=250)
def __str__(self):
return self.name + '_question_2'
**question.forms.py**
class QuestionOneForm(forms.ModelForm):
class Meta:
model = QuestionOne
fields = ('question_1a', 'question_2a', 'question_3a')
class QuestionTwoForm(forms.ModelForm):
class Meta:
model = QuestionOne
fields = ('question_1b', 'question_2b', 'question_3b')
Lasltly in my html I'd like to show how many question forms have been completed so I added the "quest__done" variable. Unfortunly is not working and in my page {{ quest_done }} is just a blank space
**question.views.py**
def question_one(request):
quest_done = 0
if request.method == 'POST':
form = QuestionOneForm(request.POST, request.FILES)
if form.is_valid():
quest_done += 1
form.instance.user = request.user
form.save()
return redirect('home')
else:
form = QuestionOneForm()
return render(request, 'quest.html', {'form': form, 'quest_done': quest_done})
def question_two(request):
quest_done = 0
if request.method == 'POST':
form = QuestionTwoForm(request.POST, request.FILES)
if form.is_valid():
quest_done += 1
form.instance.user = request.user
form.save()
return redirect('home')
else:
form = QuestionTwoForm()
return render(request, 'quest.html', {'form': form, 'quest_done': quest_done})
*html**
<div class="row">
<div class="col-sm-3">
<h6 class="mb-0">Question form completed:</h6>
</div>
<div class="col-sm-9 text-secondary">
{{ quest_done }} /2
</div>
</div>
Override save() method in model.
class UserInformation(models.Model):
name = models.CharField(max_length=250)
lastname = models.CharField(max_length=250)
phone = models.CharField(max_length=250)
birthday = models.DateField()
age = models.CharField(max_length=2,default="")
id = models.CharField(max_length=250,default="")
def save(self, *args, **kwargs):
if self.age ="":
self.age = datetime.now().year - int(self.birthdate.year)
self.save()
super(UserInformation, self).save(*args, **kwargs)
you can do same for id in save() method.

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.

How to display records belongs only for user instead for all users

I have a little problem. I want to to display in list only records belongs to user whos add it. In my app when I'am login as 'user' and I want to add new records incude records from list, I see all records in db from ForeignKey. How to make it correctly?
In 'Strona www' when I expand the list I see all records, not only records added by user personally.
My view for it is:
#login_required
def new_keyword(request):
if request.method == "POST":
new_keyword = KeywordForm(request.POST)
if new_keyword.is_valid():
new_keyword=new_keyword.save(commit=False)
new_keyword.user = request.user
new_keyword.save()
messages.success(request, 'Pomyślnie dodano słowo kluczowe')
return render(request, 'konto/new_keyword_ok.html')
else:
new_keyword = WebsiteForm()
return render(request, 'konto/new_keyword.html', {'new_keyword':new_keyword})
in forms.py I have:
class KeywordForm(forms.ModelForm):
class Meta:
model = Keyword
fields = ('www', 'keyword')
models.py
class Keyword(models.Model):
user = models.ForeignKey(User, on_delete=models.CASCADE, verbose_name="Użytkownik")
www = models.ForeignKey(Website, on_delete=models.CASCADE, verbose_name="Strona www")
keyword = models.CharField(max_length=250, verbose_name="Słowo kluczowe", unique=False)
urls.py
path('new-keyword/', new_keyword, name='new_keyword'),
and html for display the form is:
{% if request.user.is_authenticated %}
<form action="." method="post">
{{ new_keyword.as_p }}
{% csrf_token %}
<p><input type="submit" value="Dodaj nowe słowo kluczowe" ></p>
Powrót do monitoringu
</form>
{% endif %}
EDIT:
models.py
from django.db import models
from django.contrib.auth.models import User
class Website(models.Model):
user = models.ForeignKey(User, on_delete=models.CASCADE, verbose_name="Użytkownik")
website = models.CharField(max_length=250,verbose_name='Strona www', unique=False)
class Meta:
verbose_name = 'Strona www'
verbose_name_plural = 'Strony www'
def __str__(self):
return self.website
class Keyword(models.Model):
user = models.ForeignKey(User, on_delete=models.CASCADE, verbose_name="Użytkownik")
www = models.ForeignKey(Website, on_delete=models.CASCADE, verbose_name="Strona www")
keyword = models.CharField(max_length=250, verbose_name="Słowo kluczowe", unique=False)
class Meta:
verbose_name = 'Słowo kluczowe'
verbose_name_plural = 'Słowa kluczowe'
def __str__(self):
return self.keyword
Pass the request.user to your form and use the inverse relation user.website_set :
forms :
class KeywordForm(forms.ModelForm):
class Meta:
model = Keyword
fields = ('www', 'keyword')
def __init__(self, user, *args, **kwargs):
super(KeywordForm, self).__init__(*args, **kwargs)
self.fields['www'].queryset = user.website_set.all()
self.user = user
def save(self, commit=True):
instance = super(KeywordForm, self).save(commit=False)
instance.user = self.user
if commit:
instance.save()
return instance
views:
#login_required
def new_keyword(request):
if request.method == "POST":
new_keyword = KeywordForm(request.user, request.POST)
if new_keyword.is_valid():
new_keyword.save()
messages.success(request, 'Pomyślnie dodano słowo kluczowe')
# DONT DO THIS ! REDIRECT INSTEAD
return render(request, 'konto/new_keyword_ok.html')
else:
new_keyword = KeywordForm(request.user)
return render(request, 'konto/new_keyword.html', {'new_keyword':new_keyword})
As a side note: after a successful POST you want to redirect (even if to the same url). This avoids a lot of troubles (and duplicate submissions) when a user reloads the page
Just pass the user id to your form and then set a queryset for your field
like this:
How to pass the user to your form:
in your view:
#login_required
def new_keyword(request):
if request.method == "POST":
#### Notice this part.
new_keyword = KeywordForm(data=request.POST, u=request.user)
if new_keyword.is_valid():
new_keyword=new_keyword.save(commit=False)
new_keyword.user = request.user
new_keyword.save()
messages.success(request, 'Pomyślnie dodano słowo kluczowe')
return render(request, 'konto/new_keyword_ok.html')
else:
# Notice this part.
new_keyword = WebsiteForm(data=None, u=request.user)
return render(request, 'konto/new_keyword.html', {'new_keyword':new_keyword})
How to retrieve the user in form and set the queryset:
forms.py:
class KeywordForm(forms.ModelForm):
class Meta:
model = Keyword
fields = ('www', 'keyword')
def __init__(self, current_user, *args, **kwargs):
self.u = kwargs.pop("u") ## The user you just passed.
super(KeywordForm, self).__init__(*args, **kwargs)
self.fields['www'].queryset = Website.objects.filter(user=self.u) ## Setting the queryset.

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.

How to display an initial value in the text field?

I load the form. I need to in the text field city shows the initial value.
models:
class City(models.Model):
city = models.CharField(
max_length=40, blank=True,
)
class UserProfile(User):
family = models.CharField(
'Фамилия', max_length=30, blank=True, null=True,
)
city = models.ForeignKey(
City, verbose_name='Город', max_length=50, blank=True, null=True,
)
forms:
class PersonalDataForm(forms.ModelForm):
city = forms.CharField(
label='Город',
required=False,
)
class Meta:
model = UserProfile
fields = (
'family',
)
def save(self):
obj = super(PersonalDataForm, self).save(commit=False)
city_name = self.cleaned_data.get('city', None).strip()
if city_name:
if City.objects.filter(city=city_name).exists():
obj.city = City.objects.get(city=city_name)
else:
rec = City(city=city_name)
rec.save()
obj.city = rec
else:
obj.city = None
return obj.save()
views:
def personal_data_page(request):
entry_user_profile = UserProfile.objects.get(user_ptr_id=request.user.id)
form = PersonalDataForm(instance=entry_user_profile)
if request.method == 'POST':
form = PersonalDataForm(request.POST, instance=entry_user_profile)
if form.is_valid():
form.save()
return HttpResponseRedirect('/userprofile/personal_data_page_changed/')
t = loader.get_template('personal_data_page.html')
c = RequestContext(request, {
'form': form,
}, [custom_proc])
return HttpResponse(t.render(c))
template.html:
{{ family.city }}
{{ form.city }}
the problem is that when loading the form field 'city' is empty. but it must contain the value from the table (table full of values​​)
If you use this pattern, the initial value should be visible:
if request.method=='POST':
data=request.POST
else:
data=None
form=MyForm(data, initial=...)
if (not data is None) and form.is_valid():
form.save()
return django.http.HttpResponseRedirect(...)
return HttpResponse(render(...))

Categories

Resources