I'm doing a edit form for some data. I'm having problem to pass information to . As you can see in my view, I pass the data to form using "initial" dictionary.
VIEWS.PY
#login_required
def project_detail(request, project_id):
if request.method == 'POST':
project = get_object_or_404(Project, pk=project_id)
form = ProjectDetailForm(project_id, request.POST, instance = project)
if form.is_valid():
instance = form.save(commit=False)
instance.client = Project.objects.get(pk=project_id).client
form.save()
messages.success(request,'Projeto modificado')
return redirect('projects')
else:
messages.error(request,'Ocorreu um erro!')
else:
project = get_object_or_404(Project, pk=project_id)
form = ProjectDetailForm(project_id, initial={'modal':project.modal,
'culture':project.culture,
'owner':project.owner,
'value':project.value,
'final_date':project.final_date,
'text':project.text,
'status':project.status,
'farm':project.farm.values()})
return render(request,'project_detail.html',{'form':form})
But doing this, the data is not displaied in . Thinking here, ManyToManyField saves data in lists. I tried iterate this field but still not working and I guess thats not the best way to do this.
MODELS.PY
class Project(models.Model):
modal_types = [('CUSTEIO AGRÍCOLA','Custeio Agrícola'),('CUSTEIO PECUÁRIO','Custeio Pecuário'),('INVESTIMENTO AGRÍCOLA','Investimento Agrícola'),('INVESTIMENTO PECUÁRIO','Investimento Pecuário'),('FGPP','FGPP')]
status_opts = [('Análise','Análise'),('Desenvolvimento','Desenvolvimento'),('Processamento','Processamento'),('Liberação','Liberação'),('Finalizado','Finalizado'),('Cancelado','Cancelado'),('Suspenso','Suspenso')]
farm = models.ManyToManyField(Farm, related_name='farm_name',verbose_name='Propriedade beneficiada')
client = models.ForeignKey(Clients, on_delete=models.CASCADE, related_name='project_client',default=None,null=True, verbose_name='Cliente')
owner = models.ForeignKey(Owner, on_delete=models.CASCADE, related_name='project_bidder',default=None,null=True, verbose_name='Proponente')
warranty = models.ManyToManyField(Farm, related_name='project_warranty',default=None, verbose_name='Propriedade de garantia')
modal = models.CharField(max_length=100,default=None,choices=modal_types, null=True, verbose_name='Tipo')
culture = models.CharField(max_length=50,null=True, verbose_name='Cultura')
status = models.CharField(max_length=50,null=True, verbose_name='Status', choices=status_opts)
created_date = models.DateField(null=True, verbose_name='Data de criação')
value = models.FloatField(max_length=10,null=True, verbose_name='Valor financiado')
final_date = models.DateField(default=None,null=True, verbose_name='Fim do contrato')
text = models.TextField(default=None,null=True, verbose_name='Observações')
forms.py
class ProjectDetailForm(ModelForm):
class Meta:
model = Project
fields = ['status','owner', 'farm', 'warranty', 'modal', 'culture', 'value','final_date','text']
def __init__(self, project_id, *args, **kwargs):
client_id = Project.objects.get(pk=project_id).client
super(ProjectDetailForm,self).__init__(*args,**kwargs)
self.fields['value'].required = False
self.fields['final_date'].required = False
self.fields['text'].required = False
self.fields['farm'].queryset = Farm.objects.filter(client=client_id)
self.fields['warranty'].queryset = Farm.objects.filter(client=client_id)
for field_name, field in self.fields.items():
field.widget.attrs['class'] = 'form-control'
Here all the fields with information, but in "select" nothing is selected, despite having data in the database
Someone can help me?
Why are you passing 'project_id' into your form class instance? Try changing this:
form = ProjectDetailForm(project_id, request.POST, instance = project)
to this:
form = ProjectDetailForm(request.POST, instance = project)
and see if it helps. Also in your form initialization, I'm not sure you're using the "initial=" values dictionary correctly. Initial values are typically defaults applicable to the "create" view, not database records that it sounds like you want to see in an update view. I think you want to pass in the instance of your database record there, something like:
else:
project = get_object_or_404(Project, pk=project_id)
form = ProjectDetailForm(instance=project)
Also, you really don't need to write project object query twice in this view. You can do something like:
def project_detail(request, project_id):
project = get_object_or_404(Project, pk=project_id) # query this once here
if request.method == 'POST':
form = ProjectDetailForm(request.POST, instance=project)
if form.is_valid():
instance = form.save(commit=False)
instance.client = Project.objects.get(pk=project_id).client
form.save()
messages.success(request,'Projeto modificado')
return redirect('projects')
else:
messages.error(request,'Ocorreu um erro!')
# you probably want a redirect here as well
else:
form = ProjectDetailForm(instance=project)
return render(request,'project_detail.html',{'form':form})
Finally, if you're trying to limit the choices from your ManyToMany field in the user's form, you can do so with something like this:
class ProjectDetailForm(forms.ModelForm):
class Meta:
model = YourModelName
fields = ['farm']
farm = forms.ModelMultipleChoiceField(
queryset=Farm.objects.filter(some_field=some_criteria).order_by('some_field'),
widget=forms.CheckboxSelectMultiple)
More info about widgets on form classes here in Django docs.
Related
I'm learning Django, so I'm trying to create a mini-app for practice.
I've 2 tables on DB:
By one side webapp_domicilio, where is a PK for the ID and some varchars for address info.
By the other side, webapp_persona, where is a PK for the ID, some varchars for person info and a FK referencing the address ID (webapp_domicilio.id)
I created the webpage for adding new item to webapp_persona, inheriting ModelForm and now I want to add the option to create, edit and delete an address without exiting this page, just like the Django Admin page.
Searching on stackoverflow I found this article: Creating front-end forms like in Django Admin but the accepted answer get me to a 404 page on Django documentation.
Then I tried what's in https://django-addanother.readthedocs.io/en/latest/index.html and I managed to insert the 'add' button but it doesn't open in a popup using CreatePopupMixin from django_addanother.views. There is a point where they explain how to make the view popup compatible but I don't really understand it. I also tried to insert the 'edit' button but it doesn't work neither.
I let my code here:
views.py:
def nueva_persona(request):
if request.method == 'POST':
formulario_persona = PersonaForm(request.POST)
if formulario_persona.is_valid():
formulario_persona.save()
return redirect('personas')
else:
formulario_persona = PersonaForm()
return render(request, 'nueva_persona.html', {'formulario_persona': formulario_persona})
def editar_domicilio(request, id):
domicilio = get_object_or_404(Domicilio, pk=id)
if request.method == 'POST':
formulario_domicilio = DomicilioForm(request.POST, instance=domicilio)
if formulario_domicilio.is_valid():
formulario_domicilio.save()
return redirect('domicilios')
else:
formulario_domicilio = DomicilioForm(instance=domicilio)
return render(request, 'editar_domicilio.html', {'formulario_domicilio': formulario_domicilio})
def nuevo_domicilio(request):
if request.method == 'POST':
formulario_domicilio = DomicilioForm(request.POST)
if formulario_domicilio.is_valid():
formulario_domicilio.save()
return redirect('domicilios')
else:
formulario_domicilio = DomicilioForm()
return render(request, 'nuevo_domicilio.html', {'formulario_domicilio': formulario_domicilio})
def eliminar_domicilio(request, id):
domicilio = get_object_or_404(Domicilio, pk=id)
if domicilio:
domicilio.delete()
return redirect('domicilios')
models.py:
class Domicilio(Model):
calle = CharField(max_length=255)
nro = IntegerField()
localidad = CharField(max_length=255)
def __str__(self):
return f'{self.calle} {self.nro} {self.localidad}'
class Persona(Model):
nombre = CharField(max_length=255)
apellido = CharField(max_length=255)
email = CharField(max_length=255)
domicilio = ForeignKey(Domicilio, on_delete=RESTRICT)
def __str__(self):
return f'{self.id} {self.nombre} {self.apellido} {self.email}'
forms.py:
class PersonaForm(ModelForm):
class Meta():
model = Persona
fields = '__all__'
widgets = {
'email': EmailInput(attrs={'type':'email'}),
'domicilio': AddAnotherWidgetWrapper(
Select,
reverse_lazy('nuevo_domicilio'),
),
# 'domicilio': EditSelectedWidgetWrapper(
# Select,
# reverse_lazy('editar_domicilio', args=['__fk__']),
# ),
}
class DomicilioForm(ModelForm):
class Meta():
model = Domicilio
fields = '__all__'
widgets = {
'nro': NumberInput(attrs={'type':'number'}),
}
What I'd like to do is create a form similar to this:
When user try to create a new person, it should open a form like this:
And, if user click on '+' button, it should open a popup like this:
Once user saves the new address, it should close the popup and show it in drop down list of the 'domicilio' field
Thaks and regards
In my project i am using Django 1.11.10 and postgresql for database. When someone enters data to 'order_id' field i want to send it a item_barcode column whether its first 2 character is letters. How can I do that?
models.py
from django.db import models
class Customer(models.Model):
item_barcode = models.TextField(max_length=50,unique=True,null=True)
order_id = models.TextField(max_length=50,unique=True,null=True)
full_name = models.TextField(max_length=50)
company = models.TextField(max_length=60,blank=True)
email = models.EmailField(max_length=40)
phone_number = models.TextField(max_length=17)
note = models.TextField(max_length=256,blank=True)
def __str__(self):
return self.order_id
forms.py
class CustomerForm(forms.ModelForm):
class Meta:
model = Customer
fields = (
'order_id','full_name','company','email',
'phone_number','note')
views.py
def guaform(request):
form = CustomerForm()
if request.method == "POST":
form = CustomerForm(request.POST)
if form.is_valid():
form.save(commit=True)
else:
HttpResponse("Error from invalid")
return render(request,'customer_form.html',{'form':form})
*My database columns is same of the models.py
You can do some work after validating the form.
if form.is_valid():
#test to see if first two characters are letters
first_two_characters = form.cleaned_data['order_id'][0:2]
if first_two_characters.isAlpha():
#get an instance of the object without saving to db
form_uncommitted = form.save(commit=False)
#set the item_barcode field and only then save to db
form.uncommitted.item_barcode = form.cleaned_data['order_id'] #or what you want it to be
form_uncommitted.order_id = None
form_uncommitted.save
else:
#it's not a barcode so we can just save
form.save()
So this is the scenario. I allow my user to first input their vehicle brand with one form and then use another form to list down the models available for that vehicle brand. The information on the vehicles and the brands is stored in my database.
Refer to this image to get a better idea:
And this is my views.py:
def driver_dashboard_trip_brand (request, brand):
if request.method == "POST":
form = AddVehicleForm(request.POST)
else:
form = AddVehicleForm()
brands = VehicleBrand.objects.all()
context = {
"form":form,
"brands":brands,
"chosen_brand":brand
}
return render (request, "app/driver_dashboard.html", context)
And my forms.py:
class AddVehicleForm(forms.ModelForm):
model = forms.ModelChoiceField(queryset=VehicleModel.objects.all())
vehicle_colour = forms.ChoiceField(choices=COLOURS)
vehicle_number = forms.CharField(max_length=8, widget=forms.TextInput(attrs={'placeholder': 'eg: CAB-1234'}))
class Meta:
model = Vehicle
fields = ['model', 'vehicle_colour', 'vehicle_number']
So in order to set a query in the forms.py, I would first need to send the data from views.py to forms.py, and then I also need to do a query.
So my question is how can I query for all the car models from the VehicleModel database and create choices attribute for the form, once the user chooses the car brand.
My models.py...
class VehicleModel (models.Model):
brand = models.ForeignKey(VehicleBrand, on_delete=models.CASCADE)
model = models.CharField(max_length=30)
def __str__ (self):
return f"{self.brand} - {self.model}"
Its honestly not so hard, i kinda figured it out...
So this is my forms.py...
class AddVehicleForm(forms.ModelForm):
def __init__(self, brand=None, *args, **kwargs):
super(AddVehicleForm, self).__init__(*args, **kwargs)
self.fields['model'].queryset = VehicleModel.objects.filter(brand=brand)
model = forms.ModelChoiceField(queryset=VehicleModel.objects.all())
vehicle_colour = forms.ChoiceField(choices=COLOURS)
vehicle_number = forms.CharField(max_length=8, widget=forms.TextInput(attrs={'placeholder': 'eg: CAB-1234'}))
class Meta:
model = Vehicle
fields = ['model', 'vehicle_colour', 'vehicle_number']
class AddVehicleFormPost(forms.ModelForm):
model = forms.ModelChoiceField(queryset=VehicleModel.objects.all())
vehicle_colour = forms.ChoiceField(choices=COLOURS)
vehicle_number = forms.CharField(max_length=8, widget=forms.TextInput(attrs={'placeholder': 'eg: CAB-1234'}))
class Meta:
model = Vehicle
fields = ['model', 'vehicle_colour', 'vehicle_number']
Where the form AddVehicleForm allowed me to send the parameter as shown by typing form = AddVehicleForm(VehicleBrand.objects.filter(brand=brand).first()) in my views.py, but then when I wanted to save my form I needed to create another form in the forms.py without taking any query which is shown in AddVehicleFormPost.
Then i casually did,
if request.method == "POST":
form = AddVehicleFormPost(request.POST)
if form.is_valid():
In my views.py...
Here you have a nice tutorial on how to create dependent fields, you need to understand what's going on on the Server, and what's going on on the Client
Is possible to retrieve the current logged user id into a function defined inside a class, in views.py, using Django CreateView?
Something like this:
class CreationClass(CreateView):
model = Mymodel
def creation(self, request):
if request.method == 'POST':
form = MyForm(request.POST or None)
if form.is_valid:
form = myForm()
user_id = self.request.user.id
rel_table = Item_id_user ( item_id = form.id, user_id = request.user.id)
rel_table.save() #<--- this does not save, even if table exists
return render(request, ''mypage.html')
And this is my models.py
class Item(models.Model):
id_user = models.ManyToManyField(User, related_name='user_item',
verbose_name='id utente', through='Item_id_user')
object = models.Manager()
# table to handle relationship
class Item_id_user(models.Model):
user = models.ForeignKey(User, on_delete=models.CASCADE)
item = models.ForeignKey(Item, on_delete=models.CASCADE)
id = models.IntegerField(primary_key=True)
What I want to achieve is to store into Item_id_user, but nothing at all is being stored. I thought the problem was the request.user.id.
instead of:
user_id = self.request.user.id
try this:
user_id = request.user.id
Should work.
I don't understand why you re-initialize the form with form = MyForm() after the form is validated. I think that might wipe the data contained in it. It looks like you forgot it there.
Try this:
class CreationClass(CreateView):
model = Mymodel
def creation(self, request):
if request.method == 'POST':
form = ColumnCreationForm(request.POST or None)
if form.is_valid:
# form = myForm()
user_id = self.request.user.id
rel_table = Item_id_user ( item_id = form.id, user_id = request.user.id)
rel_table.save() #<--- this does not save, even if table exists
return render(request, ''mypage.html')
I'm still learning Django. I have a wizard like form workflow where each form is filling out information in succession.
I have a model form that represents what I want inputted from the form:
Models.py
class AccountParameters(models.Model):
acctFilterName = models.ForeignKey(AccountFilters)
excludeClassification = models.ManyToManyField(ClassificationNames)
tradingCash = models.FloatField()
Forms.py
This is a dumbed down form and doesn't represent the real implementation. It was for testing.
class AccountSelectionForm(forms.ModelForm):
acctFilterName = forms.ModelChoiceField(queryset=AccountFilters.objects.all().values_list('acctFilterName', flat=True),
label="Account Filters:",
empty_label="Select Here..."
)
excludeClassification = forms.ModelMultipleChoiceField(queryset=ClassificationNames.objects.all().values_list('classificationName', flat=True),
label="Classifications Exclusion:"
)
tradingCash = forms.IntegerField(label="Remove accounts whose trading cash < % of AUM")
class Meta:
model = AccountParameters
fields =['excludeClassification', 'tradingCash',]
exclude = ['acctFilterName']
labels = {
'acctFilterName': _('Account Filters:')
}
views.py
def accountSelections(request): # NewRebalnce 2: AccountParameters with Accounts and Trading Form
if request.method == "POST":
form = AccountSelectionForm(request.POST)
if form.is_valid():
accountParameters = AccountParameters
#tradingCash = form.cleaned_data['tradingCash']
return render(request, 'NewRebalance_3.html', {'model_selection_form': ModelSelectionForm()})
else:
form = AccountSelectionForm()
return render(request, 'NewRebalance2.html', {'account_selections_form': form})
I'm not sure that I'm using Modelforms correctly. What I needed was a way to create a select drop down for my acctFilterName so I created the query set manually.
When I save the form it's not valid and in the form cleaned data I get the following:
Notice that the cleaned data only has the tradingCash field.
What am I doing wrong? Is there a better way to do this? Why is the Form in valid?
try to remove .values_list('acctFilterName', flat=True) from the ModelChoiceField and remove .values_list('classificationName', flat=True) from the ModelMultipleChoiceField.
They should be like this:
acctFilterName = forms.ModelChoiceField(
queryset=AccountFilters.objects.all(),
label="Account Filters:",
empty_label="Select Here...")
excludeClassification = forms.ModelMultipleChoiceField(
queryset=ClassificationNames.objects.all(),
label="Classifications Exclusion:")
.values_list will strip your queryset of all the data the ModelChoiceField needs to recognize the item, leaving only the model fields you specify as an argument. Namely, what you're removing here is the primary key of the model which is fundamental.
Why are you redeclaring the fields on your AccountSelectionForm ModelForm???
Better this way:
class AccountSelectionForm(forms.ModelForm):
def __init__(self, *args, **kwargs):
self.fields['excludeClassification'].queryset = ClassificationNames.objects.all().values_list('classificationName', flat=True)
self.fields['acctFilterName'].queryset = AccountFilters.objects.all().values_list('acctFilterName', flat=True)
class Meta:
model = AccountParameters
fields =['excludeClassification', 'tradingCash',]
exclude = ['acctFilterName']
labels = {
'acctFilterName': _('Account Filters:')
}