I have a save method on my model which I would like to use to validate the fields (I did this in my views before but it was just messy!). I'm saving an object rather than a form because I was having some difficulties with the form validation.
I haven't used save methods before, but I assume they trigger when you use the .save() command? Mine isn't triggering at all... Also from what I understand a clean() method is run for forms when you use is_valid(), so isn't useful for me here?
Here is my view that saves an object using ajax
#login_required
def createtimesheet(request):
if request.method == "POST":
print "creating timesheet"
# Get the person from the previous view
person_object = request.session.get('person')
person = Person.objects.get(id=person_object)
# get the POST data
start_date = request.POST.get('datestart')
end_date = request.POST.get('dateend')
start_date_formatted = datetime.strptime(start_date, "%m/%d/%Y")
end_date_formatted = datetime.strptime(end_date, "%m/%d/%Y")
start_date_print = start_date_formatted.strftime("%B")[0:3] + ". " + start_date_formatted.strftime("%d") + ", " + start_date_formatted.strftime("%Y")
end_date_print = end_date_formatted.strftime("%B")[0:3] + ". " + end_date_formatted.strftime("%d") + ", " + end_date_formatted.strftime("%Y")
response_data = {}
# create our messages
message = ""
error = ""
todays_date = datetime.now()
print_date = todays_date.strftime("%A")
# now we can create the timesheet!
peach = TimeSheet(start_date=start_date_formatted, end_date=end_date_formatted, person_id=person)
# need an if valid.....?
peach.save()
message = "Created new timesheet"
response_data['startdate'] = start_date_print
response_data['enddate'] = end_date_print
response_data['status'] = peach.status
print response_data
context = {
"person": person,
"message": message,
"error": error,
"print_date": print_date,
"todays_date": todays_date,
}
return JsonResponse(response_data)
And here is where I have attempted to write a save method... I'm planning to have a much longer validation function to check if the dates fall on certain days, but for now I just want to get this to work.
class TimeSheet(models.Model):
O = "Open"
S = "Submitted"
A = "Approved"
R = "Needs review"
STATUS_CHOICES = (
(O, "Open"),
(S, "Submitted"),
(A, "Approved"),
(R, "Needs Reviewing"),
)
start_date = models.DateField()
end_date = models.DateField()
person_id = models.ForeignKey(Person)
status = models.CharField(max_length= 50, default="Open", choices=STATUS_CHOICES)
submitted_id = models.IntegerField(default=0)
approved_id = models.IntegerField(default=0)
submitted_date = models.DateTimeField(auto_now_add=True, blank=True)
approved_date = models.DateTimeField(auto_now_add=True, blank=True)
# def __str__(self):
# return self.id
def get_absolute_url(self):
return reverse('tande:timesheet', kwargs={'id': self.id})
def __init__(self, *args, **kwargs):
print "initiating a timesheet"
super(TimeSheet, self).__init__(*args, **kwargs)
def save(self, *args, **kwargs):
print "something is trying to save!"
ok_to_continue = True
start_date = self.start_date
end_date = self.end_date
if ok_to_continue:
if end_date < start_date:
error = "Start date must be before end date"
ok_to_continue = False
if ok_to_continue:
super(TimeSheet, self).save(*args, **kwargs)
else:
print "def save did not work"
Thanks!
Edit: here is the ajax call
$( document ).ready(function() {
$('#timesheet-form').on('submit', function(event){
event.preventDefault();
console.log("add a timesheet");
createtimesheet();
});
function createtimesheet() {
console.log("create timesheet is working!")
$.ajax({
url : "{% url 'tande:createtimesheet' %}",
type: "POST",
data: { datestart : $('#start').val(), dateend : $('#end').val()},
success : function(json) {
$('#start').val('');
$('#end').val('');
console.log(json);
var html = '<tr><td>'+json.startdate+'</td><td>'+json.enddate+'</td><td>'+json.status+'</td><</tr>';
console.log("success");
// $('div#talk').html(html);
$('#timesheet-list').append(html);
console.log(html)
overlay();
},
error : function(xhr,errmsg,err) {
// $('#results').html("<div class='alert-box alert radius' data-alert>Oops! We have encountered an error: "+errmsg+
// " <a href='#' class='close'>×</a></div>"); // add the error to the dom
console.log("uh oh");
}
});
};
})
URLs:
from django.conf.urls import url
from . import views
urlpatterns = [
url(r'^$', views.index, name='index'),
url(r'^people/$', views.people, name='people'),
url(r'^people/create_person/$', views.create_person, name='create_person'),
url(r'^(?P<person_id>[0-9]+)/person/$', views.person, name='person' ),
url(r'^person/createtimesheet/$', views.createtimesheet, name='createtimesheet' ),
url(r'^(?P<timesheet_id>[0-9]+)/person/timesheet/$', views.timesheet, name='timesheet' ),
]
form id didn't match the id in the ajax call...
id in html is 'create-timesheet-form' and ajax was calling 'timesheet-form'
-.-
Related
I've been trying to figure out why get_object_or_404 can't find an object that exists but I can't figure it out. So the problem is occuring when I try to call this function like this.
JS Ajax to call function:
var url;
url = {{ OrderItem.change_item_quantity}};
$.ajax(
{
type: "GET",
url: url,
data: {
newquantity: realquantity
},
success: function(data) {
console.log("success")
spinner{{ forloop.counter0 }}.addClass(pauseClass);
$("#totalprice{{ forloop.counter0 }}").css("display", "block")
},
error: function(errordata) {
console.log(errordata)
}
})
changeTimer = false;
},300);
This calls a function in my OrderItem model (models.py):
class OrderItem(models.Model):
user = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.CASCADE)
ordered = models.BooleanField(default=False)
item = models.ForeignKey(VarientItem, on_delete=models.CASCADE)
quantity = models.IntegerField(default=1)
def __str__(self):
return f"{self.quantity}x {self.item.item.title} of varient {self.item.varient} for {self.user.email}"
def get_item_total(self):
return (self.item.final_price * self.quantity)
def change_item_quantity(self):
return reverse("core:change_item_quantity", kwargs={
'slug': self.item.item.slug,
'ordervarient': self.item.varient,
'orderfinalprice': self.item.final_price
})
class VarientItem(models.Model):
item = models.ForeignKey(Item, on_delete=models.CASCADE)
varient = models.JSONField(blank=True, null=True)
final_price = models.DecimalField(max_digits=7, decimal_places=2)
def __str__(self):
return self.item.title
My url for change_item_quantity:
urlpatterns = [
path('change_item_quantity/<slug>/<ordervarient>/<orderfinalprice>', views.change_item_quantity, name='change_item_quantity')
]
Finally, my function actually lives in views.py:
def change_item_quantity(request, slug, ordervarient, orderfinalprice):
if request.method == 'GET':
new_quantity_str = request.GET.get('newquantity', None)
new_quantity = ast.literal_eval(new_quantity_str)
try:
new_quantity_int = int(new_quantity)
if int(new_quantity) <= 0:
raise ValueError("Numbers can't be negative")
except:
response = HttpResponse('Quantity not Accepted', status=406)
return response
product = get_object_or_404(Item, slug=slug)
varient_item = get_object_or_404(VarientItem, item=product, varient=ordervarient, final_price=orderfinalprice)
order_item = get_object_or_404(OrderItem, item=varient_item, user=request.user, ordered=False)
order_item.quantity = new_quantity
order_item.save()
response = HttpResponse({"new_quantity": new_quantity, "new_total": new_quantity*orderfinalprice, "items_in_cart": str(get_items_in_cart(request).content)}, status=200)
return response
However, the problem is that once it gets to the variable varient_item, the get_object_or_404 returns a 404 error instead of finding the object. I've narrowed it down specifically to the varient variable that causes the issue. When I remove that it is able to find the object. However, looking at my models in the admin page and printing out what ordervarient equals, they are exactly the same (equal to each other). Printing order_varient would give me:
{'top': 'red', 'knob': 'black', 'bottom': 'white', 'middle': 'yellow'}
And looking at my admin page, VarientItem.varient has the value:
{"top": "red", "knob": "black", "bottom": "white", "middle": "yellow"}
Printing out the other fields yields the exact same values too. So clearly all the values are the same, so idk why get_object_or_404 isn't returning anything. I tried objects.filter too, but it also returned no object.
The database I'm using is postgres if that helps.
I have a project with a model called "List," and a model called "ListItem." There are multiple list items to each list. Here's what I'd like to do. I'd like the user to be able to create a new list with as many items as they deem necessary on one form.
Here's the logic I have so far:
models.py:
class List(models.Model):
team = models.ForeignKey(Team, on_delete=models.CASCADE)
name = models.CharField(max_length=50)
def __str__(self):
return self.name
class ListItem(models.Model):
team_list = models.ForeignKey(List, on_delete=models.CASCADE)
content = models.TextField()
index = models.IntegerField()
def __str__(self):
return f"{self.team_list} [{self.index}]"
forms.py:
class NewListForm(forms.ModelForm):
name = forms.CharField(max_length=50, label='Card Name')
team = forms.ModelChoiceField(queryset=models.Team.objects.all())
class Meta:
model = models.List
fields = ['name', 'team']
class NewListItemForm(forms.ModelForm):
content = forms.CharField(widget=forms.Textarea,
label='Item', required=True)
class Meta:
model = models.ListItem
fields = ['content']
views.py:
def new_list(request):
context = {
'title': 'New List',
'list_form': NewListForm,
'list_item_form': NewListItemForm,
}
if request.method == 'POST':
list_form = NewListForm(request.POST)
list_item_form = NewListItemForm(request.POST)
if list_form.is_valid() and list_item_form.is_valid():
list_instance = list_form.save()
list_item_instance = list_item_form.save(commit=False)
list_item_instance.team_list = list_instance
list_item_instance.index = 1
list_item_instance.save()
messages.success(request, "List has been created!")
return redirect('home')
else:
messages.error(request, "That list name is already taken")
return render(request, 'lists/new_list.html', context)
This works for creating 1 list and just 1 item. Ultimately, I'd like the user to be able to add as many additional list item forms as is necessary AND have the "index" field of each item on that list increment by 1 with each new list item instance.
Is there some way to loop through each instance of a repeated form and save a unique instance in my db an indefinite number of times?
I don't think you need to increment the index yourself, django should increment it automatically. I used formset_factory and javascript on my template to have the ability to add fields to the form dynamically. I am not very familiar with django or javascript (I'm very early in the learning process), but this is how I got it to work in my case:
models.py
class Instructors(models.Model):
instructors = models.CharField(max_length=60)
injury = models.ForeignKey("Injury", on_delete=models.CASCADE)
forms.py
class InstructorForm(forms.Form):
instructor = forms.CharField(max_length=60, required=False)
InstructorFormset = formset_factory(InstructorForm, extra=1)
views.py (relevant section)
...
formset = InstructorFormset(request.POST)
if formset.is_valid()
for form in formset:
if form.cleaned_data:
instructor = Instructors(
instructors=form.cleaned_data["instructor"],
injury=injury,
)
instructor.save()
...
context = {"formset":formset}
template.html
{{ formset.management_form }}
{% for form in formset %}
<div class="row form-row spacer">
{{ form.instructor }}
<div class="input-group-append">
...
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.5.1/jquery.min.js"></script>
<script type='text/javascript'>
function updateElementIndex(el, prefix, ndx) {
var id_regex = new RegExp('(' + prefix + '-\\d+)');
var replacement = prefix + '-' + ndx;
if ($(el).attr("for")) $(el).attr("for", $(el).attr("for").replace(id_regex, replacement));
if (el.id) el.id = el.id.replace(id_regex, replacement);
if (el.name) el.name = el.name.replace(id_regex, replacement);
}
function cloneMore(selector, prefix) {
var newElement = $(selector).clone(true);
console.log(newElement);
var total = $('#id_' + prefix + '-TOTAL_FORMS').val();
newElement.find(':input:not([type=button]):not([type=submit]):not([type=reset])').each(function() {
var name = $(this).attr('name');
if (name != undefined) {
console.log(name);
console.log(total);
var name = name.replace('-' + (total-1) + '-', '-' + total + '-');
console.log("next");
};
var id = 'id_' + name;
$(this).attr({'name': name, 'id': id}).val('').removeAttr('checked');
});
newElement.find('label').each(function() {
var forValue = $(this).attr('for');
if (forValue) {
forValue = forValue.replace('-' + (total-1) + '-', '-' + total + '-');
$(this).attr({'for': forValue});
}
});
total++;
$('#id_' + prefix + '-TOTAL_FORMS').val(total);
$(selector).after(newElement);
var conditionRow = $('.form-row:not(:last)');
conditionRow.find('.btn.add-form-row')
.removeClass('btn-success').addClass('btn-danger')
.removeClass('add-form-row').addClass('remove-form-row')
.html('-');
return false;
}
function deleteForm(prefix, btn) {
var total = parseInt($('#id_' + prefix + '-TOTAL_FORMS').val());
if (total > 1){
btn.closest('.form-row').remove();
var forms = $('.form-row');
$('#id_' + prefix + '-TOTAL_FORMS').val(forms.length);
for (var i=0, formCount=forms.length; i<formCount; i++) {
$(forms.get(i)).find(':input').each(function() {
updateElementIndex(this, prefix, i);
});
}
}
return false;
}
$(document).on('click', '.add-form-row', function(e){
e.preventDefault();
cloneMore('.form-row:last', 'form');
return false;
});
$(document).on('click', '.remove-form-row', function(e){
e.preventDefault();
deleteForm('form', $(this));
return false;
});
</script>
I don't remember where I got the js code, but I did not write it and can't take credit for it. Hopefully you have a better understanding than I do, but it works for me as is.
I have 2 models:
models.py:
class Item(models.Model):
name = models.CharField(max_length=100)
price = models.FloatField(max_length=20)
shelfLife = models.BooleanField()
def __str__(self):
return self.name
#property
def shL(self):
temp = "Doesnt' have shelf life"
if(self.shelfLife):
temp = "Does have sehlf life"
return temp
class Order(models.Model):
num = models.CharField(max_length=20)
date = models.DateField()
items = models.ManyToManyField(Item)
def __str__(self):
return self.num
according to this doc I can do:
views.py:
elif request.method == "POST":
list_items = request.POST.getlist('arr[]') # get list of items
order_num = request.POST.getlist('o_n') # get order num
order_date = request.POST.getlist('o_d') # get order date
order = Order(num=order_num[0], date=order_date[0])
order.save()
for i in range(len(list_items)):
item_name = str(list_items[i])
item = Item.objects.filter(name=item_name)
order.items.add(item)
To fetch each item that I need, I loop through the list_items list of strings and filter each object request by this string and then just add the item to the many-to-many field of the order model.
In addition, when I fetch
item = Item.objects.filter(name="Salad")
the returned QuerySet is not empty, however, if I pass a string variable to the name filter it returns an empty QuerySet.
I would appreciate any help!
Thanks
EDIT:
As #Willem Van Onsem sudjested I chaned my views.py to:
elif request.method == "POST":
list_items = request.POST.getlist('arr[]') # get list of items
order_num = request.POST.getlist('o_n') # get order num
order_date = request.POST.getlist('o_d') # get order date
order = Order(num=order_num[0], date=order_date[0])
order.save()
items = Item.objects.filter(name__in=list_items)
order.items.add(*items)
However, I still get a QuerySet items as an empty QuerySet.
I have checked the request variable list_tems and it is a list of strings (it's not empty).
I tested it by creating an array of Strings
arr=["Salad", "Chocolate"]
and paste it as a filter
items = Item.objects.filter(name__in=arr)
order.items.add(*items)
to the QuerySet and it works - QuerySet object items is not empty and it writes the right data to the DB.
index.html:
$(document).on('click','.btn-create-order',function(){
$.ajax({
method: "GET",
contentType: "application/json",
url: "{% url 'order-items api' %}",
success: function(data){
var index = 1;
data.forEach(element => {
$('#multyItemSelect').append("<option value='" + index + "' id='" +index+ "'> "+ element['fields'].name+"</option>")
index++;
});
},
error: function(jqXHR, textStatus, errorThrown){}
})
})
$('.order-new-submit').click(function(){
var order_num = $('#InputNumber').val()
var order_date = $('#InputDate').val()
var item_selected = $('#multyItemSelect').val() // number
var arr = [] // arr for the item names
var index = 0;
item_selected.forEach(e => {
arr[index] = $('#' + e).html()
index++
});
console.log(order_date)
// DEBUGIN
// arr.forEach(e => {
// console.log(e)
// });
// END DEBUGIN
$.ajax({
method: "POST",
url: "{% url 'order-items api' %}",
data: {'arr[]': arr,
'o_n' : order_num,
'o_d' : order_date},
success: function(data){
},
error: function(jqXHR, textStatus, errorThrown){}
})
})
Thanks to #Willem Van Onsem the issue has been found:
print(list_items)
prints values with space at the beginning:
[' Salad', ' Beef Stake ', ' Chocolate']
item in order.items.add(…) needs to be a model object, or the primary key of that model, but not a queryset. You can however make use of iterable unpacking to pass the items wrapped in the QuerySet as individual parameters:
for i in range(len(list_items)):
item_name = str(list_items[i])
items = Item.objects.filter(name=item_name)
order.items.add(*items) # ← with an asterisk (*)
You can boost efficiency by fetching all the Items in one query with:
items = Item.objects.filter(name__in=[str(x) for x in list_items])
order.items.add(*items)
I have a model in Django like:
from django.db import models
from django.contrib.auth.models import User
from datetime import datetime
# Create your models here.
class UserDetails(models.Model):
def getFileName(self, filename):
return 'profile_pics/'+str(self.user.id)+'/'+filename
user = models.ForeignKey(User, on_delete=models.SET_NULL, null=True)
profile_picture = models.ImageField(upload_to=getFileName, blank = True)
country = models.CharField(max_length = 50, default='UK')
gender = models.CharField(max_length=10, default='NA')
birthday = models.DateField(default=datetime.now())
phone = models.CharField(max_length=15)
verified = models.BooleanField(default=False)
def __str__(self):
try:
return self.user.username
except:
return 'Deleted User - '+str(self.phone)
Then, I created a REST API that accepts Multipart requests to create a new user as well as save the user_details for the user. I am making the multipart POST request from my app in Flutter with the Image for the profile picture. The image is coming in the body of the request as a String instead of coming in as a file, where I could have read it with request.FILES['profile_picture']. The body of the request that I am getting by doing a print(request.data) is as follows:
Data: <QueryDict: {
'username': ['jonsnow'],
'first_name': ['Jon'],
'last_name': ['Snow'],
'email': ['jonsnow#got.com'],
'password': ['jonsnow'],
'country': ['UK'],
'gender': ['Male'],
'birthday': ['2020-4-28'],
'phone': ['5198189849'],
'profile_picture': ['����\x00\x10JFIF\x00\x01\x01\x00\x00\x01\x00\x01\x00\x00��\x00�\x00\t\x06\x07\x08\x07\x06\t\x08\x07\x08\n\n\t\x0b\r\x16\x0f\r\x0c\x0c\r\x1b\x14\x15\x10\x16 \x1d"" \x1d\x1f\x1f$(4,$&1\'\x1f\x1f-=-157:::#+?D?8C49:7\x01\n\n\n\r\x0c\r\x1a\x0f\x0f\x1a7%\x1f%77777777777777777777777777777777777777777777777777��\x00\x11\x08\x019\x01�\x03\x01"\x00\x02\x11\x01\x03\x11\x01��\x00\x1c\x00\x00\x02\x03\x01\x01\x01\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x03\x04\x02\x05\x06\x01\x07\x00\x08��\x00Q\x10\x00\x02\x01\x03\x02\x03\x05\x04\x06\x06\x07\x07\x03\x03\x01\t\x01\x02\x03\x00\x04\x11\x12!\x051A\x06\x13"Qa2q��\x14B����\x07#3Rr�\x154Sbs��\x16$C����5��%c�DtEFd����\x17��\x00\x1a\x01\x01\x01\x01\x01\x01\x01\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x02\x03\x04\x05\x06��\x00(\x11\x01\x01\x00\x02\x01\x04\x02\x02\x02\x02\x03\x01\x00\x00\x00\x00\x00\x01\x02\x11\x03\x12!1A\x04\x13\x14Q\x05"aqBR�\x15��\x00\x0c\x03\x01\x00\x02\x11\x03\x11\x00?\x00�Cl�0ɵX��¸�iB�k; ...\uebe8?��']
}>
And print(request.FILES) is coming as: Files: <MultiValueDict: {}>
So, I made the Multipart REST API to handle this request like:
class SignUp(APIView):
parser_classes = [MultiPartParser,]
authentication_classes = [CsrfExemptSessionAuthentication]
permission_classes = [AllowAny]
def post(self, request, format=None):
data = request.data
print('\n\nFiles: '+str(request.FILES)+'\n\n');
print('\n\nData: '+str(data)+'\n\n');
print('\n\nData: '+str(request.META)+'\n\n');
## Creating a basic user
user = User.objects.create_user(username=data['username'], first_name = data['first_name'], last_name = data['last_name'], email = data['email'], password = data['password'])
user.save()
user_details = UserDetails()
user_details.user = user
rec_img_str = data['profile_picture']
rec_img_bytes = rec_img_str.encode('utf-8')
rec_img_writer = BytesIO(rec_img_bytes)
uploaded_img = InMemoryUploadedFile(rec_img_writer, None, 'sample.jpg', 'image/jpeg', None, 'utf-8')
user_details.profile_picture = uploaded_img
user_details.country = data['country']
user_details.gender = data['gender']
user_details.birthday = datetime.strptime(data['birthday'], '%Y-%m-%d').date()
user_details.phone = data['phone']
user_details.verified = False
user_details.save()
return Response({'Message': 'Profile Created Successfully'})
Here, I read the JPG image that comes as a string in the field profile_picture, converted it to Byte form, put it into BytesIO(), and then stored it in user_details.profile_picture as an InMemoryUploadedFile. It saves as sample.jpg in my MEDIA directory, but when I try to open it, it comes as a blank image.
So, how do I save the JPEG image that is coming in as a string to a ImageField in Django?
Here's my Flutter code, if it is needed for reference:
void submit() async {
MultipartRequest request = MultipartRequest("POST",
Uri.parse("http://10.0.2.2:8000/services/authentication/signup/"));
request.fields['username'] = this.username.text;
request.fields['first_name'] = this.first_name.text;
request.fields['last_name'] = this.last_name.text;
request.fields['email'] = this.email.text;
request.fields['password'] = this.password.text;
request.fields['country'] = "UK";
request.fields['gender'] = this.gender;
String birthdayStr = "${birthday.year}-${birthday.month}-${birthday.day}";
request.fields['birthday'] = birthdayStr;
request.fields['phone'] = this.phone_no.text;
if (this.profilePicture != null) {
print('Profile picture available');
print(this.profilePicture.path);
request.files.add(
await MultipartFile.fromBytes(
'profile_picture',
await this.profilePicture.readAsBytes(), //this.profilePicture is a File
contentType: MediaType('image', 'jpeg'),
),
);
}
StreamedResponse resp = await request.send();
if (resp.statusCode < 200 || resp.statusCode >= 400) {
print('There was an error in making the SignUp Request');
print('Status code: ${resp.statusCode}');
} else {
Navigator.pop(context);
}
}
I'm converting a page from using manually rendered post/get functions to one using class-based views. I am attempting to move towards using all of Django's built-in functionality. But I'm encountering a confusing error where the ModelFormSet object is not the right type when the form is posted.
I have this form:
class AssignmentDatesForm(forms.ModelForm):
class Meta:
model = AssignmentDates
fields = [
'assignment_name',
'start_date',
'due_date',
'end_date',
]
widgets = { 'start_date' : forms.DateInput(format = '%m/%d/%Y', attrs ={ 'class' : 'datepicker'}),
'due_date' : forms.DateInput(format = '%m/%d/%Y', attrs ={ 'class' : 'datepicker' }),
'end_date' : forms.DateInput(format = '%m/%d/%Y', attrs ={ 'class' : 'datepicker' }),}
def clean(self):
logging.warning("Clean function")
logging.warning("start_date: " + str(start_date))
logging.warning("due_date: " + str(due_date))
logging.warning("end_date: " + str(end_date))
# Actual validation logic here
And create the ModelFormSet using modelformset_factory:
AssignmentDatesFormSet = forms.modelformset_factory(
model = AssignmentDates,
form = AssignmentDatesForm,
extra = 0,
)
Here is the view, shortened for brevity:
class EditDueDates(CurrentUserMixin, ModelFormSetView):
model = AssignmentDates
page_title = 'Edit Due Dates'
success_message = "Dates updated successfully!"
add_button_title = "Add Button Title"
form = AssignmentDatesForm
formset = AssignmentDatesFormSet
template_name = "edit_due_dates.html"
sidebar_group = ['scaffold', 'edit_due_dates']
columns = [
('Assignment Name', 'assignment_name'),
('Start Date', 'start_date'),
('Due Date', 'due_date'),
('End Date', 'end_date'),
]
fields = [
'assignment_name',
'start_date',
'due_date',
'end_date',
]
show_context_menu = False
def get_context_data(self, **kwargs):
context = super(EditDueDates, self).get_context_data(**kwargs)
# Date retrieval/ DB storage logic here
form = AssignmentDatesFormSet(queryset = AssignmentDates.objects.filter(created_by = creds.get_OUNetID()))
logging.warning("get_context_data form type: " + str(type(form)))
context['form'] = form
return context
def formset_valid(self, formset):
logging.warning("formset_valid form type: " + str(type(formset)))
cleaned_data = formset.clean()
if formset.is_valid():
formset.save()
return super(EditDueDates, self).formset_valid(formset)
The ModelFormSet is displayed fine in the template, and the logging message I have above prints out the type of the form as:
<class 'scaffold.forms.AssignmentDatesFormSet'>
But my clean function is never executed. When it executes the formset_valid function I have in the view and print out the formset type, I get this:
<class 'django.forms.formsets.AssignmentDatesFormFormSet'>
So it never executes my clean function because the type isn't right. Executing formset.clean() again just executes the clean function of this weird type.
I haven't a clue why it's a different type when it's POSTed from the template. If anyone has any ideas please let me know! Thank you!
-Will