Django Model Multi Select form not rendering properly - python

I am trying to display all the categories to appear as a list that I can click and select from, just an exact replica of what I have in my admin panel, but it still display's as a list that isn't clickable.
forms.py
class ProfileEditForm(forms.ModelForm):
"""
Form for updating Profile data
"""
class Meta:
model = Profile
fields = [
"first_name",
"last_name",
"about_me",
"profile_image",
"username",
"email",
"categories",
]
first_name = forms.CharField(label="First Name", max_length=63, required=False)
last_name = forms.CharField(label="Last Name", max_length=63, required=False)
about_me = forms.CharField(label="About Me", max_length=511, required=False)
email = forms.EmailField(label="Email", disabled=True)
username = forms.CharField(label="Username", disabled=True)
profile_image = forms.ImageField(required=False)
categories = forms.ModelMultipleChoiceField(
queryset=Category.objects.all(),
required=False,
widget=forms.CheckboxSelectMultiple(),
)
profile.models.py
class Profile(models.Model):
user = models.OneToOneField(User, on_delete=models.CASCADE, related_name="profile")
first_name = models.CharField(max_length=63, blank=False)
last_name = models.CharField(max_length=63, blank=False)
about_me = models.CharField(max_length=511, blank=True)
categories = models.ManyToManyField(
Category, related_name="user_categories", symmetrical=False
)
categories.models.py
from django.db import models
class Category(models.Model):
name = models.CharField(max_length=63)
created = models.DateTimeField(auto_now_add=True, blank=True, null=True)
last_modified = models.DateTimeField(auto_now=True, blank=True, null=True)
def __str__(self):
return self.name
def __unicode__(self):
return self.name
class Meta:
verbose_name_plural = "Categories"
settings.html
<div class='row'>
<div class="col s12 m6">
{{form.categories.errors}}
{{form.categories.label_tag}}
{{form.categories}}
</div>
</div>
What I hope to achieve
What I get

