I am trying to use the value of my database to display it in the form. So if a user already filled a value before, they will see it when they access again to the page.
So there is my HTML file :
<div class="form-group row">
<label class="col-4 mt-1 text-right">Modèle</label>
<div class="col-4">
{{ form.model }}
</div>
</div>
My views.py file :
def get_car(request, identifiant):
if request.method == "POST":
form = CarForm(request.POST)
if form.is_valid():
car_instance = Car(
identifiant,
form.cleaned_data["model"]
)
car_instance.save()
return HttpResponseRedirect("/forms/car/{}".format(identifiant))
else:
form = CarForm()
form.identifiant = identifiant
return render(request, "forms/car.html", {"form": form})
My models.py file :
class Car(models.Model):
model = models.CharField(max_length=16)
(primary key is automatically created)
And my forms.py file :
class CarForm(forms.Form):
model = forms.CharField(label="Modèle", max_length=32, widget=forms.TextInput({ "value": Car.objects.get(pk=1).model}))
We can see in the forms file that I gave a value to pk, so the code will search the value from the user whose pk = 1 in my database. My question is how to give the pk value from the active user ?
with form = CarForm() you create an empty form instance. No wonder the form shows up empty.
I would seriously recommend you to switch to class-based views (UpdateView and CreateView) as they created exactly for this type of usage and are super easy to implement.
Anyway, all you need to do here is to generate the form instance with the object that you plan to update.
I'm gonna guess that identifiant is a car ID(?)
car = Car.objects.get(id=identifiant)
form = CarForm(instance=car)
I would also suggest you to use a ModelForm instead of a standard form for your Car since you are collecting just the single field "model" in the "Car" model.
class CarForm(forms.ModelForm):
class Meta:
fields = ['model']
widgets = {
'model' : forms.TextInput(),
}
labels = {
'model' : 'Modèle'
}
You can add other attributes this way. You can add anything you want from there really. For example:
class CarForm(forms.ModelForm):
class Meta:
fields = ['model']
widgets = {
'model' : forms.TextInput(attrs={
'placeholder': '12345678',
'class' : 'shadow-sm',
'onClick' : "myFunction(this);"
}),
}
labels = {
'model' : 'Modèle'
}
Anything you put there will be rendered in the field. So if you add css classes you can put them all in the same line. For example
'class' : 'shadow-sm mx-3 bold-p text-responsive'
Related
I have created a model and connected a foreign key with it, but when I save them I get an error Cannot assign "1": "SupplierBidModel.Load_ID" must be a "ShipperBoardModel" instance.
I am fairly new to Django, and even newer to Django interconnected models concept. Any idea why this is happening ?? I have no idea where to go from here as there are not many questions such as this on Google either.
My models.py
class ShipperBoardModel(models.Model):
# Manufaturer_ID
LoadID = models.AutoField(primary_key=True)
From = models.CharField(max_length=100,null=True)
To = models.CharField(max_length=100,null=True)
Type = models.CharField(max_length=100,null=True)
Length = models.CharField(max_length=100,null=True)
Weight = models.CharField(max_length=100,null=True)
Numberoftrucks = models.IntegerField(null=True)
MaterialType = models.CharField(null=True,max_length=100)
Loadingtime = models.DateTimeField(null=True)
# Loadkey = models.ForeignKey()
def _str_(self):
return self.Origin
#
class SupplierBidModel(models.Model):
BidID = models.AutoField(primary_key=True)
Load_ID = models.ForeignKey(ShipperBoardModel,on_delete=models.CASCADE,default=3)
Supplier_ID = models.ForeignKey(SupplierBoardModel,on_delete=models.CASCADE,default=3)
Bid_amount = models.IntegerField(null=True)
class Meta:
unique_together = ('Load_ID', 'Supplier_ID')
Views.py
def suppliertablefun (request): # function to display shipperboardmodel
data = ShipperBoardModel.objects.all()
if request.method == 'POST':
forminput = BiddingForm(request.POST)
if forminput.is_valid():
forminput.save()
forminput = BiddingForm(request.POST)
return render(request, 'supplierboard/board.html', locals(), {'forminput': forminput})
PS: I am trying to prefill my form as such:
<form action="" method="post">
{# <input type="hidden" value={{item.LoadID}} name="Load_ID" /> #}
<input type="hidden" value={{item.LoadID}} name="Load_ID" />
{{ forminput.Bid_amount }}
<input type="submit" class="btn btn-primary" value="Submit"/>
</form>
I am trying to pass the current LoadID in the LoadID by using value = {{item.LoadID}} which is running because there a for loop in the template as such :
{% for item in data %}
Forms.py
class BiddingForm(forms.ModelForm):
Bid_amount = forms.IntegerField()
Load_ID = forms.IntegerField(widget=forms.HiddenInput())
class Meta:
model = SupplierBidModel
exclude = ()
Ok so I just fixed that error by pass value={{LoadID}} instead of value={{item.LoadID}} and there is no error, but it is not saving anything to the database. What to do now ?
Somewhere in your code you are trying to assign a number (1) to SupplierBidModel.Load_ID, which is incorrect because you have the following in your SupplierBidModel:
Load_ID = models.ForeignKey(ShipperBoardModel,on_delete=models.CASCADE,default=3,related_name='load')
If you are creating the ShipperBidModel using a number to link the ShipperBoardModel then you need to get the corresponding object first, something along the lines of:
# ... you get load_id from the form
shipper_board = ShipperBoardModel.objects.get(pk=load_id)
# then you create the SupplierBidModel instance, adding the other fields that you want
SupplierBidModel.objects.create(LoadId=shipper_board)
Your LoadId is not an id, is an ShipperBoardModel object, so you need to assign the corresponding one.
Your naming convention is all over the place, model fields should be lowercase separated by underscores. Check the docs: Model style
well you have some problem in the model
class SupplierBidModel(models.Model):
BidID = models.AutoField(primary_key=True)
Load_ID = models.ForeignKey(ShipperBoardModel,on_delete=models.CASCADE,default=3,related_name='load')
Supplier_ID = models.ForeignKey(SupplierBoardModel,on_delete=models.CASCADE,default=3,related_name='supplier')
Bid_amount = models.IntegerField(null=True)
you cannot have more than one in a single model. for that you need related_name parameter
I have a django based application where I want to create a form out of key, value pairs from a model. The `Child' model consists of the following rows of data:
(<parent 1>, 'component 1', 'dummy content 1'),
(<parent 1>, 'component 2', 'dummy content 2'),
Here is are my models:
# models.py
class Parent(models.Model):
class Meta:
verbose_name = 'Parent'
db_table = "parent"
title = models.CharField(max_length=28)
def __str__(self):
return self.title
class Child(models.Model):
class Meta:
verbose_name = 'Child'
db_table = "child"
parent = models.ForeignKey(Parent, on_delete=models.CASCADE)
key = models.CharField(max_length=20)
value = models.TextField()
def __str__(self):
return self.parent
Following is the direct model to form mapping I am currently using for my other forms to keep it straight forward and simple
# forms.py
class MyForm(ModelForm):
class Meta:
model = Child
fields = () # fields go here
Then I pass this form to my view. The view page_view takes pk of the parent, gets the parent and passes it to the form. The form is then passed on to the template parent_view.html via the view.
# views.py
#login_required
def page_view(request, parent_pk):
parent = get_object_or_404(Parent, pk=pk)
my_form = MyForm(request.POST, instance=parent)
return render(request, 'parent_view.html', {
'parent': parent,
'my_form': my_form,
})
In the template I render the form like this:
<!-- page_view.html -->
{{ my_form }}
However, I would also like to write the html for this manually to add any design changes locally. I would like the forms.py MyForm to construct a form from the model by collecting key, value pairs for the provided parent.
So it should render it like this:
<form action=''>
<label for='component_1'>component 1</label>
<textarea name='component_1' type='text'>dummy content 1</textarea>
<label for='component_2'>component 2</label>
<textarea name='component_2' type='text'>dummy content 2</textarea>
</form>
But I can't seem to get my head around how to handle that in the `MyForm'. I have looked around a couple of solutions over stackoverflow but none of them point me in the right direction for this problem. If anyone has any ideas I would highly appreciate. Thanks in advance.
If there are multiple Child instances, then a single form will not be of much use, you will have to use a formset (a model formset to be precise).
As per the docs,
A formset is a layer of abstraction to work with multiple forms on the same page
# forms.py
# You can provide a text area widget for the field that you want to be displayed as a text area
class MyForm(ModelForm):
class Meta:
model = Child
fields = () # fields go here
widgets = {
'field_name': forms.Textarea(attrs={'cols': 80, 'rows': 3}),
}
ChildFormset = forms.modelformset_factory(Child, ChildForm, exclude=[], extra=0)
Then in your views, you can pass a queryset of all the objects that you want in your form
# views.py
from .forms import ChildFormset
#login_required
def page_view(request, parent_pk):
parent = get_object_or_404(Parent, pk=pk)
child_queryset = parent.child_set.all()
if request.method == 'GET':
child_formset = ChildFormset(queryset=child_queryset)
return render(request, 'parent_view.html', {
'parent': parent,
'my_formset': child_formset,
})
else:
child_formset = ChildFormset(request.POST, queryset=child_queryset)
if child_formset.is_valid():
for form in child_formset:
form.save()
# ... Do whatever else you want to do with the data
In your templates, you will then have to traverse through all the form objects in the formset. Then you can display them in whatever way you want to.
# parent_view.html
{{ child_formset.management_form }}
{% for form in child_formset %}
<div class="hidden">{{ form.id }}</div>
{% for field in form.visible_fields %}
{{ field }}
{% endfor %}
{% endfor %}
NOTE: The Foreign Key field will be displayed as a drop down for the user to select a parent object from the list of parent objects.
Please help me. I am new to Django, cannot undertsand the following thing - I have subclass of CreateView for creating a comment. I want to create a project where people can leave their comments and attach files (images) to this comment. One should have possibility to attach as many images as he wants to ONE form with text comment. I have found in Internet a decision that I need to use 2 models - 1 model for text comment + 1 separate model for images. Is it so?
Comment (text) form is created and handled in my views.py by sublass of CreateView. How to connect new separate model for images with my CreateView ?
models.py
class Descriptions(models.Model):
…
city = models.ForeignKey(Cities, on_delete=models.CASCADE)
description = models.TextField()
date_added = models.DateTimeField(auto_now_add=True)
owner = models.ForeignKey(User, on_delete=models.DO_NOTHING)
…
class Description_Photos(models.Model):
image = models.ImageField(upload_to='images/', blank=True)
description = models.ForeignKey(Descriptions, on_delete=models.CASCADE, related_name='photos')
forms.py
class DescriptionsForm(forms.ModelForm):
class Meta:
model = Descriptions
exclude = []
widgets = {'description': forms.Textarea(attrs={'cols':90})}
class Photos_form(forms.Form):
photos = forms.FileField(widget=forms.FileInput(attrs={'multiple': True}))
views.py
class DescriptionCreate(CreateView):
model = Descriptions
form_class = DescriptionsForm
template_name = 'countries/new_description.html'
def get_success_url(self):
return reverse('countries:descr', args=[self.kwargs['country_id'], self.kwargs['city_id']])
def get_context_data(self, **kwargs):
self.city = get_object_or_404(Cities, id=self.kwargs['city_id'])
kwargs['city'] = self.city
return super().get_context_data(**kwargs)
def form_valid(self, form):
form.instance.city = get_object_or_404(Cities, id=self.kwargs['city_id'])
form.instance.owner = self.request.user
messages.success(self.request, 'Your post has been added, thank you')
return super().form_valid(form)
So my question is what should I write in views.py for class Photos_form(forms.Form): ? How to connect this class and my class DescriptionCreate(CreateView) ?
I use for same situations FormSets https://docs.djangoproject.com/en/2.0/topics/forms/formsets/
Declare FormSet for images models
…
# forms.py
class DescriptionsForm(forms.ModelForm):
class Meta:
model = Descriptions
exclude = []
widgets = {'description': forms.Textarea(attrs={'cols':90})}
class Photos_form(forms.Form):
photos = forms.FileField(widget=forms.FileInput(attrs={'multiple': True}))
##### Declare FORMSET !!! ###
class BasePhotosFormSet(BaseModelFormSet):
"""By default, when you create a formset from a model, the formset
will use a queryset that includes all objects in the model"""
def __init__(self, *args, **kwargs):
if 'city' in kwargs.keys():
city = kwargs.pop('city')
else:
city = None
super().__init__(*args, **kwargs)
if city and isinstance(instance, Cities):
self.queryset = Description_Photos.objects.filter(city=city)
else:
self.queryset = Description_Photos.objects.none()
# I usually declare formset for create operations and formset for update operations separately
PhotosCreateFormSet = forms.modelformset_factory(Description_Photos, Photos_form,
fields=Photos_form.Meta.fields, extra=0,
formset=BasePhotosFormSet)
PhotosUpdateFormSet = forms.modelformset_factory(Description_Photos, Photos_form, can_delete=True,
fields=PropertyImageForm.Meta.fields, extra=0,
formset=BasePhotosFormSet)
#############
# views.py
class DescriptionCreate(CreateView):
def __init__(self, **kwargs):
self.object = None
super().__init__(**kwargs)
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
if self.request.POST:
images_formset = PhotosCreateFormSet(self.request.POST, self.request.FILES, city=self.object)
else:
images_formset = PhotosCreateFormSet(instance=self.object)
context['formset'] = images_formset
context['city'] = self.object
return context
Templates
<div id="img-form-template" style="display: none">
<!- Declare EMPTY FORM for dynamically rebuild user interface by jQuery, for example->
{{ formset.empty_form }}
</div>
...
<div id="my-images">
...
{{ formset.management_form }}
{% for image_form in formset %}
{{ image_form }}
{% endfor %}
</div>
...
<script>
...
<!- Any javascript code to dynamically create empty form based on template "#img-form-template" ->
...
</script>
I've tried to rewrite my custom code to your variant.
I suppose it is a bad idea to declare self.city in your example as creation model instance: Django automatically create self.object
I hope you have found your answer, I have done something, but may not be the cleaned or recommended one;
I have a page for multiple images upload and another page to view the images, add additional information and complete the process. Between the pages, I have used session to pass a parent table ID through which I group multiple images being uploaded.
Below is my class for image upload:
class UploadImages(LoginRequiredMixin,CreateView):
In get_context_data, I do the below (summarized):
if "album_id" not in self.request.session:
print("Creating a temporary album!")
album = Album(
owner = self.request.user,
category_id = 6,#others
privacy_id=3,#restricted
status_id=8,#temporary file
title="Temporary Album for " + self.request.user.get_full_name(),
is_temp=True
)
album.save()
self.request.session['album_id'] = album.id
context.update({
'taid':album_id,
})
return context
When I re-direct to this view from the menu, all session IDs with album_id are clearer, this way it will get called for the first time. Each time a single file uploads, this method will be called inside form_valid and hence, it is good to validate and then create for the firs time. In the HTML template, I have this javascript variable to hold the redirect url after successful file upload, in ajax call:
<script>
var redirect_url = "{% url 'images:complete-upload' %}"
</script>
Then in form_valid:
if self.request.is_ajax():
album_id = self.request.session['album_id']
Now I have access to the album_id and I can use this to save multiple images, grouped into one album:
lnk_album = AlbumPhotos(
album_id = album_id,
photo = self.object
)
lnk_album.save()
Once this is done for each single message, my ajax call returns success, in the javascript file, I do this:
$("#fileupload").fileupload({
dataType: 'json',
sequentialUploads: true, /* 1. SEND THE FILES ONE BY ONE */
start: function (e) { /* 2. WHEN THE UPLOADING PROCESS STARTS, SHOW THE MODAL */
$("#modal-progress").modal("show");
},
stop: function (e) { /* 3. WHEN THE UPLOADING PROCESS FINALIZE, HIDE THE MODAL */
$("#modal-progress").modal("hide");
//write code to re-direct
window.location.replace(redirect_url);
},
progressall: function (e, data) { /* 4. UPDATE THE PROGRESS BAR */
var progress = parseInt(data.loaded / data.total * 100, 10);
var strProgress = progress + "%";
$(".progress-bar").css({"width": strProgress});
$(".progress-bar").text(strProgress);
},
done: function (e, data) {
console.log("completed file upload!")
if (data.result.is_valid) {
console.log("success!!")
}
else{
console.log(e)
}
}
});
This gets job done for me so far. I haven't figured out whether this is a best practice. Once I do a penetration testing, maybe in a month or so, after completing this app, I will know (or someone else points out the vulnerabilities in this code).
On the receiving page, I pick up the album_id from the session (get_context_data) and then delete it to ensure the session is clean.
I hope this helps.
I'm trying to build forms linked to a PostgreSQL database using Django ModelForms. The template is rendering two of the fields(the ones with ManyToMany relationships), but it only gives me an empty box for "title".
This is my forms.py:
Forms.py:
class ProgramForm(forms.ModelForm):
class Meta:
model = Program
fields = ['function','task', 'title']
widgets = {
'function' : forms.Select,
'task' : forms.Select,
'title' : forms.Select,
}
This is my Models.py:
class Program(models.Model):
title = models.CharField(max_length=255)
function = models.ManyToManyField(function, related_name='programs')
task = models.ManyToManyField(Task, related_name='programs')
def __unicode__(self):
return self.title
class Task(models.Model):
tasknum = models.CharField(max_length=20)
taskname = models.CharField(max_length=100)
task_num_name = models.CharField(max_length=100)
function = models.ForeignKey(Function, related_name="tasks")
def __unicode__(self):
return self.task_num_name
class Function(models.Model):
function = models.CharField(max_length=50)
function_abrev = models.CharField(max_length = 25)
def __unicode__(self):
return self.function
Views.py:
def main(request):
return render (request, 'assignments/main.html')
def add_program(request):
form = ProgramForm()
return render (request, 'assignments/ad_form.html', {"form":form})
def link(request):
if request.method == 'POST':
form = ProgramForm(request.POST)
if form.is_valid():
return HttpResponse("we maybe getting somewhere")
else:
return HttpResponse("keep working")
I need a couple of things to happen:
I need for the "title" to render in the html page as a scroll down(the same way "function" and "task" appear.
I need to be able to save the relationships. The models are populated with all the information required with the exception of the relationships. The objective is for a staff member to be able to chose a "function", for that choice to act as a filter for the "task" scroll down(function and task have a OneToMany), and then allow them to choose any programs they want to add to their portfolio.
Any help will be much appreciated.
1. Title field in form
For this, I don't quite understand how the title field could be a scroll down the same way function and task are. Function and task are drop downs because they are manytomany fields linked to other models, meaning that the user has to pick which other objects in the Functions model and the Tasks model are to be linked. The title field, on the other hand, is just a CharField and so there is no defined set of things for the user to pick from. To allow the user to enter in the title for the Program, you should change the widget for title to Textarea() as such:
forms.py
from django.forms import ModelForm, Textarea
class ProgramForm(forms.ModelForm):
class Meta:
model = Program
fields = ['function','task', 'title']
widgets = {
'function' : forms.Select,
'task' : forms.Select,
'title' : Textarea(),
}
2. Save the Program from the form
To save the Program created by the user on staff member, simply add form.save() to your link(request) function:
views.py
def link(request):
if request.method == 'POST':
form = ProgramForm(request.POST)
if form.is_valid():
form.save()
return HttpResponse("we maybe getting somewhere")
else:
return HttpResponse("keep working")
Hope this helps!
I was able to do a query from views.py and pass if to the template.
Views.py
def function_page(request, Function_id):
assignments = Function.objects.get(id=Function_id)
programs = assignments.programs.all()
context = {
'assignments': assignments,
'programs' : programs
}
return render (request, 'function.html', context)
HTML
{% for program in programs %}
<option value="{{program.title}}">{{program.title}}</option>
{% endfor %}
Consider a model:
class MyModel(models.Model):
token = models.CharField(unique=True, db_index=True, max_length...)
name = models.CharField(...)
...
(Aside: The purpose of the token is to be an alternative to displaying and using the ID in URLs; it is not the primary key.)
And its form:
class MyForm(forms.ModelForm):
...
class Meta:
model = models.MyModel
fields = '__all__' # Django 1.6
And its template:
...
<form action={% url 'create_or_edit_mymodel' %} ...>{% csrf_token %}
{{ form.token.as_hidden }}
<label for="id_name">Name:</label>
{{ form.name }}
...
And, finally, its view:
def create_or_edit_mymodel(request, token=None):
# [A] Entering via a hyperlink with the token, editing existing model
if token:
m = models.MyModel.objects.filter(token=token).first()
form = forms.MyForm(instance=m)
# [B] Postback from form
elif request.POST:
form = forms.MyForm(request.POST)
# [C] Entering via a hyperlink without the token, creating new model
else:
m = create_new_mymodel(...) # somewhere else
form = forms.MyForm(instance=m)
if request.method == 'POST' and form.is_valid():
saved = form.save()
# Determine if 'Save' or 'Save & Close' was clicked... assume 'Save'...
form = forms.MyForm(instance=saved)
return shortcuts.render(request, '...', { 'form': form }, context_instance=RequestContext(request))
This doesn't work. The problem is that the model's ID doesn't seem to be available to Django, so entering the view at [A] populates the form with everything as expected, but clicking 'Save' and entering the view at [B] attempts to save a model with no ID, and the unique constraint on the 'token' field fires.
I tried adding the id field to the form:
{{ form.id.as_hidden }} # or...
{{ form.pk.as_hidden }}
But nothing gets rendered.
That view looks pretty uncomfortable to me, so I'm hoping I'm making this harder than it needs to be.
Here you should pass both request.POST and instance to form init:
# [B] Postback from form
elif request.POST:
form = forms.MyForm(request.POST, instance=instance)