I'm a beginner at django and I'm trying to get my calendar to display a checkbox itself rather than a True/False value. I'm able to get the data to save from the form however
models.py
class Event(models.Model):
user = models.ForeignKey(User, on_delete=models.CASCADE)
title = models.CharField(max_length=200)
description = models.TextField(max_length=350)
start_time = models.DateTimeField()
#end_time = models.DateTimeField()
event_checked = models.BooleanField()
#property
def get_html_url(self):
url = reverse('cal:event_edit', args=(self.id, ))
return f' <label> {self.title} {self.event_checked}<label>'
def __str__(self):
return '{} - {} by {}'.format(self.title, self.description, self.user)
forms.py
class EventForm(forms.ModelForm):
event_checked = forms.BooleanField()
class Meta:
model = Event
# datetime-local is a HTML5 input type, format to make date time show on fields
widgets = {
'start_time': DateInput(attrs={'type': 'datetime-local'}, format='%Y-%m-%dT%H:%M'),
}
fields = ('title', 'description', 'start_time')
def __init__(self, *args, **kwargs):
super(EventForm, self).__init__(*args, **kwargs)
# input_formats parses HTML5 datetime-local input to datetime field
self.fields['start_time'].input_formats = ('%Y-%m-%dT%H:%M',)
views.py
def event(request, event_id=None):
instance = Event()
if event_id:
instance = get_object_or_404(Event, pk=event_id)
else:
instance = Event()
form = EventForm(request.POST or None, instance=instance)
if request.POST and form.is_valid():
event = Event.objects.create(**form.cleaned_data, user=request.user)
print(event.title)
return HttpResponseRedirect(reverse('cal:calendar'))
return render(request, 'cal/event.html', {'form': form})
How my calendar looks with some events
I don't know if that was your goal:
class EventForm(forms.ModelForm):
event_checked = forms.BooleanField()
class Meta:
model = Event
# datetime-local is a HTML5 input type, format to make date time show on fields
widgets = {
'event_checked' forms.CheckboxInput(), # <-- added this
'start_time': DateInput(attrs={'type': 'datetime-local'}, format='%Y-%m-%dT%H:%M'),
}
fields = ('title', 'description', 'start_time')
def __init__(self, *args, **kwargs):
super(EventForm, self).__init__(*args, **kwargs)
# input_formats parses HTML5 datetime-local input to datetime field
self.fields['start_time'].input_formats = ('%Y-%m-%dT%H:%M',)
Related
I'm currently working on a Django app that will parse the contents of an uploaded log file to the associated database in my Django project. I've managed to get it all running as expected except it won't associate my uploaded data with the model's ForeignKey. I can assign null=True which resolves the integrity error but then of course, it doesn't assign any of the uploaded data to that ForeignKey. Here's the code:
models.py
class Case(models.Model):
case_ref = models.CharField(max_length=8)
oic = models.CharField(max_length=50)
subject = models.CharField(max_length=100)
submitted_date = models.DateTimeField(default=datetime.now, blank=True)
def get_absolute_url(self):
return reverse('case_list', kwargs={'pk': self.pk})
def __str__(self):
return self.case_ref + " " + self.subject
class TeamviewerLogs(models.Model):
case = models.ForeignKey(Case, on_delete=models.DO_NOTHING)
teamviewer_id = models.IntegerField()
teamviewer_name = models.TextField()
connection_start = models.TextField()
connection_end = models.TextField()
local_user = models.TextField()
connection_type = models.TextField()
unique_id = models.TextField()
def get_absolute_url(self):
return reverse('case_list', kwargs={'pk': self.pk})
def __str__(self):
return str(self.teamviewer_id) + " - " + str(self.teamviewer_id)
forms.py
class UploadLog(forms.ModelForm):
file = forms.FileField()
class Meta:
model = TeamviewerLogs
fields = [
'file'
]
views.py
def add_logs(request, pk):
case = get_object_or_404(Case, pk=pk)
if request.method == 'POST':
form = UploadLog(request.POST, request.FILES)
if form.is_valid():
teamviewer = form.save(commit=False)
teamviewer.case = case
log_file = request.FILES['file']
log_file = filter(None, (line.rstrip() for line in log_file))
for lines in log_file:
split = lines.decode('utf-8').split('\t')
teamviewer_id = split[0]
teamviewer_name = split[1]
connection_start = split[2]
connection_end = split[3]
local_user = split[4]
connection_type = split[5]
unique_id = split[6]
teamviewer = TeamviewerLogs(teamviewer_id=teamviewer_id, teamviewer_name=teamviewer_name,
connection_start=connection_start, connection_end=connection_end,
local_user=local_user, connection_type=connection_type, unique_id=unique_id)
teamviewer.save()
return redirect('tv_log_details', pk=case.pk)
form.save()
else:
form = UploadLog()
return render(request, 'teamviewer/add_logs.html', {'form': form})
But when I click to upload the file I'm hit with:
When it tries to execute teamviewer.save().
I've been trying to resolve this issue for hours and have tried so many different variations of answers from Stackoverflow or previous code I've used that has worked for different models but I've hit a brick wall...hard!
Any help anyone can offer would be greatly appreciated.
Ok, so here's an example of the concept I've suggested in the comments.
I've got a view which passes some data to the a form;
class ListingDetailView(DetailView):
""" Listing detail page """
model = Listing
template_name = 'listing.html'
def get_form_kwargs(self):
"""Return the kwargs for the form"""
kwargs = {}
initial = {
'listing': self.object,
}
kwargs['initial'] = initial
return kwargs
def get_form(self):
form = ApplicationSignupForm(
**self.get_form_kwargs()
)
return form
def get_context_data(self, **kwargs):
""" Add our form to the context """
context = super().get_context_data(**kwargs)
context['form'] = self.get_form()
return context
The form then makes use of that initial data and sets the field it relates to as hidden. I don't validate this data, but I'll try to show how you might do that;
class ApplicationSignupForm(forms.ModelForm):
class Meta:
""" Setup the form """
fields = (
'listing',
...
)
model = Application
widgets = {
'listing': forms.HiddenInput()
}
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
initial_data = kwargs['initial']
self.listing = initial_data.get('listing')
def clean(self):
"""
Custom form cleaning
"""
cleaned_data = super().clean()
listing = cleaned_data.get('listing')
if listing != self.listing:
self.add_error('listing', "You can't modify this value")
return cleaned_data
I have two models and forms linked by the ForeignKey 'squad'. In my templates I have the user first typing the Squad name and then the shooters. I am trying to hardcode the 'squad' field of my Shooters with the 'squad_name' of my ShooterSquad so the user doesn't have to type the squad name every time for every shooter.
models.py
class ShooterSquad(models.Model):
squad_name = models.CharField(unique=True, max_length=100)
school = models.CharField(max_length=100, null=False)
def __str__(self):
return self.squad_name
class Shooter(models.Model):
name = models.CharField(max_length=100)
squad = models.ForeignKey(ShooterSquad, to_field='squad_name', related_name='squad', on_delete=models.PROTECT)
def __str__(self):
return self.name
forms.py
class ShooterSquadForm(forms.ModelForm):
class Meta:
model = ShooterSquad
fields = ['squad_name', 'squad_total_score', ]
class ShooterForm(forms.ModelForm):
class Meta:
model = Shooter
fields = '__all__'
class BaseShooterFormSet(BaseModelFormSet):
def __init__(self, *args, **kwargs):
super(BaseShooterFormSet, self).__init__(*args, **kwargs)
self.queryset = Shooter.objects.none()
ShooterFormSet = inlineformset_factory(
ShooterSquad, Shooter,
form=ShooterForm,
formset=BaseShooterFormSet,
extra=1,
max_num=3,
exclude=('squad',)
)
views.py
def add_multiple_shooters(request):
if request.method == 'POST':
squad_form = ShooterSquadForm(request.POST)
formset = ShooterFormSet(request.POST)
if squad_form.is_valid() and formset.is_valid():
set_squad = squad_form.cleaned_data.get('squad_name')
for f in formset.forms:
f.cleaned_data['squad_id'] = set_squad
f.cleaned_data['squad'] = set_squad
print(formset.cleaned_data)
squad_form.save()
formset.save()
return redirect('anasp:mainpage')
else:
print("ERROR")
formset = ShooterFormSet()
squad_form = ShooterSquadForm()
context = {
"title": title,
"formset": formset,
"squad_form": squad_form,
}
return render(request, "anasp/scores/shooter_formset.html", context)
Input Form Sample
My cleaned_data prints: [{'shooter_number': 67, 'squad': 'Woodland', 'name': 'Legolas', 'DELETE': False, 'id': None, 'shooter_score': 39, 'squad_id': 'Woodland'}]
So it seems that the squad_id has changed right? Wrong. When I look in my db my squad_id is <null>
How do I fix that?
Python: 3.5.4 Django: 1.8
I fixed it by not committing the save before all the changes were made:
if squad_form.is_valid():
squad = squad_form.save(commit=False)
if formset.is_valid():
shooters_to_save = list()
for f in formset.forms:
shooter = f.save(commit=False)
shooter.squad = squad
shooters_to_save.append(shooter)
squad.save()
for shooter in shooters_to_save:
shooter.save()
return redirect('anasp:mainpage')
I have a ModelForm for a parent model and and an InlineForm for a foreign key related model. The Inline form data is read only and can only be updated via a file upload. I have this working on the intial creation and save, but if you replace the students by uploading a new file, while the data updates properly after the upload and save, the inline form doesn't reload properly right after this save and displays an error. However, if you navigate away and return everything looks good.
Models.py
class Room(models.Model):
room_id = models.AutoField(primary_key=True)
name = models.TextField(blank=False, verbose_name = "Room Name ")
code = models.TextField(blank=False)
file = models.TextField(blank=False)
class Meta(object):
managed = False
db_table = 'public\".\"room'
class Student(models.Model):
room = models.ForeignKey(Room, related_name="students, to_field="room_id", db_column="room_id")
student_id = models.TextField(blank=False, primary_key=False)
#property
def grade(self):
return util.get_grade(self.student_id)
class Meta(object):
managed = False
db_table = 'public\".\"student’
admin.py
class StudentsInline(admin.TabularInline):
model = Student
form = StudentInlineForm
formset = StudentFormSet
readonly_fields = ('student_id', 'grade')
extra = 0
def get_actions(self, request):
'''
Removes the delete action
'''
actions = super(StudentsInline, self).get_actions(request)
del actions['delete_selected']
return actions
def has_delete_permission(self, request, obj=None):
return False
def has_add_permission(self, request, obj=None):
return False
class RoomAdmin(admin.ModelAdmin):
def student_count(self, obj):
return obj.students.count()
student_count.short_description = " Total Enrolled "
form = RoomForm
list_display = [name', ‘code']
readonly_fields = ['student_count']
list_per_page = 25
inlines = [StudentsInline]
def get_actions(self, request):
actions = super(RoomAdmin, self).get_actions(request)
del actions['delete_selected']
return actions
def has_delete_permission(self, request, obj=None):
return False
def save_formset(self, request, form, formset, change):
form.instance.file = 'processed file'
form.instance.save
formset.save()
forms_admin.py
class RoomsForm(forms.ModelForm):
def __init__(self, *args, **kwargs):
super(RoomsForm, self).__init__(*args, **kwargs)
self.fields[‘name'].required = True
self.fields[‘code'].required = True
self.fields['file'] = forms.FileField(
label='Upload your enrollees:'
def load_file(self, upload_file):
student_list = []
data = upload_file.read() #simplified for this example
for s in reader:
s_id = s[0]
new_student = Student(student_id=s_id)
student_list.append(new_student)
return student_list
def save(self, *args, **kwargs):
room_form = super(RoomsForm, self).save(commit=False)
enrollee_list = self.load_file(self.instance.file.file)
if instance.room_id is None:
instance.file = 'uploaded'
instance = super(RoomsForm, self).save(commit=True)
Student.objects.filter(room_id=self.instance.room_id).all().delete()
instance.students.add(*enrollee_list)
return instance
class Meta:
model = Room
fields = '__all__'
class StudentForm(forms.ModelForm):
def __init__(self, *args, **kwargs):
super(StudentForm, self).__init__(*args, **kwargs)
I have form for adding data in database and I want to restrict foreign key choices in my dropdown menu. It have to be restricted on my finishDate field. If finishDate is date before today (eg. today is 21-08-2016 and finishDate is 30-06-2013), then I don't want to show foreign key value of that finishDate. What is the easiest way to do this? I am relative new at this, so I need help.
models.py
class Account(models.Model):
startDate = models.DateField(verbose_name="Start")
finishDate = models.DateField(verbose_name="Finish")
def __str__(self):
return 'A{}'.format(self.id)
class Net(models.Model):
date = models.DateTimeField(default=datetime.now())
MB = models.IntegerField(validators=[MinValueValidator(1)],default=randint(100,2000))
idAccount = models.ForeignKey(Account, on_delete=models.CASCADE, verbose_name="Account")
def __str__(self):
return 'Record {}'.format(self.datum)
forms.py
class NetForm(ModelForm):
class Meta:
model = Net
fields = ['idAccount']
views.py
#login_required(login_url="/accounts/login/")
def net(request):
if request.method == 'POST':
form = NetForm(request.POST)
if form.is_valid():
internet = form.save()
return HttpResponseRedirect('/')
else:
form = NetForm()
return render(request, 'project/Net.html', {'form': form})
Thanks a lot!
You can filter it in the __init__
import datetime
def NetForm(forms.ModelForm):
#...fields
def __init__(self, *args, **kwargs):
super(NetForm, self).__init__(*args, **kwargs)
# Now set the queryset...
self.fields['idAccount'].queryset = Account.objects.filter(finishDate__gte=datetime.datetime.now())
models.py:
class Tag(models.Model):
name = models.CharField(max_length=100)
description = models.CharField(max_length=500, null=True, blank=True)
created = models.DateTimeField(auto_now_add=True)
modified = models.DateTimeField(auto_now_add=True)
class Post(models.Model):
user = models.ForeignKey(User)
tag = models.ManyToManyField(Tag)
title = models.CharField(max_length=100)
content = models.TextField()
created = models.DateTimeField(default=datetime.datetime.now)
modified = models.DateTimeField(default=datetime.datetime.now)
def __unicode__(self):
return '%s,%s' % (self.title,self.content)
class PostModelForm(forms.ModelForm):
class Meta:
model = Post
class PostModelFormNormalUser(forms.ModelForm):
class Meta:
model = Post
widgets = { 'tag' : TextInput() }
exclude = ('user', 'created', 'modified')
def __init__(self, *args, **kwargs):
super(PostModelFormNormalUser, self).__init__(*args, **kwargs)
self.fields['tag'].help_text = None
views.py:
if request.method == 'POST':
form = PostModelFormNormalUser(request.POST)
print form
print form.errors
tagstring = form.data['tag']
splitedtag = tagstring.split()
if form.is_valid():
temp = form.save(commit=False)
temp.user_id = user.id
temp.save()
l = len(splitedtag)
for i in range(l):
obj = Tag(name=splitedtag[i])
obj.save()
post.tag_set.add(obj)
post = Post.objects.get(id=temp.id)
return HttpResponseRedirect('/viewpost/' + str(post.id))
else:
form = PostModelFormNormalUser()
context = {'form':form}
return render_to_response('addpost.html', context, context_instance=RequestContext(request))
Here form.is_valid() is always false because it gets the tag as string from form. But it expects list as form.data['tag'] input. Can anyone tell me how can i fix it?
How can i write a custom widget to solve this?
I don't think you need a custom widget (you still want a TextInput), you want a custom Field. To do this, you should subclass django.forms.Field. Unfortunately the documentation is scant on this topic:
If the built-in Field classes don’t meet your needs, you can easily create custom Field classes. To do this, just create a subclass of django.forms.Field. Its only requirements are that it implement a clean() method and that its init() method accept the core arguments mentioned above (required, label, initial, widget, help_text).
I found this blog post that covers both custom widgets and fields in more depth. The author disagrees with the documentation I quoted above - it's worth reading over.
For your specific situation, you would do something like this (untested):
class MyTagField(forms.Field):
default_error_messages = {
'some_error': _(u'This is a message re: the somr_error!'),
}
def to_python(self, value):
# put code here to coerce 'value' (raw data from your TextInput)
# into the form your code will want (a list of Tag objects, perhaps)
def validate(self, value):
if <not valid for some reason>:
raise ValidationError(self.error_messages['some_error'])
Then in your ModelForm:
class PostModelFormNormalUser(forms.ModelForm):
tag = MyTagField()
class Meta:
model = Post
exclude = ('user', 'created', 'modified')
def __init__(self, *args, **kwargs):
super(PostModelFormNormalUser, self).__init__(*args, **kwargs)
self.fields['tag'].help_text = None