I have following model in django:
class ProjectScheme(models.Model):
name = models.CharField(max_length=250, blank=False,null=False)
parent_scheme_id = models.ForeignKey(ProjectSchemeMaster, on_delete = models.CASCADE)
rule = models.TextField(blank=True)
created_on = models.DateTimeField(auto_now=False, auto_now_add=True)
created_by = models.IntegerField(blank=True,null=True)
updated_on = models.DateTimeField(auto_now=True, auto_now_add=False)
updated_by = models.IntegerField(blank=True,null=True)
def __str__(self):
return str(self.name)
And in admin.py
# Register your models here.
class ProjectSchemeAdmin(admin.ModelAdmin):
exclude = ('id',)
class Meta:
model = ProjectScheme
admin.site.register(ProjectScheme, ProjectSchemeAdmin)
But date fields: updated_on, created_on don't show up on admin form.
I also tried without ProjectSchemeAdmin class, and also:
class ProjectSchemeAdmin(admin.ModelAdmin):
pass
Also,
# list_display = [field.name for field in ProjectScheme._meta.fields if field.name != "id"]
list_display = ["id", "name","parent_scheme_id","rule","created_on", "created_by","updated_on","updated_by"]
But the same.
I need to get all the fields in admin form.
You need to add readonly_fields = ('created_on','updated_on') to display the date field.
# Register your models here.
class ProjectSchemeAdmin(admin.ModelAdmin):
list_display = ["name","parent_scheme_id","rule","created_on", "created_by","updated_on","updated_by"]
readonly_fields = ('created_on','updated_on')
class Meta:
model = ProjectScheme
admin.site.register(ProjectScheme, ProjectSchemeAdmin)
As mentioned in the docs:
As currently implemented, setting auto_now or auto_now_add to True will cause the field to have editable=False and blank=True set.
The value auto_now_add is True. So no matter what date value you enter via admin UI, it will ultimately be overriden, which means there is no reason to display the field. In this case, as you need to display the field anyway, adding the readonly_fields does the trick.
Hope this helps!
Related
I created a model on django for blog posts. Each post has two status choices: Publish or Draft. How can i change Publish to Published after the post is saved?
This is my code:
from django.db import models
from django.contrib.auth.models import User
Create your models here.
STATUS = (
(0,"Draft"),
(1,"Publish"),
)
class Post(models.Model):
title = models.CharField(max_length=200)
slug = models.SlugField(max_length=200, unique=True)
author = models.ForeignKey(User, on_delete=models.CASCADE, related_name='blog_posts')
updated_on = models.DateTimeField(auto_now=True)
content = models.TextField()
created_on = models.DateTimeField(auto_now_add=True)
status = models.Integer(choices=STATUS, default=0)
class Meta:
ordering = ['-created_on']
def __str__(self):
return self.title
from django.contrib import admin
from .models import *
Register your models here
class PostAdmin(admin.ModelAdmin):
list_display = ('title','slug','status','created_on',)
list_filter = ("status",)
search_fields = ('title', 'content')
prepopulated_fields = {'slug': ('title',)}
admin.site.register(Post,PostAdmin)
Your first way is to change your value "publish" just to "published". There's no point of having additional "publish" status. Whenever a post is saved the status field should change to "published". If anyways you need it to be there,then you can add another BooleanField like "is_published" to your model and check it in your save method so whenever the self.status was equal to "publish", make the field True. If you want to have additional checks for your model; then just write a function for your model class to change the value of "is_published".
so to change the value of "is_published" field in model;
in your Post class:
add
is_published = models.BooleanField(default=False)
then override your model save method:
def save(self, *args, **kwargs):
if self.status == 1:
self.is_published = True
super(Post, self).save(*args, **kwargs)
My project consists in items to be processed and then classified, so I have two main models: Item and Classification, as follows:
class Item(models.Model):
seq_prod = models.IntegerField(primary_key=True)
value = models.DecimalField(decimal_places=4, max_digits=20)
class Classification(models.Model):
item = models.ForeignKey(Item, db_index=True, on_delete=models.CASCADE)
rule = models.ForeignKey(Rule, null=True, blank=True, on_delete=models.CASCADE)
atribute = models.ForeignKey(Atribute, on_delete=models.CASCADE)
valid_clas = models.BooleanField(default=True)
dat_emission = models.DateField()
Models Rule and Atribute doesn't really matter for the problem.
As for the admin part we have:
class ClassificationInline(admin.TabularInline):
model = Classification
list_display = ('rule', 'atribute', 'valid_clas')
#admin.register(Item)
class ItemAdmin(admin.ModelAdmin):
list_display = ('desc', 'value',)
inlines = [
ClassificationInline,
]
Notice that in Classification model I haven't specified a primary key field, so Django creates an id column.
In the list_display at ClassificationInline we have only 'rule', 'atribute' and 'valid_clas', notice that neither 'id' nor 'dat_emission' are present. However, in the interface Django shows a 'dat_emission' column and doesn't show 'id' column.
Shouldn't only fields specified at the list_display be displayed? How can I remove 'dat_emission'?
Use exclude in your Inline class
class ClassificationInline(admin.TabularInline):
model = Classification
exclude = ('valid_clas', 'dat_emission', )
As i see in django source code, there is no list_display property for TabularInline class, Ńorrect me if I'm wrong.
As #weAreStarDust posted list_display doesn't work for Inlines, so I need to add dat_emission to the exclude. And besides that the following code was needed:
def get_readonly_fields(self, request, obj=None):
result = list(set(
[field.name for field in self.opts.local_fields] +
[field.name for field in self.opts.local_many_to_many]
))
result.remove('id')
result.remove('dat_emission')
return result
The final code for the Inline is:
class ClassificationInline(admin.TabularInline):
model = Classification
exclude = ('dat_emission', )
ordering = ('rule',)
can_delete = False
def has_add_permission(self, request):
return False
def get_readonly_fields(self, request, obj=None):
result = list(set(
[field.name for field in self.opts.local_fields] +
[field.name for field in self.opts.local_many_to_many]
))
result.remove('id')
result.remove('dat_emissao')
return result
I want to display a model field ie module_name as read only in django user profile edit page. The model Category has a manytomany relationship with Profile model.
Category
id category_name module_name
1 A X
2 B Y
profile_category
id profile_id category_id
1 2 1
So for eg. when I am on the admin page to editing a user id of 2 then I would like to display the module name X if category id 1 is assigned to the user id 2
models.py
class Category(models.Model):
category_name = models.CharField(max_length=150, blank=False, null=True, default="", unique=True)
module_name = models.TextField(blank=False, null=True)
class Profile(models.Model):
user = models.OneToOneField(User, on_delete=models.CASCADE, related_name ='profile')
phone_number = PhoneNumberField( blank=True, null=True)
organisation = models.CharField(max_length=30, blank=True)
category = models.ManyToManyField(Category)
admin.py
class ProfileInline(admin.StackedInline):
model = Profile
filter_horizontal = ('category',)
class CustomUserAdmin(UserAdmin):
inlines = (ProfileInline, )
list_select_related = ( 'profile', )
Please suggest if this is possible or not.
Any help/suggestion is highly appreciated. Thanks in advance.
Method 1
Use readonly_fields which is inherited from admin.BaseModelAdmin.
class ProfileInline(admin.StackedInline):
model = Profile
readonly_fields = ('module_names',)
def module_names(self, instance):
# Write a get-method for a list of module names in the class Profile
# return HTML string which will be display in the form
return format_html_join(
mark_safe('<br/>'),
'{}',
((line,) for line in instance.get_module_names()),
) or mark_safe("<span>The user belongs to no category</span>")
# short_description functions like a model field's verbose_name
module_names.short_description = "Module names"
Method 2
For older versions of admin site, you can hook the get_fieldsets method of admin.StackedInline. This method was posted here with a nice example.
Well, i have this model:
class Application(models.Model):
name = models.CharField("nom", unique=True, max_length=255)
sonarQube_URL = models.CharField("Url SonarQube", max_length=255,
blank=True, null=True)
def __unicode__(self):
return self.name
and this serializer:
class ApplicationSerializer(serializers.ModelSerializer):
nom = serializers.CharField(source='name', required=True, allow_blank=True)
url_sonarqube = serializers.CharField(source='sonarQube_URL', required=False)
flows = FlowSerializer(many=True, read_only=True)
class Meta:
model = Application
fields = ('id', 'nom', 'url_sonarqube', 'flows')
My view is simple:
class ApplicationViewSet(viewsets.ModelViewSet):
queryset = Application.objects.all()
serializer_class = ApplicationSerializer
I use this model of permissions in my settings.py:
REST_FRAMEWORK = {
'DEFAULT_PERMISSION_CLASSES': ('rest_framework.permissions.DjangoModelPermissions',),
'PAGE_SIZE': 10,
'TEST_REQUEST_DEFAULT_FORMAT': 'json',
'TEST_REQUEST_RENDERER_CLASSES': (
'rest_framework.renderers.MultiPartRenderer',
'rest_framework.renderers.JSONRenderer',
'rest_framework.renderers.TemplateHTMLRenderer'
)
}
When I use POST operation on DRF interface (in HTML Form), I filled all the fields of the application Item. As you can see, "required" parameter of "nom" is set to True. And, this is the problem: even if 'nom' is not empty, DRF says "this field is required!". So, I can't POST a new application item.
I don't understand why it not works... Where is the mistake?
The error you got is related to the Django Model(Application). It was failing in model level not in serializer level. Add null=True and blank=True to name field in Application model.
Try to keep your code in English, you can use Django's i18n to translate stuff, also use blank and null for your name field:
class Application(models.Model):
name = models.CharField(_('name'), max_length=255, blank=True, null=True)
sonarqube_url = models.CharField(_('SonarQube URL'), max_length=255, blank=True, null=True)
def __unicode__(self):
return self.name
class ApplicationSerializer(serializers.ModelSerializer):
class Meta:
model = Application
fields = ('id', 'name', 'sonarqube_url')
Let's save flows for later as you don't even have a model relation for them.
I have the following model structure:
class Project(models.Model):
author = models.ManyToManyField(Account)
name = models.CharField(max_length=40, default='NewBook')
class Account(AbstractBaseUser):
email = models.EmailField(unique=True)
username = models.CharField(max_length=40, unique=True)
first_name = models.CharField(max_length=40, blank=True)
last_name = models.CharField(max_length=40, blank=True)
tagline = models.CharField(max_length=140, blank=True)
is_admin = models.BooleanField(default=False)
created_at = models.DateTimeField(auto_now_add=True)
updated_at = models.DateTimeField(auto_now=True)
objects = AccountManager()
USERNAME_FIELD = 'email'
REQUIRED_FIELDS = ['username']
My view looks like this:
class ProjectViewSet(viewsets.ModelViewSet):
queryset = Project.objects.order_by('-name')
serializer_class = ProjectSerializer
def perform_create(self, serializer):
instance = serializer.save(author=self.request.user)
return super(ProjectViewSet, self).perform_create(serializer)
After calling the view function, a classifier gets created in the database. But after that, I get the following error:
TypeError: 'Account' object is not iterable
The error gets thrown in this line:
instance = serializer.save(author=self.request.user)
Anyone how can help me with this?
There are two problems here:
Showing nested relationships for M2M field:
If the field is used to represent a to-many relationship, you should add the many=True flag to the serializer field.
So you need to add many=True to AccountSerializer:
author = AccountSerializer(read_only=True, required=False, many=True)
A writable nested serializer:
By default nested serializers are read-only. If you want to support write-operations to a nested serializer field you'll need to create create() and/or update() methods in order to explicitly specify how the child relationships should be saved.
So if you look at the example and the documentation it seems that you need to implement create or update method.
You need to set many=True when dealing with multiple relation - either a m2m or a reversed FK:
author = AccountSerializer(read_only=True, required=False, many=True)
Since your Author field is many to many, you will need to override the create method on your serializer.
def create(self, validated_data):
author = validated_data.pop(author, None)
project = Project.objects.save(validated_data)
if author:
project.author.add(author)
You will also probably need to set the update method on the serializer, the behavior here can be tricky so make sure you test and make sure the behavior is what you expect.
Ok, my previous answer, though could be an issue, isn't the root cause of the actual crash.
When calling the serializer, you set:
instance = serializer.save(author=self.request.user)
However, author is a ManyToManyField which means you should call the serializer as:
instance = serializer.save(author=[self.request.user])
NB: you still require the many=True on the serializer's author field.
Please check...
your model.py
class Account(AbstractBaseUser):
email = models.EmailField(unique=True)
username = models.CharField(max_length=40, unique=True)
first_name = models.CharField(max_length=40, blank=True)
last_name = models.CharField(max_length=40, blank=True)
tagline = models.CharField(max_length=140, blank=True)
is_admin = models.BooleanField(default=False)
created_at = models.DateTimeField(auto_now_add=True)
updated_at = models.DateTimeField(auto_now=True)
objects = AccountManager()
USERNAME_FIELD = 'email'
REQUIRED_FIELDS = ['username']
class Project(models.Model):
author = models.ManyToManyField(Account)
name = models.CharField(max_length=40, default='NewBook')
your serializer.py
class ProjectSerializer(serializers.ModelSerializer):
author = AccountSerializer(read_only=True, required=False)
class Meta:
model = Project
fields = ('id', 'author', 'name')
read_only_fields = ('id')
def get_validation_exclusions(self, *args, **kwargs):
exclusions = super(ProjectSerializer, self).get_validation_exclusions()
return exclusions + ['author']
and finally your view.py is
class ProjectViewSet(viewsets.ModelViewSet):
queryset = Project.objects.order_by('-name')
serializer_class = ProjectSerializer
def perform_create(self, serializer):
instance = serializer.save(author=self.request.user)
return super(ProjectViewSet, self).perform_create(serializer)