Correct way to define the initial value of a form field in Django from a database, when database values may change - python-3.x

I am trying to create an interview feedback capture app using Django. The interview feedbacks follow a template. The template would evolve with time. Therefore whenever a new interview feedback template is available, it is updated to the database by an admin user.
Whenever an interviewer opens the app, he should see the latest value of the template available in the database as the initial value of the feedback form.
Currently I am able to provide the initial value of the feedback field using the 'initial' argument of the feedback field.
Below is the code (I am interested in the R1Form):
from django import forms
from .models import R1
from .model_templates import template_R1
from ckeditor.widgets import CKEditorWidget
class DateInput(forms.DateInput):
input_type = 'date'
class R1Form(forms.ModelForm):
interview_date = forms.DateField(widget = DateInput())
feedback = forms.CharField(widget = CKEditorWidget(), initial = template_R1.objects.all().last().template)
class Meta:
model = R1
fields = ['interview_date', 'interviewers', 'comment', 'recommended_level', 'progress']
The problem with this approach if that if the template is updated the form field still shows an earlier snapshot of the template when the django server was started.
Is there any other way the form field would show dynamic values as soon as the template is updated in the database? I believe somehow if the initial value could be passed from the views.py, then this could be resolved?

Okay so, I found an elegant solution.
I used the init method of the form class to initialize the feedback field:
class R1Form(forms.ModelForm):
interview_date = forms.DateField(widget=DateInput())
feedback = forms.CharField(widget=CKEditorWidget())
class Meta:
model = R1
fields = ['interview_date', 'interviewers', 'feedback', 'comment', 'recommended_level', 'progress']
And from the views, I used the get_initial method to pass the initial value of the form as the template value from the database.
class R1CreateView(LoginRequiredMixin, UserPassesTestMixin, CreateView):
model = R1
template_name = "interviews/r1/create.html"
def get_initial(self):
"""Return the initial data to use for forms on this view."""
return {'feedback': template_R1.objects.all().last().template}

Related

How to override field name attribute in django model form?

