I have a model (Application) tied to a foreign_key (Person) table. I was having trouble getting the Person-dropdown in the admin to sort by name instead of by key, and found this Reorder users in django auth as a solution. However, this made the fields mandatory and I can't figure out how to get them to stay optional.
app/models.py
class Person(models.Model):
Full_Name = models.CharField(max_length=200)
def __unicode__(self):
return self.Full_Name
class Application(models.Model):
Name = models.CharField(max_length=100)
Primary_Contact = models.ForeignKey(Person,blank=True,null=True,related_name='appprimarycontact')
def __unicode__(self):
return self.Name
admin.py
class OwnerAdminForm(forms.ModelForm):
Primary_Contact = forms.ModelChoiceField(queryset=Person.objects.order_by('Full_Name'),)
class Meta:
model = Application
class ApplicationAdmin(admin.ModelAdmin):
form = OwnerAdminForm
list_display = ('Name','Primary Contact')
Just add the required=False option on the form field
forms.ModelChoiceField(required=False, queryset=Person.objects.order_by('Full_Name'))
The thing is, if you override the default form widget that django's ModelForm would provide, you would have to explicitly specify required=False, since the default value is True
Related
Suppose below models:
from django.db import models
class Status:
name = models.CharField(max_length=50)
order = models.PositiveIntegerField()
def __str__(self):
return self.name
class Article:
headline = models.CharField(max_length=100)
status = models.ForeignKey(Status, on_delete=models.CASCADE, null=True)
I want to create admin form for Article model, but don't want to use results of __str__ method of Status model as display name in status choices form field. It can be achieved by overriding label_from_instance method ModelChoiceField as below:
from django import forms
from blog.models import Status, Article
class StatusModelChoiceField(forms.ModelChoiceField):
def label_from_instance(self, status):
label = f"{status.order}: {status.name}"
return label
class ArticleForm(forms.ModelForm):
status = StatusModelChoiceField(queryset = Status.objects.all())
class Meta:
model = Article
fields = ('headline', 'status')
Problem with this method is that, it doesn't take into account Article model's status field definition. For example, although status field is nullable in Article model, it is required in ArticleForm. I should tell explicitly that it is not required (status = StatusModelChoiceField(queryset = Status.objects.all(), required=False)). If status field would have limit_choices_to, it also won't be considered in my form dynamically.
So, I just want different display names than default __str__. How can I achieve this goal in more DRY manner?
Although you will have to make the custom field inheriting from ModelChoiceField, what you can do is set it as the class to be used for your field by using the field_classes attribute one can set on the forms Meta (Reference Overriding the default fields [Django docs]):
class ArticleForm(forms.ModelForm):
class Meta:
model = Article
fields = ('headline', 'status')
field_classes = {
'status': StatusModelChoiceField,
}
I have two models, which are User and Record. Each has several fields.
from django.db import models
class User(models.Model):
openid = models.CharField(max_length=20)
nickname = models.CharField(max_length=20,null=True)
def __str__(self):
return self.nickname
class Record(models.Model):
expression = models.CharField(max_length=100)
user = models.ForeignKey(User)
time = models.DateTimeField(auto_now_add=True)
def __str__(self):
return self.expression
I register them in admin.py
from django.contrib import admin
from .models import User,Record
class RecordAdmin(admin.ModelAdmin):
list_display = ('expression','user','time')
class UserAdmin(admin.ModelAdmin):
empty_value_display = "çİş"
list_display = ('openid','nickname')
admin.site.register(User,UserAdmin)
admin.site.register(Record,RecordAdmin)
it works well in django admin initially. but one day, the fields of the Record model disppeared. It looks like
.
No field displays. It makes me unable to modify or add the values of the Record model. The other model User works well and all data exists in database. So why?
I think you just have to add on_delete=models.CASCADE in your ForeignKey Field. When you are using this kind of field, you have to specify the comportment when you make an update, a delete or anything else on this field.
So your script should be like this :
class Record(models.Model):
expression = models.CharField(max_length=100)
user = models.ForeignKey(User, on_delete=models.CASCADE)
time = models.DateTimeField(auto_now_add=True)
def __str__(self):
return self.expression
This is the result :
Edit :
You can also modify null=True by default=null
class User(models.Model):
openid = models.CharField(max_length=20)
nickname = models.CharField(max_length=20,default=null)
def __str__(self):
return self.nickname
I can't seem to work out how to hook into the queryset of a readonly field in Django admin. In particular I want to do this for an inline admin.
# models.py
class Value(models.Model):
name = models.TextField()
class AnotherModel(models.Model):
values = models.ManyToManyField(Value)
class Model(models.Model):
another_model = models.ForeignKey(AnotherModel)
# admin.py
class AnotherModelInline(admin.TabularInline):
# How do I order values by 'name'?
readonly_fields = ('values',)
class ModelAdmin(admin.ModelAdmin):
inlines = (AnotherModelInline,)
Note that this could probably be done by overriding the form and then setting the widget to disabled, but that's a bit of a hack and doesn't look nice (I don't want greyed out multi-select, but a comma-separated list of words.
You can set an ordering metadata in the Values model:
class Value(models.Model):
name = models.TextField()
class Meta:
ordering = ['name']
I have a model:
class Book(models.Model):
name = models.CharField(max_length=100)
alias = models.CharField(max_length=100)
description = models.TextField()
def __unicode__(self):
return self.name
and a ModelForm in forms.py:
class BookForm(ModelForm):
class Meta:
model = Book
So I'm trying to make something like this in my views:
def register_book(request):
if request.method == 'POST':
formul = BookForm(request.POST)
if formul.is_valid():
new_book=formul.save(commit=False)
new_book.alias='foo'
new_book.save()
return HttpResponseRedirect('/')
So, I'm saving from a html "form" the name & description, but the alias I need to save after I get the form. But isn't working.
A ModelForm will by default include and validate all fields of the model. If you always assign the alias value yourself in the view, then you don't need the alias field in the form and you can just exclude it:
class BookForm(ModelForm):
class Meta:
model = Book
fields = ('name', 'description')
# NOTE: you can also use excludes, but many consider it a bad practice
As always, Django docs can tell you more about it.
You're trying to save the model without an alias first. You need to allow blank values before you can do that. The recommended approach would be using blank:
alias = models.CharField(max_length=100, blank=True)
I have an application that makes use of Django's UserProfile to extend the built-in Django User model. Looks a bit like:
class UserProfile(models.Model):
user = models.ForeignKey(User, unique=True)
# Local Stuff
image_url_s = models.CharField(max_length=128, blank=True)
image_url_m = models.CharField(max_length=128, blank=True)
# Admin
class Admin: pass
I have added a new class to my model:
class Team(models.Model):
name = models.CharField(max_length=128)
manager = models.ForeignKey(User, related_name='manager')
members = models.ManyToManyField(User, blank=True)
And it is registered into the Admin:
class TeamAdmin(admin.ModelAdmin):
list_display = ('name', 'manager')
admin.site.register(Team, TeamAdmin)
Alas, in the admin inteface, when I go to select a manager from the drop-down box, or set team members via the multi-select field, they are ordered by the User numeric ID. For the life of me, I can not figure out how to get these sorted.
I have a similar class with:
class Meta:
ordering = ['name']
That works great! But I don't "own" the User class, and when I try this trick in UserAdmin:
class Meta:
ordering = ['username']
I get:
django.core.management.base.CommandError: One or more models did not validate:
events.userprofile: "ordering" refers to "username", a field that doesn't exist.
user.username doesn't work either. I could specify, like image_url_s if I wanted to . . . how can I tell the admin to sort my lists of users by username? Thanks!
This
class Meta:
ordering = ['username']
should be
ordering = ['user__username']
if it's in your UserProfile admin class. That'll stop the exception, but I don't think it helps you.
Ordering the User model as you describe is quite tricky, but see http://code.djangoproject.com/ticket/6089#comment:8 for a solution.
One way would be to define a custom form to use for your Team model in the admin, and override the manager field to use a queryset with the correct ordering:
from django import forms
class TeamForm(forms.ModelForm):
manager = forms.ModelChoiceField(queryset=User.objects.order_by('username'))
class Meta:
model = Team
class TeamAdmin(admin.ModelAdmin):
list_display = ('name', 'manager')
form = TeamForm
This might be dangerous for some reason, but this can be done in one line in your project's models.py file:
User._meta.ordering=["username"]
For me, the only working solution was to use Proxy Model. As stated in the documentation, you can create own proxy models for even built-in models and customize anything like in regular models:
class OrderedUser(User):
class Meta:
proxy = True
ordering = ["username"]
def __str__(self):
return '%s %s' % (self.first_name, self.last_name)
After that, in your model just change Foreign Key to:
user = models.OneToOneField(OrderedUser, unique=True)
or even more suitable
user = models.OneToOneField(OrderedUser, unique = True, parent_link = True)