Read only DateTimeField won't render in django admin - python

I have the following django model:
class Article(models.Model):
title = models.CharField(max_length = 200)
body = models.TextField()
created_date = models.DateTimeField(auto_now_add=True)
I also have the following django admin class:
class ArticleAdmin(admin.ModelAdmin):
fields = ['title', 'body']
readonly_fields = ['created_date']
list_display = ['title', 'body', 'created_date']
In the django admin app I can see the created_date field in my Article list:
But for the life of me I can't get the created_date field to render (as a read only field) when I open an Article:
I got the impression from the docs and from googling around that adding Article's created_date field to readonly_fields would allow this to happen even if I had set auto_now_add to True on a DateTimeField.
Am I barking up the wrong tree here?
I'm using django 1.4.2.

If you've specified fields, you need to add the field to fields.
however, when you specify ModelAdmin.fields or ModelAdmin.fieldsets the read-only fields must be present to be shown (they are ignored otherwise).
The auto_now magic has gotten me a few times.

Related

How can I show auto_now_add field in Django admin?

I have a model (as below) and in that, I've set auto_now_add=True for the DateTimeField
class Foo(models.Model):
timestamp = models.DateTimeField(auto_now_add=True)
From the doc,
As currently implemented, setting auto_now or auto_now_add to True will cause the field to have editable=False and blank=True set.
Q: How Can I show this auto_now_add field in Django Admin? (by default Django Admin doesn't show auto_now_add fields)
We can forcefully show the auto_now_add=True fields by adding the particular field(s) to the readonly_fields - (Django doc) list
class FooAdmin(admin.ModelAdmin):
readonly_fields = ('timestamp',)
admin.site.register(Foo, FooAdmin)

Badly affecting performance in populating ManyToMany field values in rest api (using django rest framework)

As I'm using django rest framework for building my product api.
Here is my model in models.py
class Tag(models.Model):
tag = models.CharField(max_length=10, unique=True)
class Product(models.Model):
product_name = models.CharField(max_length=100)
tag = models.ManyToManyField(Tag, blank=True, default=None, related_name='product_tag')
serializers.py :
class TagSerializer(serializers.ModelSerializer):
class Meta:
model = Tag
fields = '__all__'
class ProductSerializer(serializers.HyperlinkedModelSerializer):
tag = TagSerializer(many=True, read_only=True)
class Meta:
model = Product
fields = '__all__'
views.py :
class ProductViewSet(viewsets.ModelViewSet):
queryset = Product.objects.all()
serializer_class = ProductSerializer
I have given the url for ProductViewset, so when I hit the api it gives me the results as well but it takes too much time to load, it takes around 2 minutes to give me the response.
I'm having 2000 product objects in database which needs to be populated.
When I exclude the 'tag' field in "ProductSerializer", response comes very fast with all 2000 records.
Please suggest where is the loophole, why its affecting performance so much especially when I add this ManyToMany field.
I always use django-debug-toolbar to debug my queryset to find bottleneck/duplicate query in my project. Django orm always using lazy load to retrieve related fields from database.
You can change this default behavior of your queryset by eager load your many to many field using prefetch_related.
class ProductViewSet(viewsets.ModelViewSet):
queryset = Product.objects.prefetch_related('tag').all()
serializer_class = ProductSerializer
Reference: prefetch_related

Removing null=True from Django model CharField are values updated to empty string

I have a error being thrown when I navigate to my ListCreateAPIView base url:
url(r'^tests/$', TestList.as_view())
error:
coercing to Unicode: need string or buffer, NoneType found
which I believe to be related to the null=True in many of my CharField's throughout my various models. I ran into this error when attempting to add
Django Rest Framework Parsers to a ListAPIView like so:
class TestList(generics.ListCreateAPIView):
"""
"""
queryset = Tests.objects.all()
serializer_class = TestSerializer
filter_class = TestFilter
parser_classes = (FormParser, MultiPartParser)
class Courses(models.Model):
created = models.DateTimeField(default=timezone.now)
name = models.CharField(max_length=200, unique=True)
test = models.ForeignKey('Tests',
blank=True,
null=True,
on_delete=models.CASCADE)
class Tests(models.Model):
name = models.CharField(max_length=200)
it's either getting upset because of the null=True on the CharField's or perhaps because of the test foreign key I'm not totally sure? Would removing null=True and migrating solve this issue? Additionally, I should probably remove the null=True on CharField's anyway, would that be updated retroactively in the database?

DjangoRestFramework - Omit null fields when serializing objects

This is my Model:
class Post(models.Model):
user = models.ForeignKey(User)
post = models.CharField(max_length=400)
country = models.ForeignKey(Country, blank=True, null=True)
and this is my serializer:
class PostSerializer(serializers.ModelSerializer):
class Meta:
model = Post
fields = ('user', 'post', 'country',)
def create(self, validated_data):
post = Post(
user = User.objects.get(username='MyUser'),
post = validated_data['post'],
)
if validated_data.get('country', None):
post.country = validated_data['country']
return post
Is there any way for me to tell DRF that if the value of the field is null (because the 'country' field is optional and sometimes not provided) then to skip it and just serialize the other data? Or at least serialize it with a value of None?
I don't think I can use SerializerMethodField (http://www.django-rest-framework.org/api-guide/fields/#serializermethodfield) because the 'country' field is not a read-only field (I write too it too, if it is provided).
I basically want to omit the field (or at least make the value None) when serializing an object If the field is null.
As of DRF 3.2.4, so long as you add
blank=True
to the models field like so:
class Post(models.Model):
country = models.ForeignKey(Country, blank=True)
then DRF will treat the field as optional when serializing and deserializing it (Note though that if there is no null=True on the model field, then Django will raise an error if you try to save an object to the database without providing the field).
See the answer here for more information: DjangoRestFramework - correct way to add "required = false" to a ModelSerializer field?
If you are using pre-DRF 3.2.4, then you can override the field in the serializer and add required=False to it. See the documentation here for more information on specifying or overriding fields explicitily: http://www.django-rest-framework.org/api-guide/serializers/#specifying-fields-explicitly
So something like this (Note that I did not fully test the code below but it should be something along these lines):
class PostSerializer(serializers.ModelSerializer):
country = serializers.PrimaryKeyRelatedField(required=False)
class Meta:
model = Post
fields = ('user', 'post', 'country',)
This thread might be useful:
https://stackoverflow.com/a/28870066/4698253
It basically says that you can override the to_representation() function with a slight modification.
I would have put this in the comments but I don't have enough points yet :(
Use allow_null=True:
allow_null - If set to True, the field will accept values of None or the empty string for nullable relationships. Defaults to False.
serializers.py
class PostSerializer(serializers.ModelSerializer):
tracks = serializers.PrimaryKeyRelatedField(allow_blank=True)
class Meta:
model = Post

Making a field un-editable doesn't allow me to pre-populate fields

I'm writing a model called talk that has two fields title and slug. slug is a field which I do not wish the user to be able to edit and is pre-populated based on title. The model looks like this:
class talk(models.Model):
title = models.CharField(max_length = 255)
slug = models.SlugField(editable=False)
In my admin.py I have the following:
class talkAdmin(admin.ModelAdmin):
prepopulated_fields = {"slug": ("title",)}
Trying to access the model in the CMS gives me the error Exception Value: u"Key 'slug' not found in Form". If I remove editable=False everything works as desired except the user can edit the slug as they see fit.
I would like the slug field to appear in the admin but be greyed out so the user can see the slug, but can not change it.
You should use readonly_fields in the ModelAdmin class, not editable in the model.

Categories