Django. How to saves data in two forms - django

I have two forms:
class Form_registration_security (ModelForm):
class Meta:
model = Security
fields = ['fk_id_users_security', 'e_mail', 'password']
widgets = {
'e_mail': forms.TextInput(attrs = {'placeholder': 'Your Email'}),
'password': forms.TextInput(attrs = {'placeholder': 'New Password'}),
}
class Form_registration_user (ModelForm):
class Meta:
model = Users
fields = ['id', 'first_name', 'last_name', 'date_birthdaty']
widgets = {
'id': forms.TextInput(attrs = {'placeholder': 'id'}),
'first_name': forms.TextInput(attrs = {'placeholder': 'First Name'}),
'last_name': forms.TextInput(attrs = {'placeholder': 'Last Name'}),
'date_birthdaty': forms.TextInput(attrs = {'placeholder': 'Date'})
}
But data saves only in one mode - (Form_registration_user).
Code in view:
def save_registration (request ):
if request.method == 'POST':
form_user = Form_registration_user(request.POST)
form_security = Form_registration_security(request.POST)
if form_user.is_valid() and form_security.is_valid():
data_user = form_user.save()
data_security = form_security.save(commit=False)
data_security.data_user = data_user
data_security.save()
return render_to_response('see_you_later.html')
else:
return render_to_response('error.html')
I'm always see - error.html, although I'm fill right form.
Model User have a primary key.
Model Security have a foreign key.
My template:
<!DOCTYPE html>
<html>
<head>
<title></title>
</head>
<body>
<div class="entry_or_register">
{% load staticfiles %}
<img src="{% static "tumblr.gif" %}" width="1250" height="550">
<form name="registration" method="post" action="save/">
{% csrf_token %}
{{ form_registration_user.as_p }}
{{ form_registration_security.as_p }}
<input type="submit" value="SignUp">
</form>
</div>
</body>
</html>
Thanks for help! Right function:
def save_registration (request ):
if request.method == 'POST':
form_user = Form_registration_user(request.POST)
form_security = Form_registration_security(request.POST, request.FILES)
if form_user.is_valid():
data_user = form_user.save()
data_security = form_security.save(commit=False)
data_security.data_user = data_user
data_security.save()
return render_to_response('see_you_later.html')
else:
return render_to_response('error.html')

You should post also the html markup of the corresponding template.
Anyway, here's a view i used once i had to save data from two ModelForms in the same page, with the user clicking a single submit button:
def register(request):
message = None
if request.method == 'POST':
user_form = NewUserForm(request.POST)
details_form = UserDetailsForm(request.POST, request.FILES)
if user_form.is_valid():
new_simple_user = user_form.save()
message = _("User inserted")
if details_form.is_valid():
# Create, but don't save the new user details instance.
new_user_details = details_form.save(commit=False)
# Associate the user to the user details
new_user_details.user = new_simple_user
# save a new user details instance
new_user_details.save()
message = _("User details inserted")
else:
user_form = NewUserForm()
details_form = UserDetailsForm()
return render_to_response('register.html', { 'user_form': user_form, 'details_form': details_form, 'message': message,},\
context_instance=RequestContext(request))

I'm not sure how you rendered your forms in the template, but it could be that when you click submit, only one of the forms sends its data in the HTTP request.
Then the other form's constructor won't find its key in the POST variable and the outcome won't be a valid form. I think that's why you test always fail.
Now, I hope you could give us some more details on what you're trying to do but I think you are going to need a custom Form class (that would be the union of your two current forms) instead of a ModelForm.
EDIT : sorry, you shouldn't actually need to do that...
Good luck.

Related

Bespoke form on Django - dropdown menu matching models choices

