Django:What is wrong with my code? - python

These are my models:
class war(models.Model):
title = models.CharField(max_length=20)
class option(models.Model):
warval =models.ForeignKey(war)
value = models.CharField(max_length=10)
class warform(ModelForm):
class Meta:
model = war
class option_form(ModelForm):
class Meta:
model = option
exclude = ('warval')
And this is the view which handles creation of option:
def warhandler(request,war_id):
f=modelformset_factory(option,form=option_form)
wobj=get_object_or_404(war,pk=war_id)
if request.method == 'POST':
formset = f(request.POST,queryset=option.objects.filter(warval=wobj))
if formset.is_valid():
formset.save()
return HttpResponse("Saved!check your model")
else:
return render_to_response("formset.html",RequestContext(request,{"set":formset}))
else:
formset = f(queryset=option.objects.filter(warval=wobj))
print(formset)
return render_to_response("formset.html",RequestContext(request,{"set":formset,"war":wobj}))
So when I submit the form to this view,I get the following error:
Exception Type: IntegrityError
Exception Value: hit_option.warval_id may not be NULL
I know what this error is and why it is coming but how can I remove this error?

As you realize, this is because you're not setting the foreign key value anywhere. You probably want to use inlineformset_factory which will take care of setting the FK to the parent war object for you.

Make warval a non-required field with
class option(models.Model):
warval =models.ForeignKey(war, null=True)
value = models.CharField(max_length=10)
or define formset.warval before saving, make a default value...
edit:
read here and here for using subset of fields on a form and saving.

Related

How to use a different unique identifier of Django ForeignKey field in ModelForm

I have the following Models:
class Book(models.Model):
name = models.CharField(max_length=128)
isbn = models.CharField(max_length=13, unique=True)
available = models.BooleanField(default=True)
class Borrow(models.Model):
date = models.DateTimeField(auto_now_add=True)
book = models.ForeignKey(Book)
and the following ModelForm:
class CreateBorrowForm(forms.ModelForm):
class Meta:
model = Borrow
fields = ['book']
def clean_book(self):
book = self.cleaned_data['book']
try:
return Book.objects.get(id=book, available=True)
except Book.DoesNotExist:
raise ValidationError('Book does not exist or it is unavailable')
I would like to have a form that expects the isbn field of the Book model, instead of id. As the isbn field is unique, it does make sense. In the clean_book method I would need to do a little change to have the following line:
return Book.objects.get(isbn=book, available=True)
The problem is that I cannot find an approach to force the form to use a different unique identifier. In my specific case, this is required to avoid brute force enumerating over numerical IDs.
You'd need to use a custom field for that, and override the save() method instead of the clean__field():
class CreateBorrowForm(forms.ModelForm):
book_isbn = forms.CharField()
class Meta:
model = Borrow
fields = ['book_isbn']
def save(self, commit=True):
instance = super().save(commit=False)
book_isbn = self.cleaned_data['book_isbn']
try:
book = Book.objects.get(isbn=book_isbn, available=True)
instance.book = book
except Book.DoesNotExist:
raise ValidationError('Book does not exist or it is unavailable')
if commit:
instance.save()
return instance

How to change a field in parent class while creating chiled class fields in forms.py and views.py?

