I have made a select django form with list of images for each user.
How do I take that select request in my views.py ?
I have only managed to create correct that select list but I need to take that select request. But I don't know how.
models.py
class MyModel(models.Model):
user = models.ForeignKey(User, unique=True)
upload = models.ImageField(upload_to='upload')
views.py
#login_required(login_url="login/")
def carlist(request):
Myform = MyModelForm(user=request.user)
return render(request,'about.html',{'Myform':Myform})
select django form :
class MyModelForm(ModelForm):
def __init__(self, *args, **kwargs):
# extract "user" from kwrags (passed upon form init)
if 'user' in kwargs:
self.user = kwargs.pop('user')
super(MyModelForm, self).__init__(*args, **kwargs)
# generate the choices as (display, value).
# Display is the one that'll be shown to user, value is
# the one that'll be sent upon submitting
# (the "value" attribute of <option>)
choices = MyModel.objects.filter(user=self.user).values_list('upload', 'id')
self.fields['upload'].widget = Select(choices=choices)
class Meta:
model = MyModel
fields = ('upload',)
html :
<form class="" action="" method="post" enctype="multipart/form-data">
{% csrf_token %}
{{ Myform}}
<input type="submit" name="" value="Submit">
for example Myform now has a list of user images, which is correct but after that i need the selected images from the form.
Can do it that with my code or not?
Yes you can do it with your code. In your view, you can get it as:
class MyView(View):
def post(self, request):
form = MyModelForm(request.POST, request.FILES)
if form.is_valid():
upload_inst = form.cleaned_data['upload']
...
This will give you the selected image from the form.
If you want to have multiple images being selected, you could try the following:
https://pypi.python.org/pypi/django-multiselectfield/
https://pypi.python.org/pypi/django-select-multiple-field/
Related
My Objective
Access the field name in the Parent Model ParentModel and display its content in a form instance in the template. For example, let the field parent be a foreign key in the ChildModel as described below.
What I have tried
Access the parent field in the form as {{ form.parent.name }} in the template
Errors received
Tried looking up form.parent.name in context
models.py
class ParentModel(models.Model):
name = models.CharField()
def __str__(self):
return self.name
class ChildModel(models.Model):
parent = models.ForeignKey(ParentModel)
def __str__(self):
return self.parent.name
forms.py
class ChildModelForm(ModelForm):
class Meta:
model = ChildModel
fields = '__all__'
widgets = {'parent': forms.Select(),}
views.py
def childView(request, pk):
template = 'template.html'
child = ChildModel.objects.get(parent=pk)
form = ChildModelForm(instance=child)
if request.method == 'POST':
form = ChildModelForm(request.POST, instance=child)
if form.is_valid():
form.save()
else:
form = ChildModelForm(instance=child)
context = {'form': form, }
return render(request, template, context)
template.html
<form method="POST" action="">
{% csrf_token %}
{{form.parent.name}}
<button type="submit">Save</button>
</form>
Now the child model form displays pk I want to display the name of the parent field
I have also tried using this Django access foreignkey fields in a form but it did not work for me.
From my understanding, you want to display the form instance's values. You can do:
form.instance.parent.name
This question have been answered before, e.g here: Proper way to handle multiple forms on one page in Django
So before it gets marked as a duplicate. I'll try to explain why its different.
I've got three tables, Project, ProjectUser and User. ProjectUser is a join table to indicate what users belongs to what project.
I'm trying to create a view that lets users update project details (e.g. name of project), and also add users to the project (which is indicated by a dropdown that shows all available users like the standard one for models with foreign keys in the django admin panel). All works fine until I'm trying to pass an id from the views to the formclass and submit.
views.py
class ProjectUpdateView(UpdateView):
form_class = ProjectUpdateForm
second_form_class = ProjectUserAddForm
template_name = 'projects/project_edit.html'
success_url = reverse_lazy('projects:list')
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
id_ = self.kwargs.get("id")
project = Project.objects.get(id=id_)
if 'form' not in context:
context['form'] = self.form_class()
if 'form2' not in context:
team = Organization.objects.get(id=project.organization_id)
context['form2'] = self.second_form_class(queryset=team) # <-- here is where I wish to pass a queryset, which fails when trying to submit form2.
context['project_users'] = ProjectUser.objects.filter(project__id=project.id).select_related("project")
context['team'] = Organization.objects.get(id=project.organization_id)
return context
def get_object(self):
id_ = self.kwargs.get("id")
return get_object_or_404(Project, id=id_)
def form_invalid(self, **kwargs):
return self.render_to_response(self.get_context_data(**kwargs))
def form_valid(self, form):
project_id = self.kwargs.get("id")
if self.request.POST.get("form2") == 'Add':
ProjectUser.objects.create(user_id=self.request.POST.get("user"), project_id=project_id)
form.save()
success_url = reverse("projects:edit", args=(project_id,))
return HttpResponseRedirect(success_url)
def post(self, request, *args, **kwargs):
# get the user instance
self.object = self.get_object()
# determine which form is being submitted
# uses the name of the form's submit button
if 'form' in request.POST:
# get the primary form
form_class = self.get_form_class()
form_name = 'form'
else:
# get the secondary form
form_class = self.second_form_class
form_name = 'form2'
# get the form
form = self.get_form(form_class)
# validate
if form.is_valid():
return self.form_valid(form)
else:
return self.form_invalid(**{form_name: form})
projects_edit.html
<form action="{% url 'projects:edit' project.id %}" method="post" enctype="multipart/form-data">
{% csrf_token %}
{{form.name|as_crispy_field}}
<input name="form" value="Update" type="submit"></input>
</form>
<form action="{% url 'projects:edit' project.id %}" method="post" enctype="multipart/form-data">
{% csrf_token %}
{{form2.user}}
<input name="form2" value="Add" type="submit"></input>
</form>
forms.py
class ProjectUpdateForm(ModelForm):
class Meta:
model = Project
fields = ["name"]
class ProjectUserAddForm(ModelForm):
def __init__(self, queryset, *args, **kwargs):
super().__init__(*args, **kwargs)
self.fields['user'].queryset = User.objects.filter(organizations_organizationuser__organization__id=queryset.id) # here is where I wish to pass the id of the queryset from the form class
class Meta:
model = ProjectUser
fields = ["user"]
Rendering the forms works just fine with the desired queryset, but when I try to submit the second form (adding a user to the ProjectUserForm, I just get a
__init__() missing 1 required positional argument: 'queryset' error.
Any ideas on how to solve this? Perhaps I'm making it way more complicated than it should
I have also added a screenshot if it helps: https://imgur.com/a/uqu0UeB
In my project, i have a template where i'm trying to put two forms for different use cases. I've never come across this problem before, so i don't really know where to go from here to use two forms in the same page.
At first i thought of creating another view to handle each form, but i think that this solution would create problems with the rendering of my templates, other than not being sustainable if i should have this problem again with another template.
After making some research, i found a solution but it works for class based views, but i'd like to avoid that since my view is already a function based view, and i would have to make a lot of changes in my code.
Would it be possible to solve this problem with a function based view? Every advice is appreciated
First field
class FirstForm(forms.ModelForm):
firstfield = forms.CharField()
secondfield = forms.CharField()
class Meta:
model = MyModel
fields = ("firstfield", "secondfield")
def save(self, commit=True):
send = super(FirstForm, self).save(commit=False)
if commit:
send.save()
return send**
Second Form
class SecondForm(forms.ModelForm):
firstfield = forms.FloatField()
secondfield = forms.Floatfield()
thirdfield = forms.CharField()
class Meta:
model = MyModelTwo
fields = ("firstfield", "secondfield", "thirdfield")
def save(self, commit=True):
send = super(SecondForm, self).save(commit=False)
if commit:
send.save()
return send
Template
<h3> First Form </h3>
<form method="post" novalidate>
{% csrf_token %}
{% include 'main/includes/bs4_form.html' with form=form %}
<button type="submit" class="btn btn-danger" style="background-color: red;">SUBMIT</button>
</form>
<h3> Second Form </h3>
<form method="post" novalidate>
{% csrf_token %}
{% include 'main/includes/bs4_form.html' with form=form %}
<button type="submit" class="btn btn-danger" style="background-color: red;">SUBMIT</button>
</form>
EDIT: my view:
def myview(request):
# if this is a POST request we need to process the form data
if request.method == 'POST':
# create a form instance and populate it with data from the request:
form = FirstForm(request.POST)
# check whether it's valid:
if form.is_valid():
# process the data in form.cleaned_data as required
# ...
# redirect to a new URL:
send = form.save()
send.save()
messages.success(request, f"Success")
# if a GET (or any other method) we'll create a blank form
else:
form = FirstForm()
return render(request,
"main/mytemplate.html",
context={"form":form})
This answer is a bit general because you haven't included your view function. You can add each of these forms to your view's context. Something like this:
views.py
...
from .forms import FirstForm, SecondForm
...
def some_view(request):
context = {
'first_form': FirstForm(request.POST or None),
'second_form': SecondForm(request.POST or None)
}
return render(request, "app/some_template.html", context)
I have a single Car model which I'd like to filter through interdependent ModelChoiceField's:
class Car(models.Model):
make = models.CharField(max_length=50)
model = models.CharField(max_length=50)
platform = models.CharField(max_length=50)
Forms.py:
class MakeSelectForm(forms.ModelForm):
make = forms.ModelChoiceField(queryset=Car.objects.values_list('make',flat=True).distinct())
class Meta:
model = Car
fields = ["make"]
class ModelSelectForm(forms.ModelForm):
model = forms.ModelChoiceField(queryset=Car.objects.values_list('model',flat=True).distinct())
class Meta:
model = Car
fields = ["make", "model"]
Views.py:
def make_select_view(request):
form = MakeSelectForm()
make = None
if request.method == "POST":
form = MakeSelectForm(request.POST)
if form.is_valid():
make = form.cleaned_data['make']
return render(request, "reviews/makeselect.html", {"form": form, "make": make})
def model_select_view(request, make):
form = ModelSelectForm()
model = None
if request.method == "POST":
form = MakeSelectForm(request.POST)
if form.is_valid():
model = form.cleaned_data['model']
return render(request, "reviews/modelselect.html", {"form": form, "model": model})
URL's:
urlpatterns = [
url(r'^$', views.make_select_view, name="make-select"),
url(r'^(?P<make>\w+)/$', views.model_select_view, name="model-select"),
]
Makeselect.html:
<form action="{% url 'reviews:model-select' make %}" method="POST">
{% csrf_token %}
{{ form.as_p }}
<input type="submit" value="Select" />
</form>
Now, I have to pass "make" argument of the first form when posted, to the second view, and then use it to filter through Car instances with that make. But here all I pass is "None", and get Select a valid choice. That choice is not one of the available choices. error in the second form.
Any suggestion or feedback will be welcomed and greatly appreciated.
Thank you.
First point: model forms are for creating / editing models, so you should use plain forms here. Your error comes from having the make field in your ModelSelectForm but not setting its value anywhere. Also, ModelChoiceField is meant to retrieve a model instance, not field's value, so you really want a ChoiceField here.
Second point, since your goal is to display filtered informations - not to create or edit anything -, you should use GET queries (like for any "search" feature actually).
For your second form to work as expected (once ported to a plain Form with a single model field), you'll need to pass the make value to the form and, in the form's __init__(), update the model fields choices to the filtered queryset.
Also since you'll be using GET as form's method, you'll have to check wether the form has been submitted at all before deciding to instanciate it with or without the request.GET data, else the users would get error messages on first display before they even had a chance to submit anything. This is usually solved using either a name and value for the form's submit button or a hidden field in the form itself:
Forms:
class ModelSelectForm(forms.Form):
model = forms.ChoiceField()
def __init__(self, *args, **kwargs):
make = kwargs.pop("make", None)
if not make:
raise ValueError("expected a 'make' keyword arg")
super(ModelSelectForm, self).__init__(*args, **kwargs)
qs = Car.objects.filter(make=make).values_list('model',flat=True).distinct()
choices = [(value, value) for value in qs]
self.fields["model"].choices = choices
Views:
def model_select_view(request, make):
model = None
if request.GET.get("submitted", None):
form = ModelSelectForm(request.GET, make=make)
if form.is_valid():
model = form.cleaned_data['model']
else:
form = ModelSelectForm(make=make)
context = {"form": form, "model": model, "make: make}
return render(request, "reviews/modelselect.html", context)
Templates:
<form action="{% url 'reviews:model-select' make %}" method="GET">
{% csrf_token %}
<input type="hidden" name="submitted" value="1" />
{{ form.as_p }}
<input type="submit" value="Select" />
</form>
wrt/ your question about "passing 'make' to the second view": there's nowhere in your code snippet where you direct the user to the model-select view, but I assume that what you want is the user being redirected to it once he successfully selected the "make" in the first view. If yes, your first view's code should handle the case on successful form submission, ie:
def make_select_view(request):
if request.GET.get("submitted", None):
form = MakeSelectForm(request.GET)
if form.is_valid():
make = form.cleaned_data['make']
# send the user to the model selection view
return redirect("reviews:model-select", make=make)
else:
form = MakeSelectForm()
context = {"form": form}
return render(request, "reviews/makeselect.html", context)
Since the formatting of the snippet that I posted in comment got messed up so, I am writing that as an answer here.
def __init__(self, *args, **kwargs):
self.request = kwargs.pop('request', None)
super(GameForm, self).__init__(*args, **kwargs)
if not self.request.user.is_staff:
self.fields['publisher'].queryset = Publisher.objects.filter(id=self.request.user.id)
i want to create i simple django image processing .first i have create correct a django auth and multi upload images in my app.
now i want the user can select one self image from a list django form where i create and that image i get for my processing.i create something but not work.
i take that error :
'MyModelForm' object has no attribute 'user'
here the code :
views.py
#login_required(login_url="login/")
def myview(request):
Myf = MyModelForm(request.user,request.POST)
return render(request,'home.html',{'Myf':Myf})
forms.py
class MyModelForm(ModelForm):
def __init__(self, *args, **kwargs):
if 'user' in kwargs:
self.user = kwargs.pop('user')
super(MyModelForm, self).__init__(*args, **kwargs)
choices = [(obj.id, obj.upload.url) for obj in MyModel.objects.filter(user=self.user)]
self.fields['upload'].widget = Select(choices=choices)
class Meta:
model = MyModel
fields = ('upload',)
if i replace Myf = MyForm(request.user,request.POST) with Myform = MyModelForm(user=request.user) then i think list worked like this
image list
but i cant take select image for image processing.
html :
<form class="" action="" method="post" enctype="multipart/form-data">
{% csrf_token %}
{{ Myform}}
<input type="submit" name="" value="Submit">
</form>
any idea ?
Your MyForm class does not have user in the __init__ method's signature, so you need to provide it as a keyword argument when instantiating the form:
MyForm(user=request.user,data=request.POST)