Django Admin - Custom Inline Form - python

I'm attempting to use a custom inline form within the django admin.
admin.py --
class EmpInline(admin.StackedInline):
model = Emp
form = UpdateYearlyForm
show_change_link = True
class CompanyAdmin(admin.ModelAdmin):
list_display = ('companyname','companyid','get_active', 'get_updated')
inlines = [EmpInline]
When the Company name is clicked on, the company details are shown along with a formset for all the related employees.
This works in regards to displaying the form however one of the fields is a custom choice field which indirectly updated a model field. Which, in the normal user view (this form needs to be used both by an admin for all records and for users for the records pertaining to them) the custom field is handled as below.
I've only shown a snippet of the view as it is quite long.
views.py --
if formset.is_valid():
for form in formset.forms:
if form.is_valid():
obj = form.save(commit=False)
data = form.cleaned_data
if data['updatefield'] == 'accident':
obj.years += 1
else data['updatefield'] == 'free':
obj.years += 1
obj.save()
Is there a way of handling the form (and the custom field) in the same way when used as an inlineform in the admin?

If it helps anyone - overriding the save() function on the form itself sorted this problem and it probably better practice therefore I changed to using this on both the User and Admin side.

Related

Django - Use TextInput form to look up a ForeignKey

I'm currently trying to build an application in Django where users should be able to create new entries for a model. Said model contains a ForeignKey relation to a different model. However, the classic dropdown form field is not practical, because there could be hundreds of entries to choose from. Instead, I'd like to allow users to simply type in the name of the entry (all names are unique), which then gets transformed to the corresponding ID when pressing the Submit button.
I feel like this should be pretty straightforward to do, but since I'm new to Django I'm having a hard time to figure out how to do it. Currently the problem is, that the form field is declared invalid, due to the ForeignKey not existing (since the user typed in the name and not the ID of the database entry).
Code example:
forms.py:
class DogForm(ModelForm):
class Meta:
model = Dog
fields = "__all__"
widgets = {" shelter": widgets.TextInput(attrs={"id":" shelter", "placeholder":" Dog Shelter"}),
"name": widgets.TextInput({"id":"name", "placeholder":"Name"}),
def clean(self):
shelter= self.data.get("shelter")
self.cleaned_data["shelter"] = Shelter.objects.get(name=shelter)
return self.cleaned_data
views.py:
class DogCreate(CreateView):
model = Dog
form_class = DogForm
def form_valid(self, form):
if form.is_valid():
instance = form.save(commit=False)
instance.save()
return super(DogCreate, self).form_valid(form)
As you can see, my idea was to overwrite the clean method, by adding the correct Shelter to self.cleaned_data (based on the name the user put into the TextInputField). But this does not seem to work, because when pressing submit, the form is still declared invalid.

Issue with ModelForm and related objects

I have come to an impasse when using a ModelForm.
I'm extending the User model that comes with Django, and I'm also using a ModelForm so the user can edit it.
Following the same example in the documentation, I would have this code.
models.py
class Employee(models.Model):
user = models.OneToOneField(User, on_delete=models.CASCADE)
# In this case, department is optional, so I have set 'blank' and 'null' to True.
department = models.CharField(max_length=100, blank=True, null=True)
forms.py
class DepartmentForm(ModelForm):
class Meta:
model = Employee
fields = ['department',]
The problem comes at the view. I found that I need to pass an instance of the model to the form so the save() function works without having to customize it, but of course, user.employee has not been created yet, therefore it throws an error.
views.py
def DepartmentView(request):
# Here is the issue.
department = request.user.employee
if request.method == 'POST':
# I need to pass the instance here.
form = DepartmentForm(request.POST, instance=department)
if form.is_valid():
form.save()
else:
# And also here so it autocompletes the form.
form = DepartmentForm(instance=department)
return render(request, 'employee.html', {'form': form})
It works if I manually add a value to user.employee.department through the shell and then reload the page, otherwise the error is as follow.
RelatedObjectDoesNotExist at [something]
User has no employee.
Or something like that... I'm sorry, I didn't try the code above so the error could be a little different, but the concept is exactly the same.
I'm also sorry if this has been asked before. I did a Google search and couldn't find an answer to this issue.
You could use get_or_create to fetch the employee from the db, or create it if it doesn't exist.
department, created = Employee.objects.get_or_create(user=request_or_user, department='')
if request.method == 'POST':
form = DepartmentForm(request.POST, instance=department)
...
Another option is to use a signal, so that the related model is created when the user is created. Then you can assume that the employee already exists, and you can use request.user.employee instead of get_or_create.

Add extra fields to my UserCreationForm from my extended User model

I need two extra fields for the user data so I followed the official django docs Extending the existing User model, the admin form for users works fine but I have a UserCreationForm and I want to add the two extra fields in that form too, already tried to use two forms, the UserCreationForm and the form for my extended user model but I can't get the id of the UserCreationForm to fill the user_id of my extended user model so I search how to use a signal to do that like the django docs recommend and find this Django Signals: create a Profile instance when a new user is created but that only fill the user_id of my extended user model that is the OneToOneField but not the two extra fields.
sorry for my bad english.
I need to run but here's a quick implementation. It needs some tweaks apparently but should get you started:
# this is your model form for extended OneOnOne with user
class ExtendedForm(forms.ModelForm):
model = ExtendedModel
# temporary exclude user field to pass the validation
exclude = ('user')
def create_user(request):
user_form = UserForm(request.POST or None)
extra_form = ExtendedForm(request.POST or None)
if user_form.is_valid() and extra_form.is_valid():
# create a new user first
new_user = user_form.save()
# create an object in memory but not save it
new_extended_obj = extra_form.save(commit=False)
# assign the user to the extended obj
new_extended_obj.user = new_user
# write to database
new_extended_obj.save()

Custom django form that has fields populated from database

I am new to Django. I have a custom form that uses forms.Modelform to create a custom form from my model. I have some data in my database already that I manually input for testing.
However, the user and course field shows up as dropdowns. But they do not have any data in the dropdown list. How can I have django to pull data from the database and display the information into each dropdown on my form?
models.py:
class Student(models.Model):
user = models.OneToOneField(User)
course = models.ForeignKey(Course)
view.py:
def home(request):
if request.method == 'GET':
form = StudentForm()
else:
form = StudentForm(request.POST)
if form.is_valid():
pass
return render(request, "request.html", {'form': form}, context_instance=RequestContext(request))
forms.py:
class StudentForm(forms.ModelForm):
class Meta:
model = Student
Update
Actually found out that the changes weren't saved to my DB. They are now loading into the form. However in the dropdown list, it is showing up as "Student Object", and "Course Object"
How can I make it so they show up with proper names?
I would advocate that you move away from doing this if this is testing, and instead follow the guidelines for testing as outlined in the django tutorials, i.e. it creates a fake database for you and you create Users and Courses via Users.objects.create(username=...)

ModelForms on an extended User table (inline formset)

I extended the Django user in order to have additional fields. I named this entity Persons.
I am using the ModelForm in order to generate my fields. I am making a basic form insertion. When I generate the form, since I am expanding the User model and there exists a one-to-one relationship, the username name shows up as a select box, so users can select from already existing users. However, what I want to do is when a user fills in the form, for a username to be created.
Do I need to create two separate forms with the same submit, or its possible to use an inline formset? What would be the best way to solve this? I am declaring my form like this:
def trainer_signup(request):
TrainerFormSet = modelformset_factory(Trainer)
if request.method == 'POST':
formset = TrainerFormSet(request.POST, request.FILES)
if formset.is_valid():
formset.save()
# do something.
else:
formset = TrainerFormSet()
return render_to_response("forms.html", {
"formset": formset,
})

Categories

Resources