Override a form in Django admin - python

In Django admin I want to override and implement my own form for a model (e.g. Invoice model).
I want the invoice form to have auto-fill fields for customer name, product name and I also want to do custom validation (such as credit limit for a customer). How can I override the default form provided by Django admin and implement my own?
I am new to Django, I appreciate any pointers.

You can override forms for django's built-in admin by setting form attribute of ModelAdmin to your own form class. See:
https://docs.djangoproject.com/en/dev/ref/contrib/admin/#django.contrib.admin.ModelAdmin.form
https://docs.djangoproject.com/en/dev/ref/contrib/admin/#adding-custom-validation-to-the-admin
It's also possible to override form template - have a look at https://docs.djangoproject.com/en/dev/ref/contrib/admin/#custom-template-options
If you're looking specifically for autocomplete I can recommend https://github.com/crucialfelix/django-ajax-selects

How to override a form in the django admin according to the docs:
from django import forms
from django.contrib import admin
from myapp.models import Person
class PersonForm(forms.ModelForm):
class Meta:
model = Person
exclude = ['name']
class PersonAdmin(admin.ModelAdmin):
exclude = ['age']
form = PersonForm

Related

Updates to admin.py not reflected in the django admin page

I'm building a django app and the django admin page doesn't seem to be reflecting the changes I make to admin.py. For example if I want to exclude some fields, or customizing the admin change list, nothing changes in the actual page. The only thing that seems to be reflected properly is the fact that I can register the models, and they will show up.
Here's my admin.py
from django.contrib import admin
from .models import Form, Biuletyn, Ogloszenie, Album
class FormAdmin(admin.ModelAdmin):
exclude = ('img',)
class BiuletynAdmin(admin.ModelAdmin):
list_display = ('name', 'date')
class OgloszenieAdmin(admin.ModelAdmin):
fields = ('name', 'date', 'upload')
admin.site.register(Form)
admin.site.register(Biuletyn)
admin.site.register(Ogloszenie)
admin.site.register(Album)
P.S. Please ignore the weird model names. The site is actually in a different language :D
This is how you register your ModelAdmin:
admin.site.register(Form, FormAdmin)
admin.site.register(Biuletyn, BiuletynAdmin)
admin.site.register(Ogloszenie, OgloszenieAdmin)
This how to register your Models:
admin.site.register(Album)
For more details you may refer to Django official documentation at: https://docs.djangoproject.com/en/3.2/ref/contrib/admin/#modeladmin-objects
Add admin_class
So for example for the Form model:
admin.site.register(Form, admin_class=FormAdmin)

How to add an extra field to a Django ModelForm?

So I'm working on an admin page. I'm registering the form with admin.site.register. And I want to add an extra field to the form, which will let me populate a TextField with a file contents.
Therefore I need to add an extra FileInput to upload the file and populate the TextField with its contents. I am trying this:
class PersonForm(forms.ModelForm):
extra_field = forms.FileInput()
class Meta:
model = Person
fields = '__all__'
but the field is not showing. Any ideas?
Also I have no clue where to access the file contents and populate the TextField with that before saving the model.
Thanks in advance.
My problem was in this line:
extra_field = forms.FileInput()
I solved the problem changing the line to:
extra_field = forms.FileField()
Thanks to all willing to help.
Try to do it in the constructor.
class PersonForm(forms.ModelForm):
class Meta:
model = Person
fields = '__all__'
def __init__(self, *args, **kwargs):
super(PersonForm, self ).__init__(*args, **kwargs)
self.fields['extra_field'] = forms.FileInput()
And since you are using the django admin, you need to change the form in the admin too.
What you've done is ok according to the documentation, read note here - https://docs.djangoproject.com/en/2.0/topics/forms/modelforms/#overriding-the-default-fields
To register it in the admin you should add something like this to your admin.py:
from django.contrib import admin
from .forms import PersonForm
#admin.register(Person)
class PersonAdmin(admin.ModelAdmin):
form = PersonForm
Example from here - https://docs.djangoproject.com/en/2.0/ref/contrib/admin/#admin-custom-validation
EDIT: it is necessary to actually register custom ModelAdmin, there are two equivalent ways: using decorator, as in the example above, or use admin.site.register(Person, PersonAdmin).
Documentation for ModelAdmin registration - https://docs.djangoproject.com/en/2.0/ref/contrib/admin/#the-register-decorator
Registration source code - https://github.com/django/django/blob/master/django/contrib/admin/sites.py#L85
Register the model in admin as
admin.site.register(UserProfile)
where UserProfile is a OnetoOnemodel that extends django's builtin User Model then after every changes in models run
python manage.py makemigrations
python manage.py migrate

Python/Django - Generating forms for models.

