I've got a model, with two forms. When a calf is scanned in, it gets one set of information, then when it's shipped out, it's a separate form with different information. For example when scanned in, it takes DOB and arrival date, when scanned out we need ship out date, milk consumed during it's stay(2 quarts per day), where it is going, and any medication while at the depot.
Right now I have the two forms below:
Scan in form
scan out form
Now you can see when I try to update an entry I get an error that it already exists
Here is my view:
def scanoutcalf(request, id=None):
form = ScanOutForm(request.POST or None)
context = {
'form': form,
}
form = ScanOutForm(request.POST or None)
if form.is_valid():
form.save()
return render(request, 'calves/scan_out.html', context)
And my forms:
class ScanOutForm(forms.ModelForm):
class Meta:
model = Calf
fields = [
'eid', 'ship_out_date', 'program', 'destination', 'medical_history', 'milk_consumed'
]
widgets = {
'ship_out_date': forms.widgets.DateInput(
attrs={'type': 'date'}
)
}
I've googled around, but couldn't find an example of how to update without having to create a queryset or a URL with instance ID.
The idea here is that a user can just scan when calves are leaving, update with the information that is essential, and the form will check the EID, and update the DB if it exists, or create it if it doesn't. Any help would amazing
Query the instance before saving and pass into ScanOutForm as keyword argument instance.
Like so:
def scanoutcalf(request, id=None):
form = ScanOutForm(request.POST or None)
context = {
'form': form,
}
if request.method == 'POST':
try:
calf = Calf.objects.get(eid=request.POST['eid'])
except:
calf = None
if calf is not None:
form = ScanOutForm(request.POST, instance=calf)
if form.is_valid():
form.save()
return render(request, 'calves/scan_out.html', context)
Note: As you use unique identifier in the form this must be directly extracted from request.POST with validation.
Related
I have a Form (Formset) for users to update their profiles. This is a standard User model form, and custom Participants model form. Now, in cases when a participant provide his phone number, I need to refresh the whole Form with a new 'Code' filed dynamically. And the participant will type the code he received my SMS.
Here is how I am trying to do it:
def post(self, request, *args, **kwargs):
self.object = self.get_object()
form = self.get_form()
if form.is_valid():
form.save()
seller_form = SellerForm(self.request.POST, instance=self.object.seller)
if seller_form.is_valid():
seller = self.request.user.seller
seller.inn = seller_form.cleaned_data.get('inn')
if seller_form.cleaned_data.get('phone_number'):
seller_form.fields['code'] = models.CharField(max_length=4)
return render(request, self.template_name, {'form': form, 'seller_form': seller_form})
seller.save()
return HttpResponse('Seller updated')
return render(request, self.template_name, {'form': form, 'seller_form': seller_form})
Well I am not sure if this is the way I can add additional field. What would you suggest to handle this situation?
A technique I have used is to have an initially hidden field on the form. When the form otherwise becomes valid, I cause it to become visible, and then send the form around again. In class-based views and outline:
class SomeThingForm( forms.Modelform):
class Meta:
model=Thing
fields = [ ...
confirm = forms.BooleanField(
initial=False, required=False, widget=forms.widgets.HiddenInput,
label='Confirm your inputs?' )
class SomeView( CreateView): # or UpdateView
form_class = SomeThingForm
template_name = 'whatever'
def form_valid( self, form):
_warnings = []
# have a look at cleaned_data
# generate _warnings (a list of 2-tuples) about things which
# aren't automatically bad data but merit another look
if not form.cleaned_data['confirm'] and _warnings:
form.add_error('confirm', 'Correct possible typos and override if sure')
for field,error_text in _warnings:
form.add_error( field, error_text) # 'foo', 'Check me'
# make the confirm field visible
form.fields['confirm'].widget = forms.widgets.Select(
choices=((0, 'No'), (1, 'Yes')) )
# treat the form as invalid (which it now is!)
return self.form_invalid( form)
# OK it's come back with confirm=True
form.save() # save the model
return redirect( ...)
For this question, I think you would replace confirm with sms_challenge, a Charfield or IntegerField, initially hidden, with a default value that will never be a correct answer. When the rest of the form validates, form_valid() gets invoked, and then the same program flow, except you also emit the SMS to the phone number in cleaned_data.
_warnings = []
# retrieve sms_challenge that was sent
if form.cleaned_data['sms_challenge'] != sms_challenge:
_warnings.append( ['sms_challenge', 'Sorry, that's not right'] )
if _warnings:
...
form.fields['sms_challenge'].widget = forms.widgets.TextInput
return self.form_invalid( form)
I think that ought to work.
In my CreateView class I created an instance of my Wholesale_Client model.
Inside form_valid() function I am fetching from my form some information which I will use in create_woocommerce_client_individually() function in order to post this record in my woocommerce website.
Every user in woocommerce website has a post id which I have it as attribute in my Wholesale_Client model.
My aim is after storing the wholesale client instance in my db and in woocommerce website(successfully), to fetch the current stored wholesale client record in order to update the post id of this user(from null to post id).
How can I update information after fetching the record?
Here is my code:
Function for creating a woocommerce client in the website
def create_woocommerce_client_individually(wcapi,name,surname,email):
data = {
"first_name": name,
"last_name": surname,
"email": email,
}
wcapi.post("customers", data).json()
Function for giving the customer id from woocommerce website , using the api, to my record.
def give_cid_to_client_individually(wcapi,email):
r=wcapi.get("customers?email="+str(email)).json()
post_id=r[0]['id']
fetched_client=Wholesale_Client.objects.get(email=email)
fetched_client.cid=int(post_id)
fetched_client.save()
Here (is the problem) despite the fact that the record is fetched successfully the post_id is not saved to the cid attribute of my model.
My CBV
class WholesaleClientCreateView(LoginRequiredMixin, CreateView):
model = Wholesale_Client
form_class = WholesaleClientForm
success_url = reverse_lazy('wholesale_clients_list')
template_name='wholesale_clients/wholesale_client_create_form.html'
def form_valid(self, form):
print("Inside form valid...\n")
if self.request.method == 'POST':
form = WholesaleClientForm(self.request.POST)
if form.is_valid():
name = form.cleaned_data['name']
surname = form.cleaned_data['surname']
email = form.cleaned_data['email']
wcapi=get_wcapi()
create_woocommerce_client_individually(wcapi,name,surname,email)
form.save()
give_cid_to_client_individually(wcapi,email)
else:
form = WholesaleClientForm()
return super(WholesaleClientCreateView, self).form_valid(form)
I had to call the self.object to have reference on the current object of my model in order to update correctly the desired property(cid).
Here is the solution:
def form_valid(self, form):
print("Inside form valid...\n")
if self.request.method == 'POST':
form = WholesaleClientForm(self.request.POST)
if form.is_valid():
self.object = form.save(commit=False)
name=self.object.name
#print("name : {} ".format(name))
surname=self.object.surname
#print("surname : {} ".format(name))
email=self.object.email
#print("email : {} \n".format(email))
wcapi=get_wcapi()
create_woocommerce_client_individually(wcapi,name,surname,email)
r=wcapi.get("customers?email="+str(email)).json()
post_id=r[0]['id']
self.object.cid=post_id
self.object.save()
else:
form = WholesaleClientForm()
return super(WholesaleClientCreateView, self).form_valid(form)
How do I display the deleted content from an existing form to a completely separate URL, Where it displays the deleted items in django. I've been trying to figure out how to create a separate table where it displays all the items that I've deleted
I can't figure out what I should put in my function key
from django.shortcuts import render, redirect
from employee.forms import EmployeeForm
from employee.models import Employee
# Create your views here.
def emp(request):
if request.method == "POST":
form = EmployeeForm(request.POST)
if form.is_valid():
try:
form.save()
return redirect('/show')
except:
pass
else:
form = EmployeeForm()
return render(request,'index.html',{'form':form})
def show(request):
employees = Employee.objects.all()
return render(request,"show.html",{'employees':employees})
def edit(request, id):
employee = Employee.objects.get(id=id)
return render(request,'edit.html', {'employee':employee})
def update(request, id):
employee = Employee.objects.get(id=id)
form = EmployeeForm(request.POST, instance = employee)
if form.is_valid():
form.save()
return redirect("/show") enter code here
return render(request, 'edit.html', {'employee': employee})
def destroy(request, id):
employee = Employee.objects.get(id=id)
employee.delete()
return redirect("/show")
So if you want to display all of your deleted employees, then you cannot do employee.delete(), since this removes the record from the underlying database.
Instead think of a flag (i.e. a boolean value) that you attach to your Employee model - for example "deleted" with a default value False. Once you go into your destroy function you just do
employee.deleted =True
employee.save()
and in your show function you do the following:
Employee.objects.filter(deleted=False)
On your separate URL where you want to display all the deleted employees you do
Employee.objects.filter(deleted=True)
You can also work with custom model managers there.
this is my first post here and I am very new to Django but I just can't seem to find a solution for this problem... I've searched stackoverflow and google but nothing seems to work for me...
I have a wine-app and want to be able to add and remove wines from the user's stock. In the list of wines the user can choose a wine to add and the ID of this wine is passed in the POST data. Since the data is getting lost after the first time the view is rendered I saved the ID in a cookie, which is working, but the problem is when I work with ModelForm de user has to select the foreign key for the user and for the wine, which is bad, so I tried to make it hidden and set the Fk_user and Fk_wine after the user choose the number of bottles to be added but before validation. Here's the problem after google everyone suggested I should use the "initial" and pass that to the form, but this is clearly not working because if I make the fields visible in the form I can see that it is not preselected...
viewy.py:
def addStockView(request):
wineId = request.POST.get('addStock')
if 'addStock' in request.POST:
wine = get_object_or_404(Wine, idwine=int(wineId))
userId = request.user.id
user = get_object_or_404(AuthUser, id=userId)
if request.method == 'POST':
#wineIdNew = request.COOKIES.get('wineIdToAdd')
#wineNew = get_object_or_404(Wine, idwine=wineIdNew)
form = StockForm(request.POST, initial={'fk_wine': wineNew.idwine, 'fk_auth_user': user.id})
if form.is_valid():
form.save()
return redirect('home')
else:
form = StockForm(initial={'fk_wine': wine.id,
'fk_auth_user': user.id})
response = render(request, 'addToStock.html', {'form': form})
response.set_cookie('wineIdToAdd', wineId)
return response
forms.py:
class StockForm(forms.ModelForm):
#fk_wine = ModelChoiceField(queryset=Wine.objects.all(),
# widget=HiddenInput())
#fk_auth_user = ModelChoiceField(queryset=AuthUser.objects.all(),
# widget=HiddenInput())
class Meta:
model = UserWineStock
fields = ['fk_auth_user', 'fk_wine', 'number']
can anyone help me with this..?
Yes, initial data is ignored when a form is bound to submitted data.
Instead of using initial here, you should exclude those two fields from the form and set them on the created object:
form = StockForm(request.POST)
if form.is_valid():
item = form.save(commit=False)
item.fk_wine = wine
item.fk_auth_user = request.user
item.save()
return redirect('home')
(Also, please don't call your fields things like fk_auth_user. Just call it user.)
I'm trying to retrieve data from user. The form where i want to show the user information is also the same that i use to update this information.
Update3
After some updates I make this work and this is my code. If somenone have a better way to do this can share it :)
models.py
from django.db import models
from django.contrib.auth.models import User
# Create your models here.
class informacionFacturacion(models.Model):
usuario = models.ForeignKey(User, on_delete=models.CASCADE)
apellidos = models.CharField(max_length=100)
nombres = models.CharField(max_length=100)
[More fields...]
def __str__(self):
self.apellidos
forms.py
from .models import informacionFacturacion
#Create your forms here.
class informacionFacturacionForm(ModelForm):
class Meta:
model = informacionFacturacion
fields = [
"usuario",
"apellidos",
"nombres",
[More fields...]
]
views.py
#login_required
def datosPersonales(request):
#Filter query by user ID
query = informacionFacturacion.objects.filter(usuario=request.user)
form = informacionFacturacionForm()
#If query has content, edit record, else, create a new record
if query:
if request.method == "POST":
form = informacionFacturacionForm(request.POST or None, instance=query[0])
if form.is_valid():
edit_content = form.save()
edit_content.save()
else:
if request.method == "POST":
form = informacionFacturacionForm(request.POST)
if form.is_valid():
create_content = form.save(commit=False)
create_content.save()
return HttpResponseRedirect(reverse('datosPersonales'))
context = {
"titulo": "Datos personales | Co.",
"body_class": "class= sidebar_main_open sidebar_main_swipe",
"form": form,
"infoFacturacion": query,
}
template = "micuenta/datosPersonales.html"
return render(request, template, context)
Thanks for the support.
At first glance, it seems that the informacionFacturacion table is not being populated. Have you checked that the instance.save() is reached? (in other words, that the form is valid)
Second, in the template you want to use the informacionFacturacion object as the form elements, and you are handling them separately. Do:
if request.POST:
form = informacionFacturacionForm(request.POST)
if form.is_valid():
instance = form.save(commit=False)
instance.save()
else:
# handle here the form error's, maybe report it in the template
else:
query = informacionFacturacion.objects.filter(usuario=request.user)
form = informacionFacturacionForm(instance=query[0])
and render the form parameter insead of infoFacturacion:
{{ form.as_p }}
finally, make sure that your template form id's matches the form element names, otherwise the form won't be filled.
UPDATE
Based on your edit, now the error is in this line:
form = informacionFacturacionForm(request.POST, instance=query_id)
query_id is an int, and it is expecting a model. Change the following line:
query_id = informacionFacturacion.objects.get(usuario=request.user).id
to
query = informacionFacturacion.objects.get(usuario=request.user)
and the faulty line to:
form = informacionFacturacionForm(request.POST, instance=query)
that should work for now, although code can be simplified a lot.
EDIT 2
Here is what I assume you want:
#login_required
def datosPersonales(request):
query = informacionFacturacion.objects.filter(usuario=request.user)
if request.method == "POST": # This will handle the template form's POST
form = informacionFacturacionForm(request.POST)
if form.is_valid():
asd = form.save(commit=False)
asd.save()
# Here you may want to redirect to somewhere else
# Im not sure here, I guess that you want to handle the GET method if
# there is no form in the request. Post your template form to see what
# is happening.
else:
form = informacionFacturacionForm(instance=query)
# you dont need to save it, it is already in DB
context = {
"titulo": "Datos personales | Co.",
"body_class": "class= sidebar_main_open sidebar_main_swipe",
# I think here is your main issue, you are handling a form object
# AND a infoFacturacion object. You need to use just the
# form object in the template and render it accordingly.
"form": form,
"infoFacturacion": query,
}
template = "micuenta/datosPersonales.html"
return render(request, template, context)
Well, I was with the same problem on my sytem, so I made this solution, maybe it works to you! =D
I'm changing the value of the submit button and using the same form:
<button type="submit" id="submitButton" name="button" value="">Save</button>
If is a new task, I change the value of the button with JQuery:
$('#submitButton').val('new');
And if is an edition, I change the value again:
$('#submitButton').val('edit');
On my views.py, I check if is an edit or a new save by the value of the button:
def index(request):
tasks = Task.object.filter()
context = {
'tasks': tasks
}
if request.method == 'POST':
form = NewTask(request.POST or None)
if request.POST['button'] == 'new':
if form.is_valid():
context['is_valid'] = True
form.save()
form = NewTask()
else:
context['is_valid'] = False
if request.POST['button'] == 'edit':
instance = Task.object.filter(pk=request.POST['id']).first()
form = NewTask(request.POST, instance=instance)
if form.is_valid():
context['is_valid'] = True
form.save()
else:
context['is_valid'] = False
else:
form = NewTask()
context['form'] = form
return render(request, 'index.html', context)