check all forms then call save methd - django dynamic form - python

i've created a page which has a formset, i want to check all forms if they have error, then call save method, but create() automatically call save method! is there away to prevent it please ?
here is my views.py
def addNewGuestPopup(request):
if request.method == "POST":
form_no = int(request.POST.get('form_no'))
removed_form = request.POST.get('removed_form').split(",")
error_form_exits = []
new_guests = []
for i in range(form_no):
if str(i) not in removed_form:
full_name = request.POST.get('fullname-'+str(i))
dob = request.POST.get('dob-'+str(i)).split("-")
try:
visitor = Vistor.objects.get(full_name=full_name, dob=datetime.datetime(int(dob[0]), int(dob[1]), int(dob[2])))
error_form_exits.append(i)
except Vistor.MultipleObjectsReturned:
pass
except Vistor.DoesNotExist:
visitor = Vistor.objects.create(full_name=full_name,
dob=datetime.datetime(int(dob[0]), int(dob[1]), int(dob[2])),
admin=request.user)
new_guests.append(visitor)
# return JsonResponse({'error_form':error_form})
print(len(error_form_exits))
return JsonResponse({'data':list(Vistor.objects.values_list('full_name', flat=True)),
'error_form':error_form_exits}, safe=True)
return render(request, 'main/forms.html')
i dont want to use django formset is there a way to prevent create from save until all forms been checked please?
note : dob and full_name are unique together
thank you ..

Related

How To Update Specific Model Field From Django View Before Saving A Form

So, How can I update some Model Fields automatic, without the user having to input the values?
In Models:
class Url(models.Model):
long_url = models.CharField("Long Url",max_length=600)
short_url = models.CharField("Short Url",max_length=7)
visits = models.IntegerField("Site Visits",null=True)
creator = models.ForeignKey(CurtItUser,on_delete=models.CASCADE,null=True)
def __str__(self):
return self.short_url
In Views:
def home(request):
"""Main Page, Random Code Gen, Appendage Of New Data To The DB"""
global res,final_url
if request.method == 'POST':
form = UrlForm(request.POST)
if form.is_valid():
res = "".join(random.choices(string.ascii_uppercase,k=7))
final_url = f"127.0.0.1:8000/link/{res}"
form.save()
redirect(...)
else:
form = UrlForm
return render(...)
Sow how can for exapmle set from my view the value of short_url to final_url ???
You can get the data you need from the form.
you need to get the specific instance first, then you can use that instance to save values from the form.
And do not forget to save!
url_instance = get_object_or_404(Url, pk=pk)
url_instance.short_url = form.cleaned_data['short_url']
url_instance.long_url = form.cleaned_data['long_url']
url_instance.visits = form.cleaned_data['visits']
url_instance.save()
You can find more detailed infromations in the Django Documentation.

Grab an object in Django

This is probably very simple and basic but I'm struggling with grabbing a newly-created object in Django. It is for a basic library-style app. Over in models, I do this to create a Book object:
def add_book(self, postData, user_id):
title = postData['title']
first_name = postData['first_name']
last_name = postData['last_name']
user_obj = User.objects.get(id=user_id)
if not Author.objects.filter(first_name=first_name, last_name=last_name).exists():
author_obj = Author.objects.create(first_name=first_name, last_name=last_name)
else:
author_obj = Author.objects.get(first_name=first_name, last_name=last_name)
return self.create(title=postData['title'], created_by=user_obj, author=author_obj)
Then in views, I call that method and wish to redirect to a page specifically for that newly-created object. I think you can see that I have most of the code down, but don't know what to put in place of the "????".
def books_add(request):
if request.method == "POST":
errors = Book.objects.book_validation(request.POST)
if not errors:
Book.objects.add_book(request.POST, request.session['uid'])
book_id = Book.objects.get(????).id
return redirect('/books/book/{}/'.format(book_id))
else:
context = {
'errors' : errors,
}
1st part use get_or_create for retrieve or create a model entry
def add_book(self, postData, user_id):
title = postData['title']
first_name = postData['first_name']
last_name = postData['last_name']
user_obj = User.objects.get(id=user_id)
author_obj, created = Author.objects.get_or_create(first_name=first_name, last_name=last_name)
return self.create(title=postData['title'], created_by=user_obj, author=author_obj)
2nd part, return self.create return a Book entity :
def books_add(request):
if request.method == "POST":
errors = Book.objects.book_validation(request.POST)
if not errors:
book = Book.objects.add_book(request.POST, request.session['uid'])
return redirect('/books/book/{}/'.format(book.id))
else:
context = {
'errors' : errors,
}
There are some issues here. At the very least, look at Django Forms before you go much further. This is what a view that creates an object could look like:
def add_book(request):
if request.POST:
author, created = Author.objects.get_or_create(first_name=first_name,
last_name=last_name)
book = Book(title = request.POST['title'],
user_obj = request.GET['user'],
author = author,)
book.save()
return redirect('/books/book/{}/'.format(book.id))
else:
return render(request, 'book_form.html')
You really need to look into ModelForms to handle your POSTs. But start with looking at Forms.

Django models create data duplicate

