I've been experiencing a little problem when I try to update some record from database.
Strange thing is that form.errors are empty if form is invalid (I can't understand why).
Here are the
form
class PetitionUpdateForm(forms.ModelForm):
owner = forms.ModelChoiceField(
label=_('Petition creator'),
queryset=User.objects.all(),
widget=forms.HiddenInput()
)
class Meta:
fields = ('title', 'petition_text', 'description',
'category', 'num_signs', 'date_to', 'owner',)
model = Petition
model
class Petition(models.Model):
PETITION_STATUSES = (
('N', _('New petition')), # New one
('M', _('Moderation')), # On moderation
('R', _('Rejected')), # Failed petition
('S', _('Success')) # Succeeded petition
)
title = models.CharField(max_length=512)
slug = models.SlugField(max_length=512, editable=False, blank=True)
description = models.TextField()
petition_text = models.TextField(blank=True, null=True)
petition_picture = models.ImageField(upload_to=get_upload_path, blank=True)
petitioning = models.ManyToManyField(PetitionTarget, editable=False)
signs = models.ManyToManyField(User, editable=False, related_name='petition_signs')
num_signs = models.IntegerField(max_length=11, default=100, blank=True)
category = models.ForeignKey(Category, blank=True, null=True, related_name='petition_category')
date_to = models.DateTimeField(blank=True, null=True)
videos = models.ManyToManyField(Video, editable=False)
photos = models.ManyToManyField(Photo, editable=False)
audios = models.ManyToManyField(Audio, editable=False)
documents = models.ManyToManyField(Document, editable=False)
created = models.DateTimeField(auto_now_add=True, editable=False)
changed = models.DateTimeField(auto_now=True, editable=False)
status = models.CharField(max_length=1, choices=PETITION_STATUSES, default='M', blank=True)
owner = models.ForeignKey(User, related_name='petition_owner')
def __unicode__(self):
return u'{0}: {1}'.format(_('Petition'), self.title)
update view
#login_required
#render_to('petition/edit-petition.html')
def update_petition(request, slug):
p = get_object_or_404(Petition, slug=slug)
form = PetitionUpdateForm(request.POST or None, instance=p)
import pdb
pdb.set_trace()
if form.is_valid():
form.save()
messages.success(request, _('Petition saved'))
else:
print form.errors # errors are empty
messages.success(request, _('Some error happened'))
return {'form': form, 'petition': p}
What's wrong with my code?
I've already tried to set null attributes for the most of model fields, switched from class based view to a standard view and yet I'm unable to update my record.
Sultan,
Thanks
If there is no POST data, then request.POST or None is None, so the form is unbound.
Unbound forms are always invalid, but do not have any errors.
In your case, you may want to change the else: clause to elif request.POST:
See the docs on bound and unbound forms for more details.
Related
#HELP in python (DJANGO 4)
I send this message here because I have not been able to find an answer elsewhere.
Currently I’m on a project where I have to create a booking form.
The goal is that when the user submit the Reservation form, I send the data in BDD, and I retrieve the user's id by a relation (ForeignKey).
And my difficulty is in this point precisely, when I send my form in BDD I recover the information, except the id of the user…
I did a Foreignkey relationship between my 2 tables and I see the relationship in BDD but I don’t receive the id of the User table, but null in the place….
Does anyone of you know how to help me please?
Thank you all.
--My model.py --
class Reservation(models.Model):
fullName = models.CharField('Nom Complet', max_length=250, null=True)
adress = models.CharField('Adresse', max_length=100, null=True)
zip_code = models.IntegerField('Code Postal', null=True)
city = models.CharField('Vile', max_length=100, null=True)
email = models.EmailField('Email', max_length=250, null=True)
phone = models.CharField('Telephone', max_length=20, null=False)
date = models.CharField('Date', max_length=20, null=True, blank=True)
hour = models.CharField('Heure', max_length=20, null=True, blank=True)
message = models.TextField('Message', null=True)
accepted = models.BooleanField('Valide', null=True)
created_at = models.DateTimeField('Date Creation', auto_now_add=True, null=True)
modified_at = models.DateTimeField('Date Mise Jour', auto_now=True, null=True)
user = models.ForeignKey(User, null=True, on_delete=models.SET_NULL)
def __str__(self):
return self.fullName
-- my views.py --
#login_required()
def user_new_reservation(request, pk=None):
user = User.objects.get(id=pk)
if request.method == 'POST':
form = ReservationForm(request.POST)
if form.is_valid():
form.save()
messages.success(request, 'Votre réservation a bien été envoyé!')
return redirect('reservation:user_reservation', pk=request.user.id)
else:
form = ReservationForm()
context = {'form': form}
return render(request, 'reservation/new_reservation.html', context)
-- My Form.py --
class ReservationForm(forms.ModelForm):
class Meta:
model = Reservation
fields = [
'fullName',
'adress',
'zip_code',
'city',
'email',
'phone',
'date',
'hour',
'message',
]
Thank you all.
Inside your form.save use:
user = form.save(commit=False)
user.user = request.user
user.save()
user=your field name in your model
request user= in django when you use authentication you can access some of information based on request like user and other
Good luck
here is my model.py
class Product(models.Model):
user = models.ForeignKey(User, null=True, blank=True,on_delete=models.CASCADE)
coinid = models.CharField(max_length=255, unique = True, null=True)
digit = models.CharField(max_length=18, unique = True, null=True)
ctp = models.FloatField(max_length=100, null=True)
transection_id = models.IntegerField(null=True, default=0)
slug = models.SlugField(max_length=250, null=True, blank=True)
date_created = models.DateField(auto_now_add=True, null=True)
when the user fills the form which includes = coinid and ctp.
I want Django to automatically fill Digit(unique) and user(logged in) fields for me when updated to the products table.
here is my form.py
class CreateProduct(ModelForm):
class Meta:
model = Product
fields = ['user','coinid', 'ctp']
exclude = ['user']
views.py
def createProduct(request):
user_id = request.user.customer
form = CreateProduct(instance=user_id)
if request.method == 'POST':
form = CreateProduct(request.POST)
if form.is_valid():
form.save()
return redirect('/products/')
context = {'form': form}
return render(request, 'accounts/newcoin.html', context)
Also, I want to validate the product's ctp value whenever a user types in the unique digit to another form.
you can override the save method on the Product model to achieve what you want
example: models.py
import uuid
class Product(models.Model):
user = models.ForeignKey(User, null=True,
blank=True,on_delete=models.CASCADE)
coinid = models.CharField(max_length=255, unique = True, null=True)
digit = models.CharField(max_length=18, unique = True, null=True)
ctp = models.FloatField(max_length=100, null=True)
transection_id = models.IntegerField(null=True, default=0)
slug = models.SlugField(max_length=250, null=True, blank=True)
date_created = models.DateField(auto_now_add=True, null=True)
def save(self, *awags, **kwargs):
# if coinid and ctp is not none
# save a uuid in the digit field
if self.coinid and self.ctp:
self.digit = str(uuid.uuid4())
# Your code to change the user model here
# exmaple to change user name
user = User.objects.get(id = self.user.id)
user.username = "Stackoverflow user"
user.save()
super().save(*awags, **kwargs)
You can check the Django docs for reference to override Save method
For creating unique IDs you can use the python uuid module
import uuid
unique_id = str(uuid.uuid4())
You can also use uuid.uuid1() however the docs recommends uuid4 for a random unique string
You can check the docs for uuid here
This is my views.py file and Im getting this message
DETAIL: Key (member_id, match_id)=(4, 20) already exists.
However is see that Valid is printing so its obvious the is_valid() method doesnt catch this duplicate key.
def update_batter_form(request, match_id, batting_id):
"""Edit existing batter form view."""
obj = Batting.objects.get(pk=batting_id)
form = BattingForm(instance=obj)
batting_list_bn = Batting.objects.order_by('batter_number') \
.filter(match_id=match_id)
match = Match.objects.get(pk=match_id)
if request.method == 'POST':
print("Printing POST")
form = BattingForm(request.POST, instance=obj)
print(obj)
if form.is_valid():
print("Valid")
form.save()
return redirect('/club/match/'+match_id+'/batter/'+batting_id)
else:
print(form.errors)
return redirect('/club/match/' + match_id + '/batter/' + batting_id)
context = {
'form': form,
'batting_list_bn': batting_list_bn,
'match': match
}
return render(request, 'club/batter_update.html', context)
EDIT Batting model and form
class Batting(models.Model):
"""Batting performances within a match."""
member = models.ForeignKey(Member, on_delete=models.CASCADE, default='')
batter_number = models.IntegerField(
blank=False, default=1, validators=[MaxValueValidator(11), MinValueValidator(1)]
)
fours = models.IntegerField(
blank=True, null=True, default=0, validators=[MaxValueValidator(300), MinValueValidator(0)]
)
sixes = models.IntegerField(
blank=True, null=True, default=0, validators=[MaxValueValidator(300), MinValueValidator(0)]
)
runs = models.IntegerField(
blank=True, null=True, default=0, validators=[MaxValueValidator(1000), MinValueValidator(0)]
)
mode_of_dismissal = models.ForeignKey(Wicket, on_delete=models.CASCADE, default='')
out_by = models.ForeignKey(
OppositionNames, on_delete=models.CASCADE, default='', blank=True, null=True
)
match = models.ForeignKey(Match, on_delete=models.CASCADE, default='')
class Meta:
"""Meta class."""
unique_together = (("batter_number", "match",), ("member", "match",),)
def __str__(self):
return str('{0} {1} scored {2} runs'
.format(self.member, self.match.date, self.runs)
)
class BattingForm(forms.ModelForm):
class Meta:
model = Batting
exclude = ('match',)
How is it I catch this issue?
In your form you have set exclude as follows: exclude = ('match',). When we exclude a field from the form, the form also excludes it from the validation it performs, which is only logical in the case that the form may be used to create this model's instances.
Since you need the field match to be part of the validation the best method is to simply make match a disabled and hidden field on the form. This will cause the field to be rendered with the disabled and hidden attributes. Also even if the user tampers with the field it will be ignored in favor of the initial value of the field:
class BattingForm(forms.ModelForm):
match = forms.ModelChoiceField(
queryset=Match.objects.all(),
widget=forms.HiddenInput(),
disabled=True
)
class Meta:
model = Batting
fields = '__all__'
I'm trying to build courses and add lessons to a course later and the problem I encounter is that every user can choose to add courses to another person created courses.
Like if you create some courses, another user will see as an option to add his lesson to it
views.py
def creatingLessonsForm(request):
form = CreatingLessonsForm(request.POST or None)
if form.is_valid():
post = form.save(commit=False)
post.CreatedBy = request.user
post.save()
form = CreatingLessonsForm()
context = {'form': form}
return render(request, 'courses/creatingLessonsForm.html', context)
models.py
class CreatingCourses(models.Model):
NameOfTheCourses = models.CharField("Name of the courses", max_length=60, blank=False)
Category = models.ForeignKey(Subject, on_delete=models.CASCADE)
CreatedBy = models.ForeignKey(User, on_delete=models.CASCADE, null=True)
Document = models.ForeignKey(Document, on_delete=models.SET_NULL, verbose_name= "Select document for courses introduction", blank=True , null=True)
IncludeTest = models.ForeignKey(GenaratedTest, on_delete=models.SET_NULL, verbose_name= "Include test for courses", blank=True , null=True)
AdditionalInfo = models.TextField("Additional info for courses introduction", max_length=300, blank=False)
Note = models.TextField("Notes", max_length=180, blank=True)
Show_the_courses = models.BooleanField(verbose_name= "Show the courses for everyone?",default=True)
def __str__(self):
return str(self.NameOfTheCourses) if self.NameOfTheCourses else ''
class CreatingLessons(models.Model):
Courses = models.ForeignKey(CreatingCourses, on_delete=models.SET_NULL, null=True)
NameOfTheLesson = models.CharField(max_length=60, verbose_name= "Name of the lesson", blank=False)
Document = models.ForeignKey(Document, on_delete=models.SET_NULL, verbose_name= "Document for lesson", blank=True , null=True)
CreatedBy = models.ForeignKey(User, on_delete=models.CASCADE, null=True)
Lesson = models.TextField(max_length=250, verbose_name= "Lesson", blank=False)
Note = models.TextField("Notes", max_length=100, blank=True)
Show_the_lesson = models.BooleanField(verbose_name= "Show the lesson inside courses?",default=True)
forms.py
class CreatingCoursesForm(forms.ModelForm):
class Meta:
model = CreatingCourses
fields = ['NameOfTheCourses', 'Category', 'IncludeTest', 'Document' , 'AdditionalInfo', 'Note', 'Show_the_courses' ]
class CreatingLessonsForm(forms.ModelForm):
class Meta:
model = CreatingLessons
fields = ['Courses', 'NameOfTheLesson', 'Document', 'Lesson', 'Note', 'Show_the_lesson']
Image of webpage:
You need to pass the user when you initialize the form and then filter the queryset for the available courses that can be selected
class CreatingLessonsForm(forms.ModelForm):
def __init__(self, data=None, user=None, **kwargs):
super().__init__(data, **kwargs)
self.fields['Courses'].queryset = CreatingCourses.objects.filter(CreatedBy=user)
And then when you initialize the form pass the user
# When rendering the initial form
form = CreatingLessonsForm(user=request.user)
# When passing POST data to the form
form = CreatingLessonsForm(request.POST, user=request.user)
One option would be to modify your to filter the courses by user.
class CreatingLessonsForm(forms.ModelForm):
...
def __init__(self, *args, **kwargs):
request_user = kwargs.pop('request_user')
super().__init__(*args, **kwargs)
self.fields['Courses'].queryset = self.fields['Courses'].queryset.filter(
CreatedBy=request_user)
For that to work you will need to pass in the user of the request to the form, maybe like this:
def creatingLessonsForm(request):
data = request.POST.copy()
data['request_user'] = request.user
form = CreatingLessonsForm(data)
...
I have a Django 'add business' view which adds a new business with an inline 'business_contact' form.
The form works fine, but I'm wondering how to write up the unit test - specifically, the 'postdata' to send to self.client.post(settings.BUSINESS_ADD_URL, postdata)
I've inspected the fields in my browser and tried adding post data with corresponding names, but I still get a 'ManagementForm data is missing or has been tampered with' error when run.
Anyone know of any resources for figuring out how to post inline data?
Relevant models, views & forms below if it helps. Lotsa thanks.
MODEL:
class Contact(models.Model):
""" Contact details for the representatives of each business """
first_name = models.CharField(max_length=200)
surname = models.CharField(max_length=200)
business = models.ForeignKey('Business')
slug = models.SlugField(max_length=150, unique=True, help_text=settings.SLUG_HELPER_TEXT)
created = models.DateTimeField(auto_now_add=True)
updated = models.DateTimeField(auto_now=True)
phone = models.CharField(max_length=100, null=True, blank=True)
mobile_phone = models.CharField(max_length=100, null=True, blank=True)
email = models.EmailField(null=True)
deleted = models.BooleanField(default=False)
class Meta:
db_table='business_contact'
def __unicode__(self):
return '%s %s' % (self.first_name, self.surname)
#models.permalink
def get_absolute_url(self):
return('business_contact', (), {'contact_slug': self.slug })
class Business(models.Model):
""" The business clients who you are selling products/services to """
business = models.CharField(max_length=255, unique=True)
slug = models.SlugField(max_length=100, unique=True, help_text=settings.SLUG_HELPER_TEXT)
description = models.TextField(null=True, blank=True)
primary_contact = models.ForeignKey('Contact', null=True, blank=True, related_name='primary_contact')
business_type = models.ForeignKey('BusinessType')
deleted = models.BooleanField(default=False)
created = models.DateTimeField(auto_now_add=True)
updated = models.DateTimeField(auto_now=True)
address_1 = models.CharField(max_length=255, null=True, blank=True)
address_2 = models.CharField(max_length=255, null=True, blank=True)
suburb = models.CharField(max_length=255, null=True, blank=True)
city = models.CharField(max_length=255, null=True, blank=True)
state = models.CharField(max_length=255, null=True, blank=True)
country = models.CharField(max_length=255, null=True, blank=True)
phone = models.CharField(max_length=40, null=True, blank=True)
website = models.URLField(null=True, blank=True)
class Meta:
db_table = 'business'
def __unicode__(self):
return self.business
def get_absolute_url(self):
return '%s%s/' % (settings.BUSINESS_URL, self.slug)
VIEWS:
def business_add(request):
template_name = 'business/business_add.html'
if request.method == 'POST':
form = AddBusinessForm(request.POST)
if form.is_valid():
business = form.save(commit=False)
contact_formset = AddBusinessFormSet(request.POST, instance=business)
if contact_formset.is_valid():
business.save()
contact_formset.save()
contact = Contact.objects.get(id=business.id)
business.primary_contact = contact
business.save()
#return HttpResponse(help(contact))
#business.primary = contact.id
return HttpResponseRedirect(settings.BUSINESS_URL)
else:
contact_formset = AddBusinessFormSet(request.POST)
else:
form = AddBusinessForm()
contact_formset = AddBusinessFormSet(instance=Business())
return render_to_response(
template_name,
{
'form': form,
'contact_formset': contact_formset,
},
context_instance=RequestContext(request)
)
FORMS:
class AddBusinessForm(ModelForm):
class Meta:
model = Business
exclude = ['deleted','primary_contact',]
class ContactForm(ModelForm):
class Meta:
model = Contact
exclude = ['deleted',]
AddBusinessFormSet = inlineformset_factory(Business,
Contact,
can_delete=False,
extra=1,
form=AddBusinessForm,
)
The problem is you have not included the management form in your data. You need to include form-TOTAL_FORMS (total number of forms in the formset, default is 2), form-INITIAL_FORMS (the initial number of forms in the formset, default is 0) and form-MAX_NUM_FORMS (the maximum number of forms in the formset, default is '').
See the Formset documentation for more information on the management form.