You need to create the form itself:
<form method='post'>
</form>
And print each field on a new line:
{{ form.as_p }}
is a security check.
{% csrf_token %}
In the view, I left get_context_data. In it, you can add values ​​to the context, for example, like this:
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
context['rubrics'] = Car.objects.all()
Replace bboard with the name of the folder where your templates are placed.
I have this: templates/bboard which are in the application folder.
In the view for the form, the CreateView class is used, in which: template_name - the name of the template for displaying the page, form_class - the form class is indicated, success_url - where to return in case of successful saving of the form (in this case, this is the same page with the form), get_context_data - the template context (you can print it out and see what's inside).
And if your model has fields: first_name, last_name, about_me, email, username, profile_image, then it is enough that you have specified the fields variable in the class Meta class. You don't need to re-create them in the form.
template_name = 'bboard/tam_form.html'#bboard replace with your prefix
Templates
<form method='post'>
{{form.categories.errors}}
{% csrf_token %}
{{ form.as_p }}
<input type="submit" value='adding'>
</form>
views.py
from .forms import *
from django.views.generic.edit import CreateView
from django.urls import reverse_lazy
class Profile(CreateView):
template_name = 'bboard/settings.html'#bboard replace with your prefix
form_class = ProfileEditForm
success_url = reverse_lazy('test')
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
return context
urls.py
from django.urls import path
from .views import *
urlpatterns = [
path('test/', Profile.as_view(), name='test'),
]
Update 13.11.2022
This is how my form looks like when I go to the address:
http://localhost:8000/test/
But the form is not submitted. I don't have much experience with this. I can assume that forms.ModelForm expects that the model has such fields, because if you delete the lines with email, username, profile_image and also remove them from the fields and add 'user' to the field, then the data will be saved in the database (checked).
As I said earlier, if the fields are declared in fields, then you do not need to define them again (if you leave them, the form will also be saved). This is what the form class looks like:
class ProfileEditForm(forms.ModelForm):
class Meta:
model = Profile
fields = [
'user',
'first_name',
'last_name',
'about_me',
'categories',
]
categories = forms.ModelMultipleChoiceField(
queryset=Category.objects.all(),
required=False,
widget=forms.CheckboxSelectMultiple(),
)

Related

Django Adding User details to a UserPost List View

I have a UserPost List View which is a view for a specific user's posts. I am looping the posts of this specific user but I want to add this user's profile details like profile image and other details like email.
So, I am not sure on how to add the user details of the user's post names as designer not the logged-in user.
I can add the user/designer details in every looped post but I don't want it to be repeated with every post I just want it to appear once just like {{ view.kwargs.username }} as this page is realted only to this user/designer
Here is the models.py
class Post(models.Model):
designer = models.ForeignKey(User, on_delete=models.CASCADE, related_name="post")
title = models.CharField(max_length=100, unique=True)
here is the profile model related to every user
class Profile(models.Model):
user = models.OneToOneField(User, on_delete=models.CASCADE)
image = models.ImageField(default='default.jpg', upload_to='profile_pics')
class UserRegisterForm(UserCreationForm):
email = forms.EmailField()
first_name = forms.CharField()
last_name = forms.CharField()
class Meta:
model = User
fields = ['username', 'first_name', 'last_name',
'email']
here is the views for the userpostlist which is filtered by a specific user/designer not the logged in user
class UserPostListView(ListView):
model = Post
template_name = "user_posts.html"
context_object_name = 'posts'
queryset = Post.objects.filter(admin_approved=True)
paginate_by = 6
def get_queryset(self):
user = get_object_or_404(User, username=self.kwargs.get('username'))
return Post.objects.filter(designer=user, admin_approved=True).order_by('-date_posted')
def get_context_data(self, *args, **kwargs):
context = super().get_context_data(*args, **kwargs)
has_items = Item.objects.filter(designer__username=self.kwargs['username']).exists()
context['has_items'] = has_items
return context
here is the template
{% if has_items %}
<h1 class="display-4">Hello, this is {{ view.kwargs.username }} </h1>
<img class="profile_image" src={{ designer.profile.image.url }}> <----------- I want it to appear
{{ designer.email }}<----------- I want it to appear
{% else %}
Show nothing
{% endif %}
{% for post in posts %}
Post details
{% endfor %}
You can add this to the context:
from django.contrib.auth import get_user_model
class UserPostListView(ListView):
model = Post
template_name = 'user_posts.html'
context_object_name = 'posts'
queryset = Post.objects.filter(admin_approved=True)
paginate_by = 6
def get_queryset(self, *args, **kwargs):
return super().get_queryset(*args, **kwargs).filter(
designer__username=self.kwargs['username']
).order_by('-date_posted')
def get_context_data(self, *args, **kwargs):
context = super().get_context_data(*args, **kwargs)
context['designer'] = designer = get_object_or_404(
get_user_model(),
username=self.kwargs['username']
)
context['has_items'] = Item.objects.filter(designer=designer).exists()
return context

Django UpdateView with three different modelforms

I have a django UpdateView which needs to inherit three different models and different models. CreateView is working fine with three different modelforms.
models.py:
class Employee(models.Model):
"""
Create employee attributes
"""
employee_user = models.OneToOneField(settings.AUTH_USER_MODEL, on_delete=models.CASCADE, null=True)
e_id = models.IntegerField(unique=True, null=True, blank=True)
first_name = models.CharField(max_length=128,blank=True)
last_name = models.CharField(max_length=128, blank=True)
.....
class WorkExperience(models.Model):
"""
Stores employee previous work experiences
"""
employee = models.ForeignKey('Employee', related_name='we_employee', on_delete=models.CASCADE, null=True)
previous_company_name = models.CharField(max_length=128, null=True)
job_designation = models.CharField(max_length=128, null=True)
from_date = models.DateField(null=True)
......
class Education(models.Model):
"""
Stores employee education background
"""
employee = models.ForeignKey('Employee', related_name='edu_employee', on_delete=models.CASCADE, null=True)
institution_name = models.CharField(max_length=128, null=True)
degree = models.CharField(max_length=128, null=True)
.....
views.py:
class EmployeeUpdateView(LoginRequiredMixin,UpdateView):
"""
Update a created a employee
"""
login_url = '/authentication/login/'
template_name = 'employee/employee_add_form.html'
form_class = EmployeeAddModelForm
work_form_class = WorkExperienceForm
education_form_class = EducationForm
queryset = Employee.objects.all()
def form_valid(self, form):
print(form.cleaned_data)
return super().form_valid(form)
def get_object(self):
id_ = self.kwargs.get("id")
return get_object_or_404(Employee, id=id_)
WHen I go to Update view, I am only able to update EmployeeAddModelForm values. But other form's(WorkExperienceForm, EducationForm ) fields do not appear let alone edit the values of the fields.
I suppose my views.py is not correct.
I need suggestion to correct my updateview.
If you want to put multiple forms in one HTML file, in my way, write as follows.
class EmployeeUpdateView(LoginRequiredMixin,UpdateView):
login_url = '/authentication/login/'
def form_valid(self, form):
print(form.cleaned_data)
return super().form_valid(form)
def get(self, request, *args, **kwargs):
id_ = self.kwargs.get("id")
user = Employee.objects.get(id=id_)
work = WorkExperience.objects.get(employee=user)
education = Education.objects.get(employee=user)
return render(request, self.template_name, {
'form': EmployeeAddModelForm(instance=user),
'work_form': WorkExperienceForm(instance=work),
'education_form': EducationForm(instance=education)
}
)
def post(self, request):
first_name = request.POST['first_name']
# Your own code...
.....
I think the argument of each form depends on the definition of Form.
And in a very simple way, the HTML file looks like this:
<body>
<form method="post">
{% csrf_token %}
{{ employ_form }}
{{ work_form }}
{{ edu_form }}
<button type="submit">OK</button>
</form?
</body>
</html>
I'm not sure if this is the best option.
How about putting forms into get_context_data?
Something like
context['form1'] = EmployeeAddModelForm()
context['form2] = WorkExperienceForm()
Etc.
Edit:
def get_context_data(self, **kwargs):
context = super(EmployeeUpdateView, self).get_context_data(**kwargs)
context['form'] = EmployeeAddModelForm()
context['form2'] = WorkExperienceForm()
context['form3'] = EducationForm()
return context

compare value of form in view django

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.

Django filter generic form Select attribute from generic class-based view by Username or prepopulate and hide the form Select-attribute

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)

How can I fill a field with current user in form using CreateView/UpdateView in Django?

I've been looking for this for few days and I couldn't solve it, so here is my problem:
I'm trying to create a product using just CreateView in views.py for now (My idea is to create forms and pass everything to a function in views.py), but there is one field that I want it to be auto-filled with the logged user ('owner'). I've tried using the get_initial in the createView for now, but it doesn't work.
I want to say that this it actually creates a form in which I have to fill all the fields and it works fine, but I want to auto-fill the 'owner' field with the current user logged in.
For now I tried to use the get_initial as I said before, but seems that it does not work. I also tried lots of things that I've seen here, in stackoverflow, but any of them worked for me.
Here I put all the relevant code, but if you need anything else please, ask for it and I'll upload it.
This is my views.py:
# view for the product entry page
class ProductCreate(CreateView):
model = Product
fields = ['owner', 'category', 'tag', 'name', 'content_tweet']
success_url = reverse_lazy('index')
def get_form(self, form_class=None):
form = super(ProductCreate, self).get_form(form_class)
return form
def get_initial(self):
return {
'owner': self.request.user,
}
def dispatch(self, request, *args, **kwargs):
if not request.user.is_superuser or request.user.is_vendor:
raise PermissionDenied()
return super().dispatch(request, *args, **kwargs)
This is the model I'm using in models.py:
class Product(models.Model):
owner = models.ForeignKey(CustomUser, on_delete=models.PROTECT)
name = models.CharField(_('Product Name'), max_length=150)
category = models.ManyToManyField(Category)
tag = models.ManyToManyField(Tag)
content_tweet = models.CharField(_('Content Tweet'), max_length=150, blank=True)
content_abstract = models.CharField(_('Content Abstract'), max_length=3000, blank=True)
canvas_1 = models.FileField(upload_to='documents/canvas_1/', blank=True)
price_tweet = models.IntegerField(_('Tweet Price in Tokens'), default=0)
price_abstract = models.IntegerField(_('Abstract Price in Tokens'), default=50)
price_canvas_1 = models.IntegerField(_('Canvas 1 Price in Tokens'), default=500)
it_exist = models.BooleanField(_('is an existing idea?'), default=False)
is_active = models.BooleanField(
_('active'),
default=True,
help_text=_(
'Designates whether this product should be treated as active. '
'Unselect this instead of deleting products.'
),
)
history = HistoricalRecords()
class Meta:
unique_together = ('name', 'owner')
def get_categories(self):
return ",".join([str(p) for p in self.category.all()])
def get_tags(self):
return ",".join([str(p) for p in self.tag.all()])
def __str__(self):
return self.name
And this is the template I'm using (for now) in my XX.html:
{% for field in form %}
<div class="form-group">
<div >
<span class="text-danger la">{{ field.errors }}</span>
</div>
<label >{{ field.label_tag }}</label>
<div class="col-sm-10">{{ field }}</div>
</div>
{% endfor %}
def form_valid(self, form):
form.instance.owner = self.request.user
return super(ProductCreate, self).form_valid(form)
override form_valid method of CreateView as above

Categories

Resources