I have a model form similar to the one below:
class BookSearchForm(ModelForm):
class Meta:
model = Book
fields = ['publisher', 'authors', 'category'
How to override fields name attribute in the above model form?
I tried this, but it did not work:
class BookSearchForm(ModelForm):
class Meta:
model = Book
fields = ['publisher', 'authors', 'category'
widgets = {
'publisher': forms.SelectMultiple(attrs={'name': 'pub'}),
'authors': forms.SelectMultiple(attrs={'name': 'aut'}),
'category': forms.SelectMultiple(attrs={'name': 'cat'}),
}
you don't want to change the name of a field in the forms, django needs that to collect data for that field if you don't provide db_column as the name of the db column. what you can do with the first option, if you want the user to see publisher or some other name, in the models, add a verbose_name and then for the actual name you can declare the field however you want. Your code could look like this
pub = models.WhateverField(verbose_name='what i want you to see')
now when you do {{form.pub.label)}}, 'what i want you to see' is displayed in the html. Of course, don't forget to add the actual input in you template, {{form.pub}}. This way, you don't add anything extra in the form to display a user friendly name. I've posted this as an answer as i ran out of characters for a commment.

Django Form Field Not Setting Value After Submitting

I'm trying to post data from a form that contains incomplete data (I set the missing data in the View class before saving) for the following model. But the form does not get submitted as it is invalid (it's missing the harvest_amount, but I set the value on the webpage before submitting.
class Harvest(models.Model):
harvest_amount = models.IntegerField(validators=[MinValueValidator(limit_value=0)])
harvest_date = models.DateField()
harvest_for_plant = models.ForeignKey(Plant, on_delete=models.CASCADE)
and my form
class HarvestCreationForm(forms.ModelForm):
class Meta:
model = Harvest
fields = [
'harvest_amount'
]
def is_valid(self):
//check if Id in the url contains a valid id for a plant
return True
In this case I forgot to migrate my changes to the model (where a field was deleted). When the form posted the data it would always hit the not null constraint since the deleted field was not being set.

Django Admin - Include field of a model A when adding a record of model B

I'm working on legacy code which is in Django (1.11)
I have a model A, with attributes:
Model_A:
Name (NOT NULL)
City (NOT NULL)
FieldX (Nullable) - CharField
And a model B, with attributes:
Model_B:
Name (NOT NULL)
City (NOT NULL)
RelatedField (ForeignKey to an instance of Model_A)
Now, When I add a record for Model_A then I may NOT need to fill FieldX.
However, When I add a record for Model_B then I'll have to select an instance of Model_A and then if FieldX of that instance is NULL then I have to fill that as well (make it mandatory).
The form for Model_A is pretty straight forward.
But for Model_B I need a form where:
First an instance of Model_A is selected (Dropdown)
The input box for FieldX of instance selected in 1 is shown (Editable and mandatory to fill, blank=False).
The rest of the fields are shown (Name, City, FieldY).
Can this be done using the admin page? Or will I have to create proper forms and user flow for this?
I have not tested this, but you should be able to do the following:
from django.contrib import admin
class ModelAForm(ModelForm):
FieldX = CharField(
required=True
)
class Meta:
model = Model_A
fields = ['FieldX']
class ModelAInline(admin.StackedInline):
model = Model_A
form = ModelAForm
class ModelBAdmin(admin.ModelAdmin):
inlines = [
ModelAInline
]
admin.site.register(ModelB, ModelBAdmin)
For model B I'd override the view and form in order to achieve this in admin site.
model_b_view = ModelBView.as_view()
#admin.register(Model_B)
class Model_B_Admin(admin.ModelAdmin):
def get_urls(self):
urls = super().get_urls()
my_urls = [
url(r'^add/$',
self.admin_site.admin_view(model_b_view)),
]
return my_urls + urls
Where ModelBView is a template view, and you'd have to override get and post of it, In get send all instances of Model_A to template and handle via jquery there.

How to capture many to many field values via get_initial command

I am slowly progressing in my django journey, but this one has me stumped. I am trying to populate a CreateView with a different model via a copy command using the get_initial override. All of the attributes copy as I would expect with the exception of the ManytoMany fields. I've researched this topic most of today, and found the following which is very close to what I'm trying to figure out KeyError: 'manager' in django get_initial.
My View...
class BookView(LoginRequiredMixin,CreateView):
model = Book
template_name = 'book/titles.html'
form_class = BookForm
def get_initial(self):
initial = super(BookView, self).get_initial()
author = author.objects.get(pk=self.kwargs["pk"])
initial = author.__dict__.copy()
initial.update({
"author": author.name,
}}
for field in self.form_class.base_fields.items():
value = getattr(self.get_object(), field)
if field == 'author':
value = self.get_object().author.all()
initial.update({field: value})
return initial
I incorporated the suggested change based on the issue that I found on SO, but I still am getting a 'manager" KeyError. I am ultimately trying to populate the manytomanyfield in my model and then save the values, but to no avail. Any suggests are appreciated!
What a difference a day makes....
def get_initial(self):
initial = super(BookView, self).get_initial()
author = author.objects.get(pk=self.kwargs["pk"])
initial = author.__dict__.copy()
initial.update({
"author": author.name.all(),
}}
return initial
I added a .all() after the reference to the manytomanyfield in my initial get and also update the form to get the field in question. Much cleaner than a few hacks I kinda got working along the way.

Post Function Script: Set Value of Custom Field

I have a requirement to automatically populate a custom field during a particular workflow transition. This field is called "Owner" and should be populated with the name of the asignee.
I am new to scripting post functions, so as a first step, I tried the following code to attempt to populate that field with a test string. The workflow transition works, I see no errors, but the field remains empty.
import com.atlassian.jira.bc.issue.search.SearchService;
import com.atlassian.jira.component.ComponentAccessor;
import com.atlassian.jira.issue.Issue;
import com.atlassian.jira.web.bean.PagerFilter;
import com.atlassian.jira.issue.fields.CustomField;
import com.atlassian.jira.issue.CustomFieldManager;
ComponentManager componentManager = ComponentManager.getInstance();
CustomFieldManager customFieldManager = componentManager.getCustomFieldManager();
CustomField cfOwner = customFieldManager.getCustomFieldObjectByName("Owner"); IssueChangeHolder changeHolder = new DefaultIssueChangeHolder();
cfOwner.updateValue(null, issue, new ModifiedValue(issue.getCustomFieldValue(customFieldTarget), "Test"), changeHolder);
I would appreciate assistance to determine what I am doing wrong.
I think you can use in built post functions to achieve this.go to edit your workflow and select your transition need to be configure then click on post functions then navigate to add post function.
then select post function shown as the image then in next screen you can select your custom field and you can set the value as you need.

Resources