I am creating a form with all sorts of headers and question before each field.
I initially create a form in Forms.py, but it seems quite difficult to customise it the way I want it.
I resorted to build the form in the html template.
I am struggling to create a drop down menu.
In this example, when selecting the colour, users would have 4 choices listed in the choices in models.py. I am clearly not linking the form in the template to the actual form.
What am I doing wrong?
(I should say, I saw a couple of things on here about fieldsets, but I dont understand the actual solutions explained)
Here is the code
Models.py
LOOKCOLOUR=(
(1,'Straw'),
(2,'Yellow'),
(3,'Gold'),
(4,'Amber'),
)
class ChampageRating(models.Model):
user = models.ForeignKey(User,blank=True, on_delete=models.CASCADE)
product=models.ForeignKey(Product,related_name="champcomments", on_delete=models.CASCADE)
look_colour=models.IntegerField(choices=LOOKCOLOUR, default=0)
..
def __str__(self):
return '%s - %s - %s'%(self.user, self.product, self.date_added)
forms.py
class ElderFlowerChampForm(ModelForm):
class Meta:
model = ChampageRating
fields = ('look_colour', )
labels ={
'look_colour': 'Colour',
}
widgets = {
'look_colour':forms.Select(attrs={'class':'form-control'}),
}
views.py
def elderflowerchamp(request, product_id):
global ChampageRating
product = Product.objects.get(pk=product_id)
url = request.META.get('HTTP_REFERER')
submitted = False
try:
if request.method == "POST":
reviews = ChampageRating.objects.get(pk=product_id)
if request.user.is_superuser:
form = ElderFlowerChampFormAdmin(request.POST, instance=reviews)
if form.is_valid():
form.save()
return redirect('home')
else:
form = ElderFlowerChampForm(request.POST, instance=reviews)
if form.is_valid():
ChampageRating = form.save(commit=False)
ChampageRating.user = request.user
ChampageRating.save()
return redirect('home')
else:
#This part goes to the page, but doesnt submit
reviews = ChampageRating.objects.get(pk=product_id)
if request.user.is_superuser:
form = ElderFlowerChampFormAdmin
else:
form = ElderFlowerChampForm
if 'submitted' in request.GET:
submitted = True
except:
reviews = None
if request.user.is_superuser:
form = ElderFlowerChampFormAdmin(request.POST)
if form.is_valid():
data = ChampageRating()
data.rating = form.cleaned_data['rating']
data.look_colour = form.cleaned_data['look_colour']
data.ip = request.META.get('REMOTE_ADDR')
data.product_id = product_id
data.user_id = request.user.id
data.save()
messages.success(request, 'Thank you! Your review has been submitted.')
return redirect('home')
else:
form = ElderFlowerChampForm(request.POST)
if form.is_valid():
data = ChampageRating()
data.rating = form.cleaned_data['rating']
data.look_colour = form.cleaned_data['look_colour']
data.ip = request.META.get('REMOTE_ADDR')
data.product_id = product_id
data.user_id = request.user.id
data.save()
messages.success(request, 'Thank you! Your review has been submitted.')
return redirect('home')
template
<form action="{% url 'ElderFlowerReview' product.id%}" method="POST">
{%csrf_token%}
<h4>Look</h4>
<h5>Colour</h5>
<select name="look_colour" rows="4" class="form-control"></select>
</form>
Just in case someone comes across the same problem, I kinda found the solution. (it creates new problems, but it's a start).
Source here: https://github.com/hadpro24/django-forms-fieldset
Here is what I did.
I installed fieldsets (thats the part I was missing on other posts)
pip install django-forms-fieldset
I added fieldsets in the installed apps (in setting.py)
INSTALLED_APPS = [
,
'forms_fieldset']
in forms.py Fieldsets need to be added before Meta
class ElderFlowerChampFormAdmin(ModelForm):
fieldsets=[
("Look",{'fields':[
('look_colour','look_clarity','look_effervescence')]}),
]
class Meta:
model = ChampageRating
fields = ('user','look_colour', ..)
labels ={
'user': '',
'product': '',
'look_colour': '',
}
widgets = {
'user': forms.Select(attrs={'class':'form-control'}),
'look_colour':forms.Select(attrs={'class':'form-control'}),
}
then in the template
{% load forms_fieldset static %}
<link rel="stylesheet" type="text/css" href="{% static 'forms_fieldset/css/main.css' %}">
<form action="{% url '#' product.id%}"method = POST>
{%csrf_token%}
{{ form|fieldset}}
<button class="btn btn-secondary">Add Review</button>
</form>

How to upload file in django

this might be a pretty stupid question. Also I am new to django. But I was trying to create a basic file upload approach with django where user uploads a file and it gets stored into the defined media path (or whatever that it's called) and that the file size, name, and some other attributes that are needed can be stored into the database. So I have the model ready which will help you understand the question better.
class Document(models.Model):
file_uid = models.CharField(max_length = 16)
file_name = models.CharField(max_length = 255)
file_size = models.CharField(max_length = 255)
file_document = models.FileField(upload_to='uploaded_files/')
uploaded_on = models.DateTimeField(auto_now_add=True)
uploaded_by = models.CharField(max_length=16)
Now it's clearly plain that we don't need to create all the fields in the form and that most them can be received from the file itself (like the name, size). for other attrs like uid and uploaded by those also will be added by the backend. So that's where I am stuck. I have searched for 2 days straight and still couldn't find a proper solution.
As of now this is my views.py
def uploadView(request):
if(request.method == 'POST'):
form = FileUploadForm(request.POST, request.FILES)
uploaded_file = request.FILES['uploaded_file']
file_dict = {
'file_uid' : get_random_string(length=10),
'file_name' :uploaded_file.name,
'file_size' : uploaded_file.size,
'file_document' : request.FILES['uploaded_file'],
'uploaded_by' : get_random_string(length=10)
}
form = FileUploadForm(data=file_dict)
if form.is_valid():
form.save()
return HttpResponse("You reached here")
else:
return HttpResponse("Your form is invalid")
else:
form = FileUploadForm(request.POST, request.FILES)
return render(request, 'function/upload.html', {
'form':form
})
I don't know if this is correct but as of know the form.isvalid() is false.
here's my forms.py
class FileUploadForm(forms.ModelForm):
file_document = forms.FileField(widget=forms.FileInput(attrs={'name':'uploaded_file'}))
class Meta:
model = Document
fields = ('file_uid', 'file_name', 'file_size', 'file_document', 'uploaded_by')
and my upload page section looks like this
<body>
<h1>Upload a file</h1>
<form action="" method="POST" enctype="multipart/form-data">
{% csrf_token %}
<input type="file" name="uploaded_file">
<button type="submit">Upload</button>
</form>
</body>
If you can mercifully guide me into a proper way of doing this i'll be really gratefull.
Before solution, Here are few issues i found in your code
Major issue is how you tried to update the name of your file_document input, it doesn't work this way. confirm this by inspecting in devtools.
Checkout my answer here to update name attribute of django input form field.
Without updating this, you are not getting file from form.
Not issues just something i would like to point out
def uploadView(request):
if(request.method == 'POST'):
form = FileUploadForm(request.POST, request.FILES)
# your code in between, here the above form is never used and the overridden by the form in next line so why assigning it
form = FileUploadForm(data=file_dict)
# your form.is_valid() code start here
else:
form = FileUploadForm(request.POST, request.FILES)
# This block will only run for GET request, why using request.POST, request.FILES
return render(request, 'function/upload.html', {
'form':form
})
Here is how i got your code working
update FileUploadForm like this
class FileUploadForm(forms.ModelForm):
class Meta:
model = Document
fields = ('file_uid', 'file_name', 'file_size', 'file_document', 'uploaded_by')
# below code is only used to change the name of file_document to uploaded_file
custom_names = {'file_document': 'uploaded_file'}
def add_prefix(self, field_name):
field_name = self.custom_names.get(field_name, field_name)
return super(FileUploadForm, self).add_prefix(field_name)
use form in html like this
<form method="POST" action="" enctype="multipart/form-data">
{% csrf_token %}
{{form.file_document}}
<input type="submit" value="send"/>
</form>
Update view as
def uploadView(request):
if(request.method == 'POST'):
uploaded_file = request.FILES['uploaded_file']
file_dict = {
'file_uid' : 'test1',
'file_name' :uploaded_file.name,
'file_size' : uploaded_file.size,
'uploaded_by' : 'hemant'
}
form = FileUploadForm(file_dict, request.FILES)
if form.is_valid():
form.save()
return HttpResponse("You reached here")
else:
return HttpResponse("Your form is invalid")
else:
form = FileUploadForm()
return render(request, 'function/upload.html', {
'form':form
})

ValueError: Cannot assign value: must be an instance

I have four fields in a model, one of which is a foreign key field and the other three are m2m fields. The form is opened in the modal, but the data is not being saved, Error given below. I don't understand what I did wrong. I would be very grateful for a little help.
Model:
class ProductAttributes(models.Model):
product = models.ForeignKey('Product', blank=True, null=True, on_delete=models.SET_NULL)
size = models.ManyToManyField('ProductSize', blank=True)
colour = models.ManyToManyField('ProductColour', blank=True)
cupsize = models.ManyToManyField('ProductCupSize', blank=True)
def __str__(self):
return self.product
Form:
class ProductAttributesForm(forms.ModelForm):
product = forms.IntegerField(label=('ID'),required=True, disabled=True)
size = forms.ModelMultipleChoiceField(queryset=ProductSize.objects.all(),widget=Select2MultipleWidget, required=False)
colour = forms.ModelMultipleChoiceField(queryset=ProductColour.objects.all(),widget=Select2MultipleWidget, required=False)
cupsize = forms.ModelMultipleChoiceField(queryset=ProductCupSize.objects.all(),widget=Select2MultipleWidget, required=False)
class Meta:
model = ProductAttributes
fields = ['product','size','colour','cupsize']
Template:
{% load crispy_forms_tags %}
<form id="Form" method="post" action="{% url 'accpack:products_attributes_create' product %}" class="js-product-create-form col s12" >
{% csrf_token %}
{% crispy form form.helper %}
</form>
View:
def save_attribute_form(request, form, template_name, pk):
data = dict()
if request.method == 'POST':
if form.is_valid():
form.save()
data['form_is_valid'] = True
else:
data['form_is_valid'] = False
context = {'form': form, 'product':pk}
data['html_form'] = render_to_string(template_name, context, request=request)
return JsonResponse(data)
def attribute_create(request, pk):
if request.method == 'POST':
form = ProductAttributesForm(request.POST, initial={'product': pk})
else:
form = ProductAttributesForm(initial={'product': pk})
return save_attribute_form(request, form, 'main/products/partial_product_attribute_form.html', pk)
ajax:
var saveForm = function () {
var form = $(this);
$.ajax({
url: form.attr("action"),
data: form.serialize(),
type: form.attr("method"),
dataType: 'json',
success: function (data) {
if (data.form_is_valid) {
$("#modal-product_attribute").modal("hide");
console.log(data.form_data);
}
else {
$("#modal-product_attribute .modal-content").html(data.html_form);
}
}
});
return false;
$("#modal-product_attribute").on("submit", ".js-product-create-form", saveForm);
error:
File "C:\ProgramData\Anaconda3\envs\djangoproject\lib\site-packages\django\db\models\fields\related_descriptors.py", line 220, in __set__
self.field.remote_field.model._meta.object_name,
ValueError: Cannot assign "111": "ProductAttributes.product" must be a "Product" instance.
You have an error in your forms.py.
class Meta:
model = ProductSize
fields = ['product','size','colour','cupsize']
Here, the model should be
model = ProductAttributes
Since the model you specified here ProductSize does exist, submitting form will just create another instance to ProductSize model without those specific fields and error messages. You can check your admin page.
EDIT ******
2. Based on what you added in the question and the error message, it looks like in attribute_create you are passing product's pk. Now in the attribute_create, you are passing initial dict {'product': pk}. This is wrong, because, in your ProductAttributesForm, the product field should be an instance rather than a pk.
You need to refer product as
product = Product.objects.filter(pk=pk)
initial = {'product':product}
The current error message will be gone, but you will have other errors.

Form not registering photo Django 3.0

I'm trying to get a photo to upload and the form is not seeing the file and in the form.errors, it says 'this field is required'. I've tried using picture = request.FILES['picture'] to no avail and have also tried picture = form.FILES['picture'] as well as picture = request.POST.FILES['picture'] and picture = form.cleaned_data.get('picture') What am I missing? Let me know if you need anymore information
template
{% block content %}
<h1>Create {{post_type.title}} Post</h1>
<form method="post" enctype="multipart/form-data">
{% csrf_token %}
{{form.as_p}}
<button type='submit'>Submit</button>
</form>
{% endblock %}
forms.py
class PicturePostForm(forms.ModelForm):
class Meta:
model = PicturePost
fields = ('description', 'privacy', 'picture', 'categories')
views.py
#login_required()
def picture_post(request):
"""
Creates new picture post
"""
if request.method == "POST":
form = PicturePostForm(request.POST)
print("is post")
if form.is_valid():
print("is valid") # this never gets printed because of the 'this field is required' error
author = request.user
content = form.cleaned_data['description']
category = form.cleaned_data['categories']
picture = form.cleaned_data['picture']
privacy = form.cleaned_data['privacy']
p_post = PicturePost(author=author, description=content, categories=category, picture=picture,privacy=privacy )
p_post.save()
#redirect to last page
return redirect('home')
else:
l = []
for i in form.errors.keys():
l.append(form.errors[i])
return HttpResponse(l)
else:
post_type = 'picture'
form = PicturePostForm()
return render(request, 'create_post.html', {'form': form, 'post_type': post_type})
The corresponding model field
picture = models.ImageField(upload_to=f'profiles/{User}_gallery', max_length=255)
Fixed it by replacing form = PicturePostForm(request.POST) with form = PicturePostForm(request.POST, request.FILES)
I have tried to complete the code before, please following
views
#login_required()
def picture_post(request):
"""
Creates new picture post
"""
form = PicturePostForm(request.POST or None, request.FILES or None)
if request.method == "POST":
if form.is_valid():
# instance new object p_post (this best practice if using forms.ModelForm)
# commit=False (to save data on ram/memory device without database/hardrive)
p_post = form.save(commit=False)
# assign author attribute from thr current user session
p_post.author = request.user
# commit=True to move/save data from memory to harddrive
p_post.save() # p_post.save(commit=True)
return redirect('home')
else:
l = []
for i in form.errors.keys():
l.append(form.errors[i])
return HttpResponse(l)
post_type = 'picture'
return render(request, 'create_post.html', {'form': form, 'post_type': post_type})

Django TypeError, invite users to 'team'

I want to signed in user to be able to invite users to a 'team', where the teams they can select from are only those they are a part of. I keep getting the same error (init() missing 1 required positional argument: 'user') when I try and output a list of all teams in model UserTeams where the userID = current logged in user.
My view:
def invite(request):
if request.method == 'POST':
form = InvitePlayerForm(request.POST)
if form.is_valid():
userteam = form.save(commit=False)
userteam.save()
else:
form = InvitePlayerForm()
query = UserTeams.objects.all()
return render(request, 'teammanager/invite.html', {
"invite": query,
"form": form
})
My Form:
class InvitePlayerForm(forms.ModelForm):
class Meta:
model = UserTeams
fields = ['userID','teamID']
def __init__(self,user,*args,**kwargs):
super (InvitePlayerForm,self ).__init__(user,*args,**kwargs)
self.fields['teamID'].queryset = Team.objects.filter(id__in =
UserTeams.objects.filter(userID = user))
My UserTeams model:
class UserTeams(models.Model):
userID = models.ForeignKey(User,on_delete=models.CASCADE)
teamID = models.ForeignKey(Team,on_delete=models.CASCADE)
My HTML:
<html>
<body>
<h4>Invite players to your team</h4>
<form method="post">
{% csrf_token %}
{{ form.as_p }}
<input class="btn btn-success" type="submit" value="Add Player"></button>
</form>
You've redefined the signature of the form so that it accepts a user element. But you haven't actually passed that user when you create the form. How else are you expecting it to get into the form?
if request.method == 'POST':
form = InvitePlayerForm(request.user, request.POST)
...
else:
form = InvitePlayerForm(request.user)
(Note also, your queryset would be better as Team.objects.filter(userteam__UserId=user.)