I'm was creating ModelForm I try to make change the parent class while saving child class fields to the database, in the views.py I made but it didn't save to the database.
here is my model.py
class Table(models.Model):
restaurant = models.ForeignKey(Restaurant, on_delete=models.CASCADE)
book = models.BooleanField(default=False)
class People(models.Model):
user = models.OneToOneField(User, on_delete=models.CASCADE, null=True)
taple = models.OneToOneField(Table, on_delete=models.CASCADE, null=True, blank=True)
#receiver(post_save, sender=User)
def update_people_profile(sender, instance, created, **kwargs):
try:
instance.people.save()
except ObjectDoesNotExist:
People.objects.create(user=instance)
Class People is the child class and Table is the parent class so I'm using People class for making forms. here is my forms.py
class Booking(forms.ModelForm):
class Meta:
model = People
fields = [
'taple',
]
So I want to make True book field in Table class and save it to the database when saving Booking form. here is my views.py
def booking(request):
if request.method == 'POST':
try:
people_instance = People.objects.get(user=request.user)
except Table.DoesNotExist:
people_instance = People(user=request.user)
form = Booking(request.POST, instance=people_instance)
if form.is_valid():
user = form.save(commit=False)
user.taple.booking = True
user.refresh_from_db()
user.user = request.user
user.taple = form.cleaned_data.get('taple')
user.save()
print(user.taple.booking, user.taple.id)
return redirect('booked')
else:
form = Booking()
return render(request, 'main/booking.html', {'form': form})
Any Idea?
What I understand from the snippets is that you want to be able to record if a table is booked (book Boolean Field in your Table model and if so by whom, which is the object of your People model.
If my understanding is correct, then I don't think you really need a join table (People model). Instead, I would change your model as follow:
class Table(models.Model):
restaurant = models.ForeignKey(Restaurant, on_delete=models.CASCADE)
booked_by = models.OneToOneField(User, null=True, on_delete=models.SET_NULL, related_name='table_booked')
#property
def is_booked(self):
# This returns True if booked_by is set, False otherwise
return self.booked_by_id is not None
This way you don't need the People model. The property decorator will allow you to use is_booked as a calculated field.
Also, note the related name which will be used in the form:
class BookingForm(forms.ModelForm):
table_booked = forms.ModelChoiceField(queryset=Table.objects.filter(booked_by__isnull=True))
class Meta:
model = User
fields = ['table_booked',]
In the form, you will see that we define a custom queryset for table_booked. THe aim is to filter for free tables only.
Then you can hopefully simplify as well your view as follow:
Update:
As table_booked is a reverse foreign key, we actually need to save the table object which contains the relation. Here is the modified view:
#login_required
def booking(request):
form = BookingForm(request.POST or None, instance=request.user)
if form.is_valid():
user = form.save(commit=False)
tbl = form.cleaned_data['table_booked']
tbl.booked_by = request.user
tbl.save()
user.save()
print(request.user.table_booked.id, request.user.table_booked.is_booked)
return redirect('/')
return render(request, 'booking/booking.html', {'form': form})
Note: I haven't tested the code so there could be some typos but that should help you getting started.

Setting model data after validation

I'm trying to set data in a FormModel after validation. Example of a use case here is if I want to assign a unique number to a form data set if and only if it passes validation. There's some other information I'm trying to tack on too that isn't available prior to validation. I've tried setting in both the view class and in the clean() method of the ModelForm but can't seem to get it right. Each time I get an exception saying that "tag_id" cannot be null. Obviously I'm not setting it in a way that let's form.save() access the data.
Note that in the example below I'm trying to set tag_id in two places to illustrate what I've tried; obviously only one place would be needed if it worked.
What is the proper way to do this?
Model and FormModel:
class Video(models.Model):
tag_id = models.BigIntegerField()
name = models.CharField(max_length=200)
uploaded = models.DateTimeField()
size = models.BigIntegerField()
video_file = models.FileField(upload_to='documents/%Y/%m/%d')
class Meta:
db_table = 'videos'
class VideoForm(forms.ModelForm):
class Meta:
model = Video
fields = ['name', 'video_file']
def clean(self):
self.data['tag_id'] = 10
return self.cleaned_data
The view class:
class Upload(FormView):
template_name = "account/templates/upload.html"
form_class = VideoForm
success_url = reverse_lazy('account:home')
def form_valid(self, form):
form.cleaned_data['tag_id'] = 10
form.save()
return super().form_valid(form)
Exception on form.save():
IntegrityError at /account/upload/
(1048, "Column 'tag_id' cannot be null")
You should set the attribute of the model instance:
form.instance.tag_id = 10
form.save()

State Control/Workflow in Django

I'm having an object with a few fields such as order line, reference no, state
the state is a selection of draft and confirmed
what I want is when the record's state is confirmed, the other field can't be modified/ readonly
what's the best / common way to do this in django ?
thanks
I tired it with 3 example fields.
I create a model with 3 fields:
class New(models.Model):
title = models.CharField(max_length=100,unique=True)
body = models.TextField()
editable = models.BooleanField(default=True)
def __unicode__(self):
return self.title
My forms.py code is:
class MyNewForm(forms.ModelForm):
class Meta:
model = New
def clean(self):
cleaned_data = super(MyNewForm,self).clean()
title = cleaned_data.get('title')
body = cleaned_data.get('body')
editable = cleaned_data.get('editable')
if self.instance.pk:
try:
row = New.objects.get(id=self.instance.pk)
except New.DoesNotExist:
raise forms.ValidationError('Record not found')
if not row.editable and not editable:
raise forms.ValidationError('This record is not editable')
return cleaned_data
And my admin.py code is:
from news.models import New
from news.forms import MyNewForm
class MyNew(admin.ModelAdmin):
form = MyNewForm
admin.site.register(New,MyNew)
Hope it works fine for you.
A true/false field (i.e. the BooleanField) can do the job. Read the docs here: https://docs.djangoproject.com/en/dev/ref/models/fields/#booleanfield

This field is required. Error with ImageField and FileField on Django

I am new on Django, I am using Django 1.6.1 and in one of my form I get the next error
This field is required.
I don't understand why I get this error, my form is very basic, so my Model, the statement who launch this error is form.is_valid(), but I don't know why.
Some help would be apreciate.
my views is:
if request.method == 'POST':
form = campoImagenForm(request.POST, request.FILES)
if form.is_valid():
articulo = form.save(commit=False)
articulo.item = item
articulo.atributo = atributo
articulo.save()
return HttpResponseRedirect('/workproject/' + str(project.id))
my Form is:
class campoImagenForm(forms.ModelForm):
class Meta:
model = campoImagen
fields = ('imagen',)
my Model is:
class campoImagen(models.Model):
item = models.ForeignKey(ItemBase)
atributo = models.ForeignKey(TipoItem)
imagen = models.ImageField(verbose_name='Imagen', upload_to='archivos')
version = models.IntegerField()
I don't have a clue of why I get such an error.
At first, in your model make your fields empty and nullable:
class campoImagen(models.Model):
# [...]
imagen = models.ImageField(verbose_name='Imagen', upload_to='archivos', null=True, blank=True)
Then in your model form alter the required parameter of your field:
class campoImagenForm(forms.ModelForm):
class Meta:
model = campoImagen
fields = ('imagen',)
def __init__(self, *args, **kwargs):
super(campoImagenForm, self).__init__(*args, **kwargs)
self.fields['imagen'].required = False
The model part is, however, obligatory. Otherwise you might be getting database inconsistency errors.
Keep in mind that blank and null are different things. They do, however, work well together and should give you what you want.
In forms.py
class campoImagenForm(forms.ModelForm):
imagen = forms.ImageField(verbose_name='Imagen', upload_to='archivos', required = False)
class Meta:
model = campoImagen
fields = ('imagen',)

Categories

Resources