Getting FieldError in modelformset factory in django view.py - python

I am getting FieldError as :
Unknown field(s) (notedate) specified for AssistantNotes
When i call the page. It throws this error. I am using Django 1.9.5 and python 2.7.
I have notedate field in the AssistantNotes table in my db. If i delete "notedate" from modelformset_factory row in my view, it works. I couldnt solve why it is not showing notedate although it is in DB and in model. And generating error. The field is already in the model.
My view is :
def edit_assistant_notes(request):
isassistantsuperadmin = getUserPermissions(request) #Yes if 1, no if 0
list = getUserType(request)
userisassistant = list[2]
if userisassistant == "YES" or isassistantsuperadmin ==1:
list = getUserType(request)
type = list[0]
usertype = list[1] #"Nöbetçi Muavin":1 , "Yetkili":2
if request.method == 'GET':
if AssistantNotes.objects.filter(notedate=nicosia_date(datetime.today()).date()).count() == 0:
AssistantNotesFormsetFactory = modelformset_factory(AssistantNotes, fields=('time', 'notedate', 'categories', 'type', 'dailynote',))
else:
AssistantNotesFormsetFactory = modelformset_factory(AssistantNotes, fields=('time', 'notedate', 'categories', 'type', 'dailynote',), can_delete=True)
if usertype == 1:
formset = AssistantNotesFormsetFactory(queryset=AssistantNotes.objects.filter(notedate=nicosia_date(datetime.today()).date(), type=type))
elif usertype == 2:
formset = AssistantNotesFormsetFactory(queryset=AssistantNotes.objects.all().order_by("notedate", "time"))
helper = TableInlineHelper()
return render(request, 'edit-assistant-notes.html', {'formset': formset, 'helper': helper})
My model is :
class AssistantNotes(BaseModel):
categories = models.CharField(choices=CATEGORIES, default="GENERAL", max_length=100, verbose_name=_("CAT"))
time = models.CharField(choices=TIME, default="-------------", max_length=20, verbose_name=_("Time"))
dailynote = models.TextField(null=True, blank=True, verbose_name=_("Add Note"))
writer = models.TextField(null=True, blank=True, verbose_name=_("Adder"))
notedate = models.DateField(auto_now_add=True, db_index=True, verbose_name=_("Date"))
type = models.CharField(choices=SCHOOLTYPE, default="---", max_length=100, verbose_name=_("SchoolType"))
def __unicode__(self):
return "%s / %s" % (self.dailynote, self.categories)
class Meta:
ordering = ['dailynote']

How can i force this field to be editable ?
Instead of setting auto_now_add, you may override the save() method of the model, say
class AssistantNotes(BaseModel):
....
notedate = models.DateField(db_index=True, verbose_name=_("Date"))
def save(self, *args, **kwargs):
if not self.id:
self.notedate = timezone.now()
return super(AssistantNotes, self).save(*args, **kwargs)

Related

Failure to save certain attributes from ModelForm to django database (Logic error)

