Problem with saving a property of an object after validation - django

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)

Related

Django update functionality

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.

How to link two forms (wagtail form and django form) with a foreign key?

I'm using a django form in conjunction with a wagtail form. The django form will record some fields that will be on any form of this type: name, email and the wagtail form will record extra data defined by the form page creator specific to that instance.
I've overloaded the serve method to capture both sets of data and I can process both forms, but I'm stuck when trying to add the logic to relate the form contents to each other so that when one submission set is deleted, the other set will be as well. I think what I need is a foreign key.
The following code fails at form_submission.event_submission = a.id where I'd like to take the id from the wagtail form submission and add that as a foreign key to the django form, so that when the wagtail form portion is deleted, the other is deleted as well, and so that I can have a usable link between the two form submissions.
def serve(self, request, *args, **kwargs):
if request.method == 'POST':
form = EventSignupForm(request.POST)
wagtail_form = self.get_form(request.POST, request.FILES, page=self, user=request.user)
if form.is_valid() and wagtail_form.is_valid():
a = self.process_form_submission(wagtail_form)
form_submission = form.save(commit=False)
form_submission.event_submission = a.id
form_submission.save()
return self.render_landing_page(request, form_submission, *args, **kwargs)
else:
form = EventSignupForm()
wagtail_form = self.get_form(page=self, user=request.user)
context = self.get_context(request)
context['form'] = form
context['wagtail_form'] = wagtail_form
return TemplateResponse(
request,
self.get_template(request),
context
)
The form submission class and django model form looks like this. I think the ForeignKey I have in the Model isn't right, but I don't know. Any help?
class EventFormSubmission(AbstractFormSubmission):
cancellation_id = models.CharField(max_length=7)
class EventSignup(models.Model):
"""
A model to contain signup info for an event: name, email.
"""
event_submission = models.ForeignKey(EventFormSubmission, on_delete=models.CASCADE)
name = models.CharField(max_length=100)
email = models.EmailField()
I solved this by adding the extra fields I wanted (name, email) to the EventFormSubmission and then using a regular django form (not a ModelForm) to collect these pieces of information.

Why the Django extended user model is not able to show pre-populated data in while updating the fields?

I have written a program to update the User default fields(email with the help of UserCreationForm) and Extended User models(DOB, country etc). Below is the function:
#login_required(login_url="/login/")
def editUserProfile(request):
if request.method == "POST":
form = UserProfileUpdateForm(request.POST, instance=request.user) # default user profile update
obj = UserProfile.objects.get(user__id=request.user.id) # custom User fields.
form1 = UserProfileForm(request.POST or None, instance=obj)
if form.is_valid() and form1.is_valid():
obj.Photo = form1.cleaned_data['Photo']
obj.dob = form1.cleaned_data['dob']
obj.country = form1.cleaned_data['country']
obj.State = form1.cleaned_data['State']
obj.District = form1.cleaned_data['District']
obj.phone = form1.cleaned_data['phone']
form.save()
form1.save()
messages.success(request, f'updated successfully')
return redirect('/profile1')
else:
messages.error(request, f'Please correct the error below.')
else:
form = UserProfileUpdateForm(instance=request.user)
form1 = UserProfileForm(instance=request.user)
return render(request, "authenticate\\editProfilePage.html", {'form': form, 'form1': form1})
With the help of above method I am able to update the user data. However, the issue is when I click on the "update" button on my profile page the next page that I get to enter new data to the fields doesn't come with pre-populated data. i.e, the "email" field has the pre-populated data, but the custom fields like (country, dob, state) are blank, ideally it they should have existing data showing to the user after the user click on the "update" button from the profile page.
Any idea. I hope I was able to explain. Please let me know if any other query(s).
Thank you
You are sending the same form:
form = UserProfileUpdateForm(instance=request.user)
form1 = UserProfileUpdateForm(instance=request.user)
email and the custom fields are in 2 separate forms.
2nd solution:
Try:
default_data_profile = UserProfileForm.objects.get(user=obj)
form1 = UserProfileForm(initial = default_data_profile, instance=obj)

Create, get and edit user information in same form and template

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)

Django Foreign Key to a yet-to-be created Model

I'm wondering if there's way in Django to associate a model to another, yet-to-be created model with a foreign key. Both model would be created using the same ModelForm in the same HTML page.
e.g.
class Team(models.Model):
name = forms.CharField
...
class Player(models.Model):
name = forms.CharField()
key = forms.ForeignKey(Team)
...
Basically, I'm wondering if both these models can be put in the same <form>...</form> in one HTML page.
a foreign key is a reference to the primary key of the referenced model, so the target needs to exist. you need to save the first form, and then update the reference on the second one before saving. to get a model instance from a form without saving to the db, you can use
instance = form.save(commit=False)
you then need to save the instance yourself
instance.save()
and if you are using many-to-many fields, you need to look at save_m2m
You may want to check the documentation for inlineformset, it allows to edit the related objects of a model in the same view, also see formsets.
def manage_teams(request, team_id):
team = Player.objects.get(pk=team_id)
PlayerInlineFormSet = inlineformset_factory(Player, Team)
if request.method == "POST":
formset = PlayerInlineFormSet(request.POST, request.FILES, instance=team)
if formset.is_valid():
formset.save()
# Do something.
else:
formset = PlayerInlineFormSet(instance=team)
return render_to_response("manage_teams.html", {
"formset": formset,
})
Here goes another example:
from django.forms.models import inlineformset_factory
def new_team(request):
PlayerInlineFormSet = inlineformset_factory(Team, Player)
team= Team()
if request.method == 'POST':
form_team = TeamForm(request.POST, request.FILES, instance= team, prefix= 'team')
form_player = PlayerInlineFormSet(request.POST, request.FILES, instance= team, prefix= 'players')
if form_team.is_valid() and form_player.is_valid():
form_team.save()
form_player.save()
return HttpResponseRedirect('/teams/%s/' % team.slug)
else:
form_team = TeamForm( instance= team, prefix= 'team')
form_player = PlayerInlineFormSet(instance= team, prefix= 'players')
return render_to_response('Teams/new_team.html', {'form_team': form_team, 'form_player':form_player}, context_instance=RequestContext(request))