I need to create a form of persons, where the camp Name must receive an API response. I created the formulary e rendered the api response in template, but I can´t put it in my formulary, in order to save in my Models camp Name. So, I just want to save my API respone inside my forms and in my database.
Views
def cadastro(request):
url = 'https://gerador-nomes.herokuapp.com/nome/aleatorio'
api = requests.get(url)
nome_api = ' '.join(api.json())
form = PessoaForm()
form.nome = api
if request.method == 'POST':
form = PessoaForm(request.POST)
if form.is_valid():
form.cleaned_data('nome')
form.save()
return redirect('/')
context = {'form': form, 'api': nome_api}
return render(request, 'base/pessoa_form.html', context)
pessoa_form.html
<body>
<form action="" method="post">
{% csrf_token %}
{{form}}
<input type="submit" name="Cadastrar">
</form>
</body>
</html>
Forms
from django.forms import ModelForm
from . models import Pessoa
class PessoaForm(ModelForm):
class Meta:
model = Pessoa
fields = '__all__'
Models
from django.db import models
class Pessoa(models.Model):
name= models.CharField(max_length=255, null=True)
lastname= models.CharField(max_length=255, null=True)
age= models.IntegerField(null=True)
birthday_date= models.DateField()
email = models.CharField(max_length=255, null=True)
nickname= models.CharField(max_length=255, null=True, blank=True)
note = models.CharField(max_length=500, null=True, blank=True)
def __str__(self):
return self.nome
class Meta:
ordering = ['nome', 'sobrenome']
I have tried some things of my head but nothing actually worked, like try to access the variable Name in my forms inside my template and inside my views.
[English]
Well, by judging by the variable names you've chosen, I guess you're brazilian, so I'll post the answer in portuguese as well.
I don't know if this is the best practice, but you could just append the api response as a new field in the request.POST, for instance:
[Portuguese Translation]
Pelos nomes que tu usou, imagino que sejas BR então vou botar a resposta em Português também além do inglês.
Não sei se é o método que segue as melhores práticas, mas você poderia simplesmente adicionar a resposta da API como um campo novo no teu request.POST, por exemplo:
def cadastro(request):
url = 'https://gerador-nomes.herokuapp.com/nome/aleatorio'
api = requests.get(url)
nome_api = ' '.join(api.json())
form = PessoaForm()
if request.method == 'POST':
updated_request = request.POST.copy()
updated_request.update({'name': nome_api})
form = PessoaForm(updated_request)
if form.is_valid():
form.save()
return redirect('/')
context = {'form': form, 'api': nome_api}
return render(request, 'base/pessoa_form.html', context)
Related
I have pre-filled forms for my user (the django user + my profile one with more informations) that just doesn't want to be saved. No error message, no redirection, I press the button "edit", and then... same page, with the modifications already written. But the database isn't changed.
So, here is the code :
forms.py :
class UpdateUser(forms.ModelForm):
email = forms.EmailField(required=True)
class Meta:
model = User
fields = ('email', 'username')
def clean_email(self):
email = self.cleaned_data.get('email')
username = self.cleaned_data.get('username')
if email and User.objects.filter(email=email).exclude(username=username).count():
raise forms.ValidationError('Cette adresse email est déjà utilisée, veuillez en indiquer une autre')
return email
class UpdateProfil(forms.ModelForm):
class Meta:
model = Profil
fields = ("society", "thingA", "thingB", "thingC", "thingD", "thingE")
views.py :
#login_required
def edit_profile(request):
user = User.objects.get(username = request.user)
profile = Profil.objects.get(user = user)
if request.method == 'POST':
form1 = UpdateUser(request.POST, instance=user)
form2 = UpdateProfil(request.POST, instance=profile)
if form1.is_valid() and form2.is_valid():
form1.save()
form2.save()
return HttpResponseRedirect('Register/view_profile.html')
else:
form1 = UpdateUser(initial={"email": user.email,
"username": user.username})
form2 = UpdateProfil(initial={"society": profile.society,
"thingA": profile.thingA,
"thingB": profile.thingB,
"thingC": profile.thingC,
"thingD": profile.thingD,
"thingE": profile.thingE})
return render(request, 'Register/edit_profile.html', locals())
and the template:
<form action="" method="post">
{% csrf_token %}
<p>Email : </p>{{ form1.email }}
<p>Nom d'utilisateur : </p>{{ form1.username }}
<p>Société (entreprise, association, établissement...") :</p>
{{ form2.society }}
<p>Si vous êtes membres d'un ou plusieurs centres pilotes, veuillez les cocher ci-dessous :</p>
<p>thingA : {{form2.thingA }}</p>
<p>thingB : {{form2.thingB }}</p>
<p>thingC : {{form2.thingC }}</p>
<p>thingD : {{form2.thingD }}</p>
<p>thingE : {{form2.thingE }}</p>
<button type="submit">Editer</button>
</form>
models.py
class Profil(models.Model):
user = models.OneToOneField(User, on_delete=models.CASCADE)
deadline = models.DateField(blank=True, null=True,
default=None,
verbose_name="Date limite de validité")
thingA = models.BooleanField(default=False)
thingB = models.BooleanField(default=False)
thingC = models.BooleanField(default=False)
thingD = models.BooleanField(default=False)
thingE = models.BooleanField(default=False)
society = models.CharField(max_length = 255,
blank=True, null=True,
verbose_name="Société",
help_text="Le nom de votre entreprise, association, établissement...")
def __str__(self):
return "Profil de {0}".format(self.user.username)
After trying different thing and reading everything I could on the topic without finding a solution working, I try to think outside the box : I thought that maybe it was because I didn't put the password inside the form, but it should'nt play a role here, right ?
So, maybe a permissions problem ? I try giving permisions, for both the model. Still not working...
Thanks for your time, and sorry for my English mistakes...
So, I tinkered with my code a bit, and it's now working, I don't know why, and if someone know, I'm all ears!
I'll put it here, in case it could be helpful for others.
so, new view's code :
#login_required
def edit_profile(request):
user = User.objects.get(username = request.user)
profile = Profil.objects.get(user = user)
if request.method == 'POST':
form1 = UpdateUser(request.POST, instance=user)
form2 = UpdateProfil(request.POST, instance=profile)
if form1.is_valid() and form2.is_valid():
form1.save()
form2.save()
return redirect("viewProfile") # Here is the only change I finished with
else:
form1 = UpdateUser(initial={"email": user.email,
"username": user.username})
form2 = UpdateProfil(initial={"society": profile.society,
"thingA": profile.thingA,
"thingB": profile.thingB,
"thingC": profile.thingC,
"thingD": profile.thingD,
"thingE": profile.thingE})
return render(request, 'Register/edit_profile.html', locals())
So, I guess the problem was with the httpResponseRedirect, don't know why, since there was no error, and nothing was saved, but well... I won't look a gift horse in the mouth! It's working now. 2020 suddenly seems a lot better! Until tomorrow that is =P
Thanks to those who tried to help me!
My view:
'''
from django.shortcuts import render
from django.http import HttpResponse
from .models import Post
from .forms import createPostForm
def showPosts(request):
if request.method == "POST":
crf = createPostForm(request.POST)
crf.author = request.user
crf.save()
else:
crf = createPostForm()
context = {
'post' : Post.objects.all(),
'crf' : crf
}
return render(request, 'Content/FeedsPage.html', context)
'''
My Model:
'''
from django.db import models
from django.contrib.auth.models import User
class Post(models.Model):
# image = models.ImageField(blank=True, null=True, upload_to='post_images/')
# video = models.FileField(blank=True, null=True, upload_to='post_videos/')
title = models.CharField(max_length=100)
description = models.CharField(blank=True, max_length=1000)
date_posted = models.DateTimeField(auto_now_add=True)
author = models.ForeignKey(User, on_delete=models.CASCADE)
def __str__(self):
return self.title
'''
My Template:
'''
<form enctype="multipart/form-data" novalidate method="post">
{%csrf_token%}
<div class="fieldWrapper">
{{crf.title.errors}}
{{crf.title}}
</div>
<div class="fieldWrapper">
{{crf.description.errors}}
{{crf.description}}
</div>
<button class="primaryButton" type="submit">submit</button>
</form>
'''
My Form:
'''
from django import forms
from .models import Post
class createPostForm(forms.ModelForm):
title = forms.CharField(
widget = forms.TextInput(attrs={
'placeholder': 'Give a sweet title',
'autocomplete' :'off'
})
)
description = forms.CharField(widget=forms.TextInput(attrs={
'placeholder': 'Please elaborate a little',
'autocomplete' :'off'
}))
class Meta:
model = Post
fields = '__all__'
'''
I removed the is_valid() function to see whats happening and apperently its showing
'The Post could not be created because the data didn't validate'
Please somebody help
This save() method accepts an optional commit keyword argument, which accepts either True or False. If you call save() with commit=False, then it will return an object that hasn't yet been saved to the database. Which is neat for some post processing before actually saving it! So, you method should look something like this.
def showPosts(request):
if request.method == "POST":
crf = createPostForm(request.POST)
if crf.is_valid():
form = crf.save(commit=False)
form.author = request.user
form.save()
else:
crf = createPostForm()
context = {
'post' : Post.objects.all(),
'crf' : crf
}
return render(request, 'Content/FeedsPage.html', context)
I'm trying to make a form, with the ModelForm class, for people to be recruited by a small company. So I need photo of their identity card (face and back) and their life card. The problem is that when I send the form, after selecting the photos from my computer, it does not register in the database (not even the path), and they do not a copy to the desired media folder. By cons, if I do it from the admin, it works, I can even open the image in my browser. However, they still do not upload to the media folder.
models.py :
from django.db import models
from django.contrib.auth.models import User
class UserExtention (models.Model):
user = models.OneToOneField(User, on_delete = models.CASCADE, null=True, verbose_name='utilisateur')
phone_number = models.CharField (max_length = 10, null = True, blank=True, verbose_name='numéro de téléphone')
postal_code = models.IntegerField (null = True, blank=True, verbose_name='code postal')
town = models.CharField (max_length=50, null=True, blank=True, verbose_name='ville')
address = models.CharField (max_length=500, null=True, blank=True, verbose_name='adresse')
id_card_recto = models.ImageField (upload_to = 'pictures/id_card_recto', null=True, blank=True, verbose_name="photo du recto de la carte d'identité")
id_card_verso = models.ImageField (upload_to = 'pictures/id_card_verso', null=True, blank=True, verbose_name="photo du verso de la carte d'identité")
vital_card = models.ImageField (upload_to = 'pictures/vital_card', null=True, blank=True, verbose_name="photo de la carte vitale")
hours_number = models.IntegerField (null=True, blank=True, verbose_name="nombre d'heure effectuée par le salarié")
def __str__(self):
return "Profil de {}".format(self.user.username)
forms.py :
from django import forms
from .models import UserExtention
from django.contrib.auth.models import User
class UserForm(forms.ModelForm):
class Meta:
model = User
fields = (
'password',
'username',
'first_name',
'last_name',
'email',
)
class UserExtentionForm(forms.ModelForm):
class Meta:
model = UserExtention
exclude = ('user', 'hours_number')
views.py :
from django.shortcuts import render
from .forms import UserForm, UserExtentionForm
def registration (request):
form = UserForm(request.POST or None, request.FILES)
form2 = UserExtentionForm(request.POST or None)
envoi = False
if form.is_valid() and form2.is_valid():
user = form.save()
user_extention = form2.save(commit = False)
user_extention.user = user
user_extention.save()
envoi = True
return render (request, 'registration/registration.html', locals())
The template :
<h1>Ceci est la page principale de l'application nommée "Registration"</h1>
{% if not envoi %}
<form action="{% url "registration" %}" enctype="multipart/form-data" method="post">
{% csrf_token %}
{{ form.as_p}}
{{ form2.as_p}}
<input type="submit" value="submit">
</form>
{% else %}
<p>Votre inscription a bien été prise en compte, vous pouvez à présent vous connecter dans l'onglet connexion</p>
{% endif %}
STATIC_URL = '/static/'
STATICFILES_DIRS = (
os.path.join(BASE_DIR, "static"),
)
MEDIA_ROOT = '/media/'
MEDIA_URL = '/media/'
Thanks for answer !
The form where you have media form fields is the UserExtentionForm, but in your code, you pass request.FILES only to the UserForm, that has no such media fields.
def registration (request):
if request.method == 'POST':
form = UserForm(request.POST, request.FILES)
form2 = UserExtentionForm(request.POST, request.FILES)
if form.is_valid() and form2.is_valid():
user = form.save()
user_extention = form2.save(commit = False)
user_extention.user = user
user_extention.save()
return redirect('some-view-name')
else:
form = UserForm()
form2 = UserExtentionForm()
return render (
request,
'registration/registration.html',
{'form': form, 'form2': form2}
)
Your view however contains some serious anti-patterns that are now (partially) migitated by the proposed solution:
you should not use request.POST or None, since a valid POST request can be empty, but it is still a POST request;
in case the POST request is successful, you should make a redirect, to implement the Post/Redirect/Get pattern [wiki]; and
please do not use locals(), since it will pass all variables to the template, even uninteded ones. Furthermore since it is not clear what you pass to the template, later you might be tempted to remove some variables from your view for optimization, and the IDE will not raise a warning/error that these variables are still necessary in the template.
If you want to add a message that the submission was successful, I advise you to use Django's messaging framework [Django-doc], and not pass a variable through the context. This framework is designed to post messages, regardless of the template itself, and prevent showing the same message multiple times.
Problem description: UserProfile form doesn't save any data.
I am creating a new User and automatically create a UserProfile object for him (so I'm extending UserProfile), so I can go to admin page and fill all the fields . But when I'm trying to do it from client side, my form just doesn't catch the data.
Also the strangest moment is that I can change username and email using UserChangeForm, so I'm trying to do the same for UserProfileObject.
models.py:
class UserProfile(models.Model):
user = models.OneToOneField(User)
image = models.ImageField(upload_to='profile_image', blank=True)
title = models.CharField(max_length=100, default = '')
first_name = models.CharField(max_length=200, default = '')
last_name = models.CharField(max_length=200, default = '')
subject = models.ManyToManyField('Subject', related_name='tutor_type', default = '', help_text="Select a subject")
AREA_STATUS = (
('Jerusalem', 'Jerusalem'),
('Tel Aviv', 'Tel Aviv'),
('Haifa', 'Haifa'),
('Eilat', 'Eilat')
)
area = models.CharField(max_length=200, choices=AREA_STATUS, blank=True, default='', help_text='Tutor area')
# Foreign Key used because tutor can only have one area, but area can have multiple tutors
# Author as a string rather than object because it hasn't been declared yet in file.
description = models.TextField(max_length=4000, help_text="Enter a brief description about yourself")
charge = models.IntegerField(default = '0')
# ManyToManyField used because Subject can contain many tutors. Tutors can cover many subjects.
# Subject declared as an object because it has already been defined.
LANGUAGE_CHOICES = (
('English','English'),
('Hebrew','Hebrew'),
('Russian','Russian'),
('French','French'),
('Arabic','Arabic'),
)
language = models.CharField('Language', choices = LANGUAGE_CHOICES, max_length=50, null=True)
def __str__(self):
return self.user.username
def display_subject(self):
"""
Creates a string for the subject. This is required to display subject in Admin.
"""
return ', '.join([ subject.name for subject in self.subject.all()[:3] ])
display_subject.short_description = 'Subject'
def create_profile(sender, **kwargs):
if kwargs['created']:
user_profile = UserProfile.objects.create(user=kwargs['instance'])
post_save.connect(create_profile, sender = User)
forms.py::
class EditProfileForm(UserChangeForm):
class Meta:
model = User
fields = (
'username',
'email',
'password'
)
class EditExtendedProfileForm(UserChangeForm):
class Meta:
model = UserProfile
fields = '__all__'
exclude = ('user',)
views.py:
def edit_profile(request):
if request.method == 'POST':
form = EditProfileForm(request.POST, instance=request.user)
if form.is_valid():
form.save()
return redirect(reverse('accounts:view_profile'))
else:
form = EditProfileForm(instance=request.user)
args = {'form': form}
return render(request, 'accounts/edit_profile.html', args)
def edit_extended_profile(request):
if request.method == "POST":
form = EditExtendedProfileForm(request.POST, instance=request.user)
if form.is_valid():
form.save()
return redirect(reverse('accounts:view_profile'))
else:
return redirect(reverse('accounts:edit_extended_profile'))
else:
form = EditExtendedProfileForm(instance = request.user)
args = {'form':form}
return render(request, 'accounts/edit_extended_profile.html', args)
edit_extended_profile.html:
{% extends "base.html" %}
{% block head %}
<title>Profile</title>
{% endblock %}
{% block body %}
<div class = "container">
<form method="POST">
{% csrf_token %}
{{form.as_p}}
<button type = "submit" class = "btn btn-success">Submit</button>
</form>
</div>
{% endblock %}
and it is the same template as for edit_profile view.
No traceback, no errors. Any help will be appreciated. Thanks in advance.
I can't figure out how to store a simple form in the database. I think I'm quite close but there is probably something wrong in my views.py. Here is my code, any ideas what I'm doing wrong? (also on dpaste)
# models.py
class IngredienceCategory(models.Model):
name = models.CharField(max_length=30, unique=True)
user = models.ForeignKey(User, null=True, blank=True)
class Meta:
verbose_name_plural = "Ingredience Categories"
def __unicode__(self):
return self.name
# forms.py
class CategoryForm(forms.Form):
name = forms.CharField(max_length=30)
# views.py
#login_required
def newCategory(request):
if request.method == 'POST':
username = request.user.username
cform = CategoryForm(request.POST)
if cform.is_valid():
formInstance = cform.save(commit = False)
formInstance.user = username
formInstance.name = cform.cleaned_data['name']
formInstance = IngredienceCategory.objects.filter(name=formInstance.name, user=formInstance.user)
formInstance.save()
# return HttpResponseRedirect('new-category/')
else:
form = CategoryForm()
context = {'form': form}
return render_to_response('new-category.html', context, context_instance=RequestContext(request))
# new-category.html
<h3>Insert New Category</h3>
<form action="/" method="post" id="food-form">{% csrf_token %}
{{ form.as_p }}
<input type="submit" name="foodForm" value="Save" />
</form>
The line below is not useful at it current position. That command will perform a database query and assign the result as a queryset, before you have saved the form data.
formInstance = IngredienceCategory.objects.filter(name=formInstance.name, user=formInstance.user)
This should work:
With cform as a normal Form:
if cform.is_valid():
formInstance = IngredienceCategory(user=request.user, cform.cleaned_data['name'])
formInstance.save()
If cform had been a ModelForm you could do:
if cform.is_valid():
formInstance = cform.save(commit=False)
formInstance.user = request.user
formInstance.save()
I do recommend you to check out ModelForms since it will build the cleaning functionality based on your model.
You should inherit from ModelForm
from django.forms import ModelForm
class CategoryForm(ModelForm):
class Meta:
model = IngredienceCategory
Refer to https://docs.djangoproject.com/en/dev/topics/forms/modelforms/ for how to render form and save it to database.