I have a ModelForm called ListingForm. It takes data from a user but I have stopped some of the model attributes from appearing in this form as I want to feed data to those myself. I have put print statements in my createlisting function in views.py to inspect if the data is actually being saved correctltly, it turns out the data is being saved. Here is the createlisting function:
def create_listing(request):
if request.method == 'POST':
import datetime
listing_form = ListingForm(request.POST, request.FILES)
if listing_form.is_valid():
bid = listing_form.cleaned_data['starting_bid']
print(bid)
listing_form.save(commit=False)
listing_form.user = request.user
print(listing_form.user)
listing_form.date_made = datetime.datetime.today()
listing_form.is_active = True
listing_form.category = Category.objects.get(name=listing_form.cleaned_data['listing_category'])
print(listing_form.category)
#The form is being saved correctly here, and the print statements give the correct results in my terminal
listing_form.save()
Bid.objects.create(user= request.user, value=bid, listing=listing_form.instance)
all_listings = Listing.objects.all()
return render(request, 'auctions/index.html', {
'all_listings': all_listings })
else:
listing_form = ListingForm()
return render(request, 'auctions/createlisting.html',{
'listing_form':listing_form
})
However, when I try to access the data from the model Listing from which the ListingForm is inheriting, the print statements I have put for debugging return the default values for certain fields (category and user) instead of the values I have saved in the ListingForm.
Here is the code that allows me to view the data for the model instance I have created. Mind you, all the other fields have saved correctly except for the fields category and user:
def view_listing(request, listing_id):
listing = Listing.objects.get(pk=listing_id)
#the print results return the default values for the fields category and user instead of the values I saved in my ModelForm
print(listing.category)
print(listing.user)
if request.user == listing.user:
return render(request, 'auctions/view_listing.html', {
'listing': listing,
'flag':True,
'count': listing.bids.all().count()
})
else:
return render(request, 'auctions/view_listing.html',{
'listing':listing,
'count': listing.bids.all().count()
})
What could be the problem with my code?
Also, let me provide the code for some of my models and a form as the error might be embedded in those:
Listing Model:
class Listing(models.Model):
NAME_CHOICES = [
('Fashion', 'Fashion'),
('Toys','Toys'),
('Electronics','Electronics'),
('Home', 'Home'),
('Other', 'Other')
]
title = models.CharField(max_length= 64)
date_made = models.DateTimeField(auto_now_add=True)
description = models.TextField()
user = models.ForeignKey(User, to_field='username', on_delete=models.CASCADE, related_name='user_listings', null=True)
starting_bid = models.DecimalField(decimal_places=2, max_digits=264, default=10.00)
upload_image = models.ImageField(blank=True, upload_to='media/media')
category = models.ForeignKey(Category, on_delete=models.CASCADE, to_field='name', related_name='category_listings', default=NAME_CHOICES[4][0], db_constraint=False)
listing_category = models.CharField(max_length=12, choices=NAME_CHOICES, null=True, default=NAME_CHOICES[4][0])
is_active = models.BooleanField(default=True)
watchlist = models.ForeignKey('Watchlist', on_delete=models.DO_NOTHING, related_name='listings', null=True)
Category Model:
class Category(models.Model):
NAME_CHOICES = [
('Fashion', 'Fashion'),
('Toys','Toys'),
('Electronics','Electronics'),
('Home', 'Home'),
('Other', 'Other')
]
name = models.CharField(max_length=12, choices= NAME_CHOICES, unique=True)
User Model:
class User(AbstractUser):
def __str__(self):
return f'{self.username} '
ListingForm`` (ModelForm```):
class ListingForm(ModelForm):
class Meta:
model = Listing
exclude = [
'date_made',
'user',
'category',
'is_active',
'watchlist'
]
Any form of help would be greatly appreciated.
When you call listing_form.save(commit=False) it returns an unsaved model instance with the submitted values. If you assign that to a variable, you can use it to set the other field values and save:
def create_listing(request):
if request.method == 'POST':
import datetime
listing_form = ListingForm(request.POST, request.FILES)
if listing_form.is_valid():
bid = listing_form.cleaned_data['starting_bid']
listing = listing_form.save(commit=False)
listing.user = request.user
listing.date_made = datetime.datetime.today()
listing.is_active = True
listing.category = Category.objects.get(name=listing_form.cleaned_data['listing_category'])
listing.save()
Bid.objects.create(user=request.user, value=bid, listing=listing)
# You should probably use HttpResponseRedirect to an `all_listings` page, rather than displaying them here
all_listings = Listing.objects.all()
return render(request, 'auctions/index.html', {
'all_listings': all_listings })
Here's a link to the ModelForm.save() docs.

Django form intergrityerror: foreign key with unique field, unique constraint fails

When trying to add a second appointment (for the same date) which has a dayplan foreign key using ModelForm and CreateView, unique constraint fails due to DayPlan having 'date' field as unique.
This issue is not present using the django-admin create form.
I tried to remove the unique=True from dayplan.date to see what happens -> every time i add an appointment, even if dayplan.date exist, a new dayplan is created.
the issue seems to be related to these 2 line:
daydate = DayPlan.objects.filter(date=planned_date)
form.cleaned_data['dayplan'] = daydate
The code is here:
class DayPlan(models.Model):
date = models.DateField(unique=True, db_index=True)
comment = models.TextField(null=True, blank=True)
def __str__(self):
return 'Planning voor {}'.format(self.date)
def get_absolute_url(self):
return reverse('organizer_dayplan_detail', kwargs={'pk': self.pk})
class Appointment(models.Model):
comment = models.CharField(null=True, blank=True, max_length=255)
planned_date = models.DateField()
doctor = models.ForeignKey(Doctor)
visited = models.BooleanField(default=False)
dayplan = models.ForeignKey(DayPlan)
class AppointCreate(CreateView):
model = Appointment
form_class = AppointmentForm
template_name = 'organizer/organizer_appointment_create.html'
# initial = {'doctor': 'pk', 'comment': 'test',}
def get_initial(self):
return {
"doctor": self.request.GET.get('doctor')
}
def form_valid(self, form):
planned_date = form.cleaned_data['planned_date']
try:
daydate = DayPlan.objects.filter(date=planned_date)
form.cleaned_data['dayplan'] = daydate
form.instance.save()
except:
daydate = DayPlan.objects.create(date=planned_date)
form.instance.dayplan = daydate
form.instance.save()
return super(AppointCreate, self).form_valid(form)
class AppointmentForm(forms.ModelForm):
class Meta:
model = Appointment
fields = {'comment', 'planned_date', 'doctor', 'visited', 'dayplan'}
widgets = {'visited': forms.HiddenInput(),}
exclude = {'dayplan',}
P.S. i do realize that i don't need to use "form.instance.save()" here. removing them has no effect.
Thanks in advance!
solved
daydate, created = DayPlan.objects.get_or_create(date=planned_date)
form.instance.dayplan = DayPlan.objects.get(date=planned_date)

__str__ returned non-string (type tuple)

I have a form that keeps throwing me an error in django, Ive tried searching online tried str() on my models but wouldnt work at all. Googled a couple of times tried a couple different methods but none worked still get the same django error page everytime i click the link to the form.
TypeError: __str__ returned non-string (type tuple)
my model
# Injury Parameters -> SOI Level 2 #
####################################
class SourceOfInjuryLevel2(models.Model):
creator = models.ForeignKey('auth.User')
id = models.AutoField(primary_key=True)
soi_l1 = models.CharField(max_length=80)
soi_l2 = models.CharField(max_length=80)
status = models.CharField(max_length=8)
created_date = models.DateTimeField(default=timezone.now)
modified_date = models.DateTimeField(blank=True, null=True)
modified_by = models.CharField(max_length=60, blank=True, null=True)
def create(self):
self.save()
def __str__(self):
return self.soi_l1, self.soi_l2, self.status
my form
# Soure of Injury Level 2 #
###########################
class SourceOfInjuryLevel2Form(forms.ModelForm):
options = (('Enabled', 'Enabled',), ('Disabled', 'Disabled'))
soi_l1 = forms.ModelChoiceField(
queryset=SourceOfInjuryLevel1.objects.filter(status='Enabled'),
widget=forms.Select(attrs={'class': 'form-control'})
)
soi_l2 = forms.CharField(
widget=forms.TextInput(attrs={'class': 'form-control'})
)
status = forms.CharField(
widget=forms.Select(
attrs={'class': 'form-control'},
choices=options
)
)
class Meta:
model = SourceOfInjuryLevel2
fields = ('soi_l1', 'soi_l2', 'status')
My Views
# New Source of Injury Level 2 #
################################
def new_source_of_injury_level2(request):
form = SourceOfInjuryLevel2Form()
if request.method == "POST":
form = SourceOfInjuryLevel2Form(request.POST)
if form.is_valid():
source_of_injury_level2 = form.save(commit=False)
source_of_injury_level2.creator = request.user
source_of_injury_level2.created_date = timezone.now()
source_of_injury_level2.save()
messages.success(request, 'Object Has Been Created')
return redirect(injury_parameters)
else:
messages.error(request, 'Object Has Not Been Created')
else:
form = SourceOfInjuryLevel2Form()
return render(request,
'process_injury_management/source_of_injury_level2.html',
{'form': form,
'title': 'New Source of Injury Level 2'})
The error is in your model:
class SourceOfInjuryLevel2(models.Model):
...
def __str__(self):
return self.soi_l1, self.soi_l2, self.status
I guess you were confused because the Python 2 print statement looks like it turns tuples into strings, but that's not actually how the print statement works - it's a confusing detail that was changed in Python 3.
Try this instead:
def __str__(self):
template = '{0.soi_l1} {0.soi_l2} {0.status}'
return template.format(self)
Those commas aren't actually doing what you think they do. The commas make your return value a tuple instead of a string which a __str__ method is supposed to return.
You can instead do:
def __str__(self):
return '%s %s %s'%(self.soi_l1, self.soi_l2, self.status)
Or use the new-style formatting:
def __str__(self):
return '{} {} {}'.format(self.soi_l1, self.soi_l2, self.status)
You can also try this,
def __str__(self):
return f'{self.soi_l1} {self.soi_l2} {self.status}'
use the string formatting method

Default value for ForeignKey field in django admin panel

I have two django Models: PageModel and RecordModel. They are registered in django admin panel. I want automatically create RecordModel object and assign it to (object of PageModel).record field if record is not selected in process of Page creation. (Django Admin - Add Page form) I tried to create form and used clean_record() method, but that not work. (debugger is not stopped there) How can i solve the problem?
Models (Sortable and SortableAdmin classes are part of adminsortable (https://github.com/iambrandontaylor/django-admin-sortable), but I think it does not really matter):
class Record(Sortable):
"""
Запись в книге почетных гостей
"""
class Meta(Sortable.Meta):
verbose_name = u'Запись'
verbose_name_plural = u'Записи'
author = models.CharField(verbose_name=u'Автор', max_length=255, unique=False, blank=False,
default=author_default)
def __unicode__(self):
return u'Запись {} ({})'.format(self.id, self.author)
class Page(Sortable):
"""
Страница книги почетных гостей
"""
class Meta(Sortable.Meta):
verbose_name = u'Страница'
verbose_name_plural = u'Страницы'
record = SortableForeignKey(Record, verbose_name=u'Запись', related_name='pages', blank=False, default=None)
image = models.ImageField(verbose_name=u'Картинка',
upload_to='pages',
default='',
help_text=u'Размер файла - до 10 MB. Формат PNG.',
validators=[ImageValidator(formats=['PNG'], max_size=10000000)])
updated = models.DateTimeField(verbose_name=u'Обновление', auto_now=True, null=True,
help_text=u'Время последнего изменения страницы на сервере')
def __unicode__(self):
return u'Страница {} ({})'.format(self.id, self.image)
Admin:
class PageInline(SortableTabularInline):
model = Page
#admin.register(Record)
class RecordAdmin(SortableAdmin):
list_display = ['author', 'pages_count']
inlines = [PageInline]
fields = ['author']
def pages_count(self, object):
return object.pages.count()
pages_count.short_description = u'Количество страниц'
pages_count.allow_tags = False
class PageAdminForm(forms.ModelForm):
def clean_record(self):
return self.cleaned_data["record"]
#admin.register(Page)
class PageAdmin(SortableAdmin):
list_display = ['__unicode__', 'image', 'author', 'updated']
form = PageAdminForm
readonly_fields = ['updated']
def get_fields(self, request, obj=None):
if obj:
return super(PageAdmin, self).get_fields(request, obj)
else:
return ['record', 'image']
def author(self, page):
return page.record.author
author.allow_tags = False
author.short_description = u'Автор записи'
I solved the problem as follows:
Change record field in Page model
record = SortableForeignKey(Record, verbose_name=u'Запись', related_name='pages', null=True, blank=True, default=None)
Add save_model() method to PageAdmin
def save_model(self, request, obj, form, change):
if obj.record is None:
record = Record.objects.create(author=BookConfiguration.get_solo().record_author_default + ' (' + timezone.localtime(timezone.now()).strftime('%Y-%m-%d %H:%M:%S') + ')')
record.save()

Django: Edit ModelForm using AutoField

I'm trying to make a view where the user can edit DB records through a form in a template. I've searched a lot of web pages (and Django docs as well) where they teach how to make these views, but they always use the "id" that Django generates for each Model. In this particular Model, I have to use an AutoField to override the "id". Is there a way to use this AutoField as an "id" of the record with Django?
Here's my complete model:
class T031003 (models.Model):
C003IDCD = AutoField(primary_key=True)
C003INST = models.IntegerField(unique=True) #usar AutoSlug
C003TPCD = models.CharField(max_length=1)
C003CHCD = models.CharField(max_length=14)
C003MTR = models.CharField(max_length=30, blank=True, null=True)
C003CTCD = models.CharField(max_length=3)
C003RZSC = models.CharField(max_length=60, blank=True, null=True)
C003EML = models.EmailField(max_length = 254, blank=True, null=True)
C003LOGA = models.CharField(max_length=20)
C003LOGB = models.DateTimeField()
C003LOGD = models.CharField(max_length=15, blank=True, null=True)
C003LOGF = models.CharField(max_length=20, blank=True, null=True)
def __unicode__(self):
return '%s' % self.C003MTR
class T031003Form(ModelForm):
class Meta:
model = T031003
ordering = ["-C003MTR"]
exclude = ('C003LOGA','C003LOGB','C003LOGD','C003LOGE','C003LOGF')
And here's the view I tried to do, but it gives me the error "No T031003 matches the given query." and it's right, since there is no "id" in the table:
def t031003form_edit(request, id=None):
pin = get_object_or_404(T031003, pk=id)
form = T031003Form(request.POST or None, instance=pin)
if request.method == 'POST':
if form.is_valid():
form = form.save(False)
form.C003LOGA = request.user
form.C003LOGB = datetime.date.today()
form.C003LOGD = request.META['REMOTE_ADDR']
form.C003LOGF = request.META['USERDOMAIN']
form.save()
form = T031003Form()
else:
return HttpResponseRedirect('/erro/')
return render_to_response('T031003Form_edit.html', {'form': form,}, context_instance=RequestContext(request))
Any help would be very appreciated!
If a model has an AutoField — an auto-incrementing primary key — then that auto-incremented value will be calculated and saved as an attribute on your object the first time you call save():
>>> b2 = Blog(name='Cheddar Talk', tagline='Thoughts on cheese.')
>>> b2.id # Returns None, because b doesn't have an ID yet.
>>> b2.save()
>>> b2.id # Returns the ID of your new object.
There's no way to tell what the value of an ID will be before you call save(), because that value is calculated by your database, not by Django.
ref : https://docs.djangoproject.com/en/dev/ref/models/instances/?from=olddocs
Well, thanks to the help from a close friend, I could do the trick using formsets. Here's the view:
def t031002form_edit(request, id_auto):
j = get_object_or_404(T031002, pk=id_auto)
T031003FormSet = modelformset_factory(T031002, can_delete=True, max_num=1)
if request.method == 'POST':
form = T031002FormSet(request.POST or None, request.FILES or None, queryset=T031002.objects.filter(pk=id_auto))
if form.is_valid():
instance = form.save(commit=False)
form.C003LOGA = request.user
form.C003LOGB = datetime.date.today()
form.C003LOGD = request.META['REMOTE_ADDR']
form.C003LOGF = request.META['USERDOMAIN']
for reform in instance:
reform.save()
else:
return HttpResponseRedirect('/erro/')
else:
form = T031002FormSet(queryset=T031002.objects.filter(pk=id_auto))
return render_to_response(('T031002Form_edit.html'), {'form': form,}, context_instance=RequestContext(request))
So, with formsets, you can work nicely and with no worries. Hope it helps others with this same questioning.

Categories