1.Models's name is UserRecord.
2.Below is the code of my view.
#login_required
def data(request, page, keyword,strEncode):
current_username = request.user.username
data_s = dosomething() #It takes a long time!!!
UserRecord.objects.get_or_create(user=User.objects.get(username=current_username),MyRecords=keyword) # in order to create unique value
# or use below method
# if not UserRecord.objects.filter(user=User.objects.get(username=current_username),MyRecords=keyword):
# UserRecord.objects.create(user=User.objects.get(username=current_username),MyRecords=keyword)
return JsonResponse(data_s, safe=False)
Requested below URL several times with no interval,something like concurrent threading .
http://127.0.0.1:8000/data/1/test/english/
After this operation done,MyRecords column is populated by duplicate values.
I found something in Django document to use 'with transaction.atomic' to deal with this problem but it did not work.
You don't need to get user by User.objects.get(user=User.objects.get(username=current_username))
Instead use request.user for same.
#login_required
def data(request, page, keyword,strEncode):
current_user = request.user
data_s = dosomething()
UserRecord.objects.get_or_create(user=current_user,MyRecords=keyword) # in order to create unique value
return JsonResponse(data_s, safe=False)
And MyRecords=keyword will create a new record every time a new keyword is passed in the def data view, so please review your code.
Mysql
class UserRecord(models.Model):
user = models.ForeignKey(User)
MyRecords = models.CharField(max_length=128)
class Meta:
unique_together = (("user", "MyRecords"),) #mutil column uique idex
def __unicode__(self):
return self.user.username

django 1.8 - 'NoneType' object has no attribute 'aggregate'

The error is self clear. But I was puzzled at how to solve it.
If the form entry get the corresponding record in the database, then there is no error. But if I enter something in the form that doesn't have corresponding data in the database, then it would appear the error of 'NoneType' object has no attribute 'aggregate'. I know the reason is because no query result, so in def context it cannot continue the calculation.
So if there is anyway if not finding corresponding record in the database, then it will not continue to do the calculation in "def get_context_data" to avoid this error? So the page will just remain on the current data entry page without redirecting to the another page to show the result.
Any suggestion is appreciated, thanks in advance.
views.py
from django.contrib import messages
class FinalView(ListView):
context_object_name = 'XXX'
template_name = 'XXX.html'
model = Final
def get_queryset(self):
form = InputForm(self.request.GET)
if form.is_valid():
department = form.cleaned_data['department']
person = form.cleaned_data['person']
if department !="" and person !="":
if Final.objects.filter(department=department,person=person).exists():
queryset=Final.objects.filter(department=department,person=person)
return queryset
else:
form.add_error(ValidationError('No corresponding data exists'))
elif department =="" and person !="":
if Final.objects.filter(person=person).exists():
queryset=Final.objects.filter(person=person)
return queryset
else:
form.add_error(ValidationError('No corresponding data exists'))
elif ........
else: #if form not valid
messages.error(request, "Error")
def get_context_data(self,**kwargs):
context["sales"] = self.get_queryset().aggregate(Sum('sales'))
EDIT as suggest
.........Before are the same....
def get_context_data(self,**kwargs):
query_set = self.get_queryset()
if query_set is not None:
context = super(FinalView, self).get_context_data(**kwargs)
context["sales"] = query_set.aggregate(Sum('sales'))
return context
Use the fact that django query sets are are lazy to your advantage, it won't make a database query till it needs the data so just split it up to do some validation
query_set = self.get_queryset()
context = super(FinalView, self).get_context_data(**kwargs)
if query_set is not None:
context['sales'] = query_set.aggregate(Sum('sales'))
return context
You may also want to make sure that all paths from get_queryset do actually return something to make this kind of validation easier.

How to pass data between django views

This questions addresses my question genearally, but I am looking for a more specific explanation.
I would like a user to update a a group of model objects, however, the queryset for these objects will need to be retrieved first. My plan is to do this in two seperate URs/views, getting the query set info from the first, then displaying the model formset to be updated next.
My first view gives a list of all the the "Project"s (One of my models), and retrieves the id of the project selected.
Here is the form:
class ProjectLookupForm(forms.Form):
Project_Name = chosenforms.ChosenModelChoiceField(queryset=Project.objects.all())
and here is the view:
def update_project_filter(request):
project_form = ProjectLookupForm(request.POST or None)
if request.method == 'POST':
if project_form.is_valid():
context = {"project_form":project_form}
# Get project here and share it with the next view.
selected_project_id = project_form.cleaned_data["Project_Name"].id
# Add a new return statement here?
# Or call update project view from here?
# Add a redirect button to html?
else:
errors = project_form.errors
context = {"errors":errors, "project_form":project_form}
else:
context = {"project_form":project_form}
return render(request, 'filter_update_project_form.html', context)
As one can see, I have included some comments brainstorming what my possibilities are. My goal is to send the selected_project_id to this next view, so that it can use that id as a model form query set.
def update_project(request):
UpdateFormset = modelformset_factory(Sample, fields=("sample_name", "extraction_date",
"project", "order", "notebook", "notebook_page"))
if request.method == 'POST':
formset = UpdateFormset(request.POST, request.FILES)
if formset.is_valid():
formset.save()
context = {"formset": formset, "project_form":project_form}
else:
errors = formset.errors
context = {"formset":formset, "errors":errors, "project_form":project_form}
else:
formset = UpdateFormset(queryset=Sample.objects.filter(project=2))
context = {"formset":formset, "project_form":project_form}
return render(request, 'update_project_form.html', context)
One can see here that I have hard coded the queryset like so:
queryset=Sample.objects.filter(project=2)
How can I set "project=" to my selected_project_id? Do I pass this info to the view as an input parameter? Or do I send it to the next URL and take it from there?
Assuming you've activated django.contrib.sessions.middleware.SessionMiddleware; you can pass data between views using request.session dictionary as follows:
def update_project_filter(request):
...
selected_project_id = project_form.cleaned_data["Project_Name"].id
request.session['selected_project_id'] = selected_project_id
...
def update_project(request):
...
selected_project_id = request.session.get('selected_project_id')
...

Categories