everyone!
I want to display to forms in a template
My forms are:
class ContactForm(forms.Form):
contact_name = forms.CharField(
required=True)
contact_email = forms.EmailField(
required=True)
contact_phone = forms.CharField(
required=True)
subject = forms.CharField(
required=True)
message = forms.CharField(
required=True,
widget=forms.Textarea)
class CVCreateForm(forms.ModelForm):
class Meta:
model = CV
fields = '__all__'
And I have two FormViews:
class ContactView(FormView):
form_class = ContactForm
succes_url = reverse_lazy('webpage:home')
def form_valid(self, form):
context = super(ContactView, self).form_valid(form)
contact_email = form.cleaned_data['contact_email']
subject = form.cleaned_data['subject']
message = 'Name: {}\nPhone:{}\n{}'.format(form.cleaned_data['contact_name'], form.cleaned_data['contact_phone'], form.cleaned_data['message'],)
send_mail(subject,
message,
contact_email,
['maumg1196#gmail.com'])
return context
class CVCreateView(FormView):
form_class = CVCreateForm
succes_url = reverse_lazy('webpage:home')
def form_valid(self):
context = super(CVCreateView, self).form_valid(form)
form_owner = form.cleaned_data['owner']
form_cv = form.cleaned_data['cv']
form_email = form.cleaned_data['email']
send_mail('Curriculum Vitae',
form_cv,
form_email,
['maumg1196#gmail.com'])
cv = CV(owner=form_owner, email=form_email, cv=form_cv)
cv.save()
return context
(Note: In the second form the 'form_cv' is gonna be a PDF file I think that isn't a problem to send the email but I don't know very well.)
I want to display this two FormViews in a TemplateView
Thanks :)
In your TemplateView you need to just need to pass the two forms in the context as follows:
from django.views.generic import TemplateView
from .forms import ContactView, CVCreateView
class MyTemplateView(TemplateView):
template_name = 'path/to/my_template.html'
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
context['contact_form'] = ContactView()
context['cv_form'] = CVCreateView()
return context
In the template you set the form action attribute to point to the URL of the appropriate view, ContactView or CVCreateView, so something like this:
<form action="{% url 'contact_form' %}" method="POST">
{{ contact_form }}
</form>
<form action="{% url 'cv_form' %}" method="POST">
{{ cv_form }}
</form>
Hope this helps?
Related
View.py
class Register(TemplateView):
template_name = 'registration.html'
def get(self, request, *args, **kwargs):
form = CreateForm()
return render(request, self.template_name, {'form': form})
#staticmethod
def post(request):
try:
data = request.POST.get
user = User(
first_name=data('first_name'),
last_name=data('last_name'),
username=data('username').strip(),
email=data('email'),
)
user.set_password(data('password').strip())
user.save()
request.session["user_id"] = user.id
return HttpResponse(' Save successfully ')
except Exception as c:
return HttpResponse("Failed : {}".format(c), 500)
Form.py
role_choice= (("Customer", "Customer"), ("Employee", "Employee"))
class CreateForm(forms.Form):
first_name = forms.CharField(label="Enter Your First Name", max_length=30, required=True)
last_name = forms.CharField(label="Enter Your Last Name", max_length=30, required=True)
username = forms.CharField(required=True, widget=forms.TextInput())
email = forms.CharField(required=True, widget=forms.TextInput())
password = forms.CharField(required=True, widget=forms.PasswordInput())
role = forms.ChoiceField(choices=role_choice, widget=forms.RadioSelect())
class Customer(forms.Form):
contact = forms.IntegerField(label="Enter your contact number", required=True, )
amount = forms.IntegerField(required=True, min_value=500)
type = forms.ChoiceField(choices=choice)
Model.py
class Customers(models.Model):
user = models.ForeignKey(User, on_delete=models.CASCADE)
contact = models.BigIntegerField()
amount = models.BigIntegerField()
type = models.CharField(max_length=1)
Template
{% extends "home.html" %}
{% load crispy_forms_tags %}
{% block title %}Create Account{% endblock %}
{% block content %}
<div>
{% csrf_token %}
{{ form|crispy }}
<button type="submit">Submit</button><br>
</div>
{% endblock %}
After the registration when user select customer option after sumbit the form i go to customer page if user select employee option he/she go to employee page but i don't know how to do this
First of all, I strongly advice not to write all the views, etc. yourself. Django already has a lot of tooling inplace. It has a UserCreationForm [Django-doc] that can be slighly modified. For example:
# app/forms.py
from django import forms
from django.contrib.auth.forms import UserCreationForm
class RoleUserCreationForm(UserCreationForm):
ROLES = (
('Customer', 'Customer'),
('Employee', 'Employee')
)
role = forms.ChoiceField(choices=ROLES, widget=forms.RadioSelect())
class Meta(UserCreationForm.Meta):
fields = (*UserCreationForm.Meta.fields, 'first_name', 'last_name')
We can here thus add the extra fields for first_name and last_name as well.
Now we can make use of this in a CreateView [Django-doc], and override the form_valid(..) method [Django-doc]:
# app/views.py
from app.forms import RoleUserCreationForm
from django.contrib.auth import get_user_model
from django.shortcuts import redirect
from django.views.generic.edit import CreateView
class RegisterView(CreateView):
model = get_user_model()
form_class = RoleUserCreationForm
def form_valid(self, form):
request.session['user_id'] = self.object.id
if form.cleaned_data['role'] == 'Customer':
return redirect('name-of-customer-view')
else:
return redirect('name-of-employee-view')
Where you replace the 'name-of-customer-view' and 'name-of-employee-view' with the name of these views respectively.
I Need to Restrict the Options in a Select Field of a Django Form for not staff users.
So these are my models.py:
#!/usr/bin/python3
from django.db import models
from django.urls import reverse
class Extension(models.Model):
username = models.CharField(primary_key=True, max_length=200, help_text='')
callerid = models.CharField(max_length=200, help_text='')
extension = models.CharField(max_length=3, help_text='')
firstname = models.CharField(max_length=200, help_text='')
lastname = models.CharField(max_length=200, help_text='')
password = models.CharField(max_length=200, help_text='')
context = models.ForeignKey('Context', on_delete=models.SET_NULL, null=True)
def get_absolute_url(self):
return reverse('extension-detail', args=[str(self.username)])
def my_get_absolute_url(self):
return reverse('my-extension-detail', args=[str(self.username)])
def __str__(self):
return self.username
class Context(models.Model):
name = models.CharField(primary_key=True, max_length=200, help_text='')
countryprefix = models.CharField(max_length=200, help_text='')
cityprefix = models.CharField(max_length=200, help_text='')
number = models.CharField(max_length=200, help_text='')
extensionsfrom = models.CharField(max_length=200, help_text='')
extensionstill = models.CharField(max_length=200, help_text='')
portscount = models.CharField(max_length=200, help_text='')
def get_absolute_url(self):
return reverse('context-detail', args=[str(self.name)])
def my_get_absolute_url(self):
return reverse('my-context-detail', args=[str(self.name)])
def __str__(self):
return self.name
views.py:
#!/usr/bin/python3
from django.contrib.auth.mixins import LoginRequiredMixin, PermissionRequiredMixin
from django.contrib.auth.models import Permission
from catalog.models import Extension, Context
from django.shortcuts import render
from django.urls import reverse_lazy
from django.views.generic.edit import CreateView, UpdateView, DeleteView
from django.views.generic.detail import DetailView
from django.views.generic.list import ListView
class ExtensionCreate(LoginRequiredMixin, PermissionRequiredMixin, CreateView):
model = Extension
fields = '__all__'
permission_required = 'catalog.add_extension'
class ExtensionUpdate(LoginRequiredMixin, PermissionRequiredMixin, UpdateView):
model = Extension
fields = '__all__'
permission_required = 'catalog.change_extension'
class ExtensionDelete(LoginRequiredMixin, PermissionRequiredMixin, DeleteView):
model = Extension
success_url = reverse_lazy('extensions')
permission_required = 'catalog.delete_extension'
urls.py:
#!/usr/bin/python3
from . import views
from django.urls import path
urlpatterns = [
path('', views.index, name='index'),
path('extensions/', views.ExtensionListView.as_view(), name='extensions'),
path('extension/<str:pk>', views.ExtensionDetailView.as_view(), name='extension-detail'),
path('extension/create/', views.ExtensionCreate.as_view(), name='extension-create'),
path('extension/<str:pk>/update/', views.ExtensionUpdate.as_view(), name='extension-update'),
path('extension/<str:pk>/delete/', views.ExtensionDelete.as_view(), name='extension-delete'),
path('myextensions/', views.ExtensionsByUserListView.as_view(), name='my-extensions'),
path('myextension/<str:pk>', views.ExtensionsByUserDetailView.as_view(), name='my-extension-detail'),
path('contexts/', views.ContextListView.as_view(), name='contexts'),
path('context/<str:pk>', views.ContextDetailView.as_view(), name='context-detail'),
path('context/create/', views.ContextCreate.as_view(), name='context-create'),
path('context/<str:pk>/update/', views.ContextUpdate.as_view(), name='context-update'),
path('context/<str:pk>/delete/', views.ContextDelete.as_view(), name='context-delete'),
path('mycontexts/', views.ContextByUserListView.as_view(), name='my-contexts'),
path('mycontext/<str:pk>', views.ContextByUserDetailView.as_view(), name='my-context-detail'),
]
template:
{% extends "base_generic.html" %}
{% block content %}
<form action="" method="post">
{% csrf_token %}
<table>
{{ form.as_table }}
</table>
<input type="submit" value="Submit">
</form>
{% endblock %}
In this is how it looks like:
The Username is always the same as one of the contexts.
Only Staff User can create a new Context and new Users.
The users then should add their extensions.
While employees should be able to select the context when creating a new extension, customers should only be able to see or select their context in the list.
Therefore it is needed to filter the Select-attribute for non-staff members so that only the user's context is visible, which is equal to his Username.
Alternatively, I want to prepopulate and hide the context form field with the Username (=own context)
How can I do either of this in the easiest way possible?
Here is what I tried myself so far:
Like described in this how-to: https://developer.mozilla.org/en-US/docs/Learn/Server-side/Django/Forms#Renew-book_form_using_a_Form_and_function_view I Defined a Form in forms.py:
#!/usr/bin/python3
from django import forms
class MyExtensionCreateForm(forms.Form):
# username = forms.CharField(help_text="")
# callerid = forms.CharField(help_text="")
# context = forms.CharField(help_text="")
firstname = forms.CharField(help_text="")
lastname = forms.CharField(help_text="")
extension = forms.CharField(help_text="")
password = forms.CharField(help_text="")
def clean_data(self):
data = self.cleaned_data
# Remember to always return the cleaned data.
return data
I then added the folowing to the views.py:
from django.http import HttpResponseRedirect
from django.shortcuts import get_object_or_404
from django.urls import reverse
from catalog.forms import MyExtensionCreateForm
def MyExtensionCreate(request):
# extension = get_object_or_404(Extension)
# If this is a POST request then process the Form data
if request.method == 'POST':
# Create a form instance and populate it with data from the request (binding):
form = MyExtensionCreateForm(request.POST)
# Check if the form is valid:
if form.is_valid():
# process the data in form.cleaned_data as required
form.firstname = form.cleaned_data['firstname']
form.lastname = form.cleaned_data['lastname']
form.extension = form.cleaned_data['extension']
form.password = form.cleaned_data['password']
# Prepopulated Fields
form.context = request.user
form.callerid = str(form.cleaned_data['firstname'])+" "+str(form.cleaned_data['lastname'])+" "+str(form.cleaned_data['extension'])
form.username = str(request.user)+"_"+str(form.cleaned_data['extension'])
form.save()
# redirect to a new URL:
return HttpResponseRedirect(reverse('my-extensions'))
# If this is a GET (or any other method) create the default form.
else:
form = MyExtensionCreateForm({'context': request.user})
context = {
'form': form,
}
return render(request, 'catalog/extension_form-by-user.html', context)
# class MyExtensionCreate(LoginRequiredMixin, CreateView):
# model = Extension
# fields = '__all__'
# form_class = MyExtensionCreateForm
Then I added a new URL to URL patterns in urls.py and added the new Link to the base_generic.html
path('myextensions/create/', views.MyExtensionCreate, name='my-extension-create'),
<li>Add Extension</li>
I can view the form, and if I add the context field to the visible form fields, I can see that the context will initially fill with the logged-in username (See First Picture Below). But as soon as I submit the form I'll get Error's no matter what I try, So basically the GET is working, but the POST isn't really.
See Folowing Pictures:
I was able to Filter the Choices by the Username in the ModelForm but since then I'm not able to save the form to the database anymore.
Here is the new Stack Post with the Resolution of this Post here and the new Question/Problem.
Django: saving the Form does not work (The ModelForm Filters the ForeignKey choices by request.user)
So I have a student model which inherits from AbstractUser. I used 2 forms in one view for registration since I needed email, name and surname to be in my student database (as well as other fields). Now I'm trying to make an update profile view, with 2 forms that I made especially for updating the info. But I think I'm getting it wrong.. might need a little help here. I need the student to be able to update his email (which is from User model) and his photo, phone, name and surname (which are in Student model).
<form method="POST" action="{% url 'profile_edit' %}" class="" >
{% csrf_token %}
{{ form.as_p }}
<button type="submit">Save</button>
</form>
def profile_edit(request):
user = request.user
form1 = UserEditForm(request.POST or None, initial={'email': user.email,
})
form2 = StudentEditForm(request.POST or None, initial={'name': user.student.name,
'surname': user.student.surname,
'phone': user.student.phone,
'photo': user.student.photo})
if request.method == 'POST':
if form1.is_valid() and form2.is_valid():
user.email = request.POST['name']
user.student.name = request.POST['name']
user.student.surname = request.POST['surname']
user.student.phone = request.POST['phone']
user.student.photo = request.POST['photo']
user.save()
return render(request, 'index.html')
context = {
"form1": form1,
"form2": form2
}
return render(request, "registration/profile_edit.html", context)
class UserForm(forms.ModelForm):
email = forms.EmailField(required=True)
password = forms.CharField(label='Password', max_length=32, required=True, widget=forms.PasswordInput)
confirm_password = forms.CharField(label='Confirm', max_length=32, required=True, widget=forms.PasswordInput,
help_text="Passwords must match!")
class StudentForm(forms.ModelForm):
name = forms.CharField(max_length=30, required=True)
surname = forms.CharField(max_length=50, required=True)
student_ID = forms.CharField(required=True, max_length=14, min_length=14)
photo = forms.ImageField(required=True)
phone = forms.CharField(max_length=15, required=True)
class Meta:
model = Student
fields = ('name', 'surname', 'phone', 'student_ID', 'photo')
class UserEditForm(forms.ModelForm):
email = forms.EmailField(required=False)
class Meta:
model = User
fields = ('email',)
class StudentEditForm(forms.ModelForm):
name = forms.CharField(max_length=30)
surname = forms.CharField(max_length=50)
photo = forms.ImageField(required=False)
phone = forms.CharField(max_length=15, required=False)
class Meta:
model = Student
fields = ('name', 'surname', 'phone', 'photo')
Problem is that I am getting no form, so I am either doing something wrong in the view, either the forms.
<form method="POST" action="{% url 'profile_edit' %}" class="" >
{% csrf_token %}
{{ form1.as_p }}
{{ form2.as_p }}
<button type="submit">Save</button>
</form>
according to your context the names of your forms are form1 and form2, so form only wont display any form
You don't need two forms. I have answered your previous question which led to this question.
It will save you from a lot of unnecessary Code.
I am new to Django and need a help.
I want to allow users to update their account data using form, but struggle with associating Django User model with my UserProfile model, which extends default model with some additional fields.
I found, that solution is to create my own model form, but unfortunately I'm not exactly sure how to implement it.
models.py:
class UserProfile(models.Model):
user = models.OneToOneField(User)
description = models.CharField(max_length=100, default='')
city = models.CharField(max_length=100, default='')
website = models.URLField(default='')
phone = models.IntegerField(default=0)
image = models.ImageField(upload_to='profile_image', blank=True)
def __str__(self):
return self.user.username
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):
image = forms.ImageField(required=False)
city = forms.CharField(required=False)
class Meta:
model = User
fields = (
'email',
'first_name',
'last_name',
'password',
'image',
'city'
)
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)
edit_profile.html:
<form method="post">
{% csrf_token %}
{{ form.as_p }}
<button type="submit">Submit</button>
</form>
You are looking for Inline formsets. Just read the docs, it's pretty simple.
I'm trying to user Django model formset factory to render a template where a user can add images and change the images they have uploaded(very similar to what can be done in the admin). I currently can render the template and its correct fields to the template. What I cannot do is have the user preselected(want currently logged in) and when I refresh the page the image will be posted again(not sure if this is preventable). Below is my code. Thanks!
Model:
class Image(models.Model):
user = models.ForeignKey(User)
image = models.ImageField(upload_to=content_file_name, null=True, blank=True)
link = models.CharField(max_length=256, blank=True)
Form:
class ImageForm(forms.ModelForm):
image = forms.ImageField(label='Image')
class Meta:
model = Image
fields = ('image',
'link',
)
View:
#login_required
def register(request):
user_data = User.objects.get(id=request.user.id)
ImageFormSet = modelformset_factory(Image,
fields=('user', 'image', 'link'), extra=3)
if request.method == 'POST':
print '1'
formset = ImageFormSet(request.POST, request.FILES, queryset=Image.objects.all())
if formset.is_valid():
formset.user = request.user
formset.save()
return render(request, 'portal/register.html', {'formset': formset, 'user_data': user_data})
else:
print '2'
formset = ImageFormSet(queryset=Image.objects.all())
return render(request, 'portal/register.html', {'formset': formset, 'user_data': user_data})
Template:
<form id="" method="post" action=""
enctype="multipart/form-data">
{% csrf_token %}
{{ formset.management_form }}
{% for form in formset %}
{{ form }}
{% endfor %}
<input type="submit" name="submit" value="Submit" />
let me explain the way you can do it.
MODELS
from django.utils.text import slugify
from django.db import models
from custom_user.models import AbstractEmailUser
# User model
class UserModel(AbstractEmailUser):
full_name = models.CharField(max_length=255)
def __str__(self):
return str(self.id)
# Function for getting images from instance of user
def get_image_filename(instance, filename):
title = instance.id
slug = slugify(title)
return "user_images/%s-%s" % (slug, filename)
# Save images with user instance
class UserImages(models.Model):
user = models.ForeignKey('UserModel', db_index=True, default=None)
image = models.ImageField(upload_to=get_image_filename, verbose_name='Image', db_index=True, blank=True, null=True)
In forms it's a just a two form, one for model User, other for UserImages model.
# Images forms
class ImageForm(forms.ModelForm):
image = forms.ImageField(label='Image', required=False)
class Meta:
model = UserImages
fields = ('image',)
# User form
class UserForm(forms.ModelForm):
full_name = forms.CharField(required=True)
class Meta:
model = UserModel
fields = ('full_name','email','password',)
And in Views for post you can do something like this
# View
from models import *
from forms import *
#csrf_protect
def post_view(request):
template = 'some_template.html'
ImageFormSet = modelformset_factory(UserImages, form=ImageForm, extra=15)
if request.method == 'POST':
user_form = UserForm(request.POST, prefix='form1')
formset = ImageFormSet(request.POST, request.FILES, queryset=UserImages.objects.none(), prefix='form2')
if user_form.is_valid() and formset.is_valid():
# Save User form, and get user ID
a = user_form.save(commit=False)
a.save()
images = formset.save(commit=False)
for image in images:
image.user = a
image.save()
return HttpResponseRedirect('/success/')
else:
user_form = UserForm(prefix='form1')
formset = ImageFormSet(queryset=UserImages.objects.none(), prefix='form2')
return render(request, template, {'form_user':user_form,'formset':formset})
In template you are doing the right thing.