I have two questions concerning models and forms.
1) What is the best way to create automatically forms for the models?
In the example below I have two models - ModelA and ModelB. I need forms for them - ModelAForm and ModelBForm. They should be defined automatically. I do not want to do it manually, because in the future I will add other models, and all the forms will look the same. I am thinking about creating special decorator for models and use modelform_factory.
from django.db import models
from django.forms import ModelForm
class ModelA(models.Model):
...
class ModelB(models.Model):
...
class ModelAForm(ModelForm):
class Meta:
abstract = ModelA
class ModelBForm(ModelForm):
class Meta:
abstract = ModelB
2) Assuming I am using only ModelForm forms, it is possible to find the form for the model? Example. I have two models ModelA and ModelB, and two forms ModelAForm and ModelBForm. I have instance of ModelA and I would like to identify proper form for this model which I will pass to template - in this case ModelAForm.
Django provides some generic editing views. You only have to provide a model and the view will generate the form automatically. If you want to use the forms to create or update instances you can just use them.
If your really need to create the forms yourself you can use the modelform_factory that these views use themself to create the correct form for your model. But i would first go with the generic views as long as they can be modified to suit your needs.
Just pass it your model and optionally the fields you want. If you omit the fields, all fields will be generated:
from .models import MyModel
from django.forms.models import modelform_factory
my_form = modelform_factory(MyModel, fields=['name', 'age', 'job'])
There's ModelForm in django.
Here's fragment of documentation and link for it.
https://docs.djangoproject.com/en/1.10/topics/forms/modelforms/
class ArticleForm(ModelForm):
class Meta:
model = Article
fields = ['pub_date', 'headline', 'content', 'reporter']
You're probably looking for generic class-based views, where you only pass form_class and model instances, everything else django handles without your help.
Link for them - https://docs.djangoproject.com/en/1.10/ref/class-based-views/

Customize Django Group Model

I'm trying to add a field to 'Groups' within the Django admin - for instance, when you create a group in the backend, you define 'Name' and 'Permissions', and I'd like to add a field to that list (CharField). Does this require a new app, or can I extend the Group model in my root models.py?
New to django and python here, so sorry if the question is badly worded.
Here's what I have so far:
#models.py
from django.db import models
from django.contrib.auth.models import Group
class AppDBName(Group):
AppDB = models.CharField(max_length=30)
def __unicode__(self):
return self.AppDB
#admin.py
from django.contrib import admin
from .models import AppDBName
admin.site.register(AppDBName)
You can try to create a new model, which will extend the Django built-in group model. To do this you should link a new model, say GroupExtend, to the original one with a OneToOne field, like it can be done for user (link):
from django.contrib.auth.models import Group
class GroupExtend(models.Model):
group = models.OneToOneField(Group, on_delete=models.CASCADE)
# other fields
You don't need to create new app just override the django admin models.py in to your project and customize it as per your requirement.
https://docs.djangoproject.com/en/1.8/topics/db/models/

Access model name in Django CreateView from template

I'm using the generic CRUD views in Django 1.6, e.g.:
class KanriCreateView(CreateView):
template_name = 'generic_form.html'
class KanriUpdateView(UpdateView):
template_name = 'generic_form.html'
etc.
N.B. These are classes used as a base class which I subclass inside views.py files throughout the project.
In order to keep DRY I'm writing a generic form template for all create/update views.
For update views, I have access to object in the template, which is the instance I am updating. I then use object.__class__.__name__ (via a custom filter) to get the name of the class (so I can have automatically generated custom buttons like "Add User", "Add Role".etc so the forms look less...generic.
Of course, when I'm using my template in CreateView, object does not exist (as it has not been created), so my custom buttons.etc do not work, and I get a VariableDoesNotExist exception.
Does Django provide the class somewhere so I can use it in the template?
The name of your first view should be different, e.g. KanriCreateView
It might help you to get the name of the view class: {{ view.class.name }}
If you have access to the view class (which is provided by default by the ContextDataMixin) you can access the model attribute of the view class and get the name of the model: {{ view.model.__name__ }}
Cheers
If you're using a ModelForm for your CreateView, this doesn't quite work. This is because you're not specifying
model = MyModel
but instead you're specifying
form_class = MyModelForm
so what you can do instead is
from django.contrib.admin.utils import model_ngettext
model_ngettext(self.form_class._meta.model, 1)
I propose a solution updated for Django 2 and 3: retrieve the model verbose name from the ModelForm associated to the CreateView.
class YourCreateView(CreateView):
form_class = YourModelForm
def get_context_data(self, **kwargs):
"""Add the models verbose name to the context dictionary."""
kwargs.update({
"verbose_name": self.form_class._meta.model._meta.verbose_name,})
return super().get_context_data(**kwargs)
Now you can use {{ verbose_name }} inside your template.
Please, remark the double _meta in the code snippet above: the first is meant to access the model from the ModelForm, while the second accesses the verbose name of the Model.
As with internationalization, remark that if your model uses ugettext as shown below, then the verbose name will automatically be translated in the template.
from django.utils.translation import ugettext_lazy as _
class MyModel(models.Model):
class Meta:
verbose_name = _("your verbose name")

Categories