Django: Popup for FK CRUD form inside another form - python

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

Related

How to assign a user to an employee in Django

I am a beginner in django and trying to create a web application for my task.
I am trying to assign a user to every to employee.
The idea is that user(in my class Employee) brings a list of user options that have not yet been assigned to the new employee to be registered.
My model:
class Employee():
name = models.CharField(max_length=100)
job = models.CharField(max_length=30)
user = models.OneToOneField(User,on_delete=models.CASCADE)
def __str__(self):
return'{}'.format(self.name,self.job,self.user)
My form:
class EmployeeForm(forms.ModelForm):
user= forms.ModelChoiceField(queryset=User.objects.filter(id=Employee.user))
class Meta:
model = Employee
fields = [
'name',
'job',
'user'
]
My view:
def register_employee(request):
if request.method == 'POST':
form = EmployeeForm(request.POST)
if form.is_valid():
form.save()
return redirect('/')
return redirect('list_employee')
else:
form = EmployeeForm()
return render(request, 'employee/employee_form.html',{'form': form})
I guess your code to be modified as,
class EmployeeForm(forms.ModelForm):
user= forms.ModelChoiceField(queryset=User.objects.filter(employee=None))
Please try the above.

Show multi-selected itens when load a edit view

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.

Make a choices list for forms.py after receiving data from views.py in django

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

How to display a single form with Foreign Key and choices in a Django Form?

My goal is display a form with all theses fields, I'm stuck to display city and description field from City model, the first one needs to display a select box with all cities choices and the other just a text field.
So, I need to display a form with this format:
city (With selected box from all choices)
description
date
status
CITIES_CHOICES = (('RJ', 'Rio de Janeiro'), ('NY', 'New York'), ('PIT', 'Pittsburgh'))
class City(models.Model):
city = models.CharField(max_length=50, choices=CITIES_CHOICES)
description = models.TextField()
def __str__(self):
return self.city
class Checkin(models.Model):
destination = models.ForeignKey(City, on_delete=models.SET_NULL)
date = models.DateTimeField()
status = models.BooleanField()
I had create a form using Modelform but how can I display the fields from City model instead display de city object properly?
Any idea where I need to go now?
forms.py
class DocumentForm(forms.ModelForm):
class Meta:
model = Checkin
There a few ways to go about this. One of the easier ways would be to create two forms, a ModelForm for City and a ModelForm for Checkin. Inside the view, you can pass both forms to the context and validate both forms. You can load them inside the same form tag on the HTML page.
I would not include the "city" field inside the Checkin form, you can handle this manually inside the view.
def some_view(request):
if request.method == 'GET':
city_form = CityForm()
Checkin_form = CheckInForm()
elif request.method == 'POST':
city_form = CityForm(request.POST)
checkin_form = CheckInForm(request.POST)
if city_form.is_valid() and checkin_form.is_valid():
city = city_form.save()
date = checkin_form.cleaned_data.get('date')
status = checkin_form.cleaned_data.get('status')
Checkin.objects.create(
destination=city,
date=date,
status=status
)
context = {
'city_form': city_form,
'checkin_form': checkin_form,
}
return render(request, <template>, context)
This is a quick example, you could create this in a single form or even through an API if you wanted. I think it would be better in a Class Based View as well.

How update models modelforms and django

i have a problem when i try update the data for model usuario
this is my model
class Usuario(models.Model):
user = models.ForeignKey(User)
nombres = models.CharField(max_length = 50)
correo = models.EmailField()
class Meta:
db_table = u'utp_users'
def __str__(self):
return str(self.nombres.encode('utf-8') )
this is mi form. py
class UsuarioForm(forms.ModelForm):
class Meta:
model = Usuario
fields = ['nombres','correo']
my url
url(r'^menu/update/(?P<usuario_id>\d+)$', 'utpapp.views.update'),
this my view update
#login_required(login_url='/')
def update(request,usuario_id):
form = UsuarioForm(request.POST)
if form.is_valid():
user = Usuario.objects.get(pk=usuario_id)
form = UsuarioForm(request.POST, instance = user)
form.save()
return redirect('/menu/')
else:
user = Usuario.objects.get(pk = usuario_id)
form = UsuarioForm(instance=user)
return render_to_response('form.html',{ 'form':form }, context_instance=RequestContext(request))
and the template i am do this
<a title="Editar informacion" href="/menu/update/{{usuario.id}}"><img src="/media/imagenes/usuario.png" class=" col-xs-3 col-md-7 quitar-float" alt="Editar informacion" ></a>
the problem is when i select the option update i get the this msj "Page not found (404)"
but i change in template href {{usuario.id}} for {{user.id}} is work but with user different what is the problem ??
Try this, you need to pass usuario as context to the template, and you can much simplify the code (especially the form for GET/POST, they are basically the same form, so don't repeat it) as like:
from django.shortcuts import get_object_or_404
#login_required(login_url='/')
def update(request,usuario_id):
user = get_object_or_404(Usuario, pk=usuario_id)
form = UsuarioForm(request.POST or None, instance=user)
if request.method == 'POST' and form.is_valid():
form.save()
return redirect('/menu/')
# you need to pass `usuario` as part of the context to template
# so you can access usuario.id in template
return render_to_response('form.html',{ 'form':form, 'usuario': user }, context_instance=RequestContext(request))
Also make sure you have a url route for /menu/, or else redirect will get you 404.
You forget to pass the usuario variable to the template.

Categories

Resources