I am extending UserCreationForm and have added
username=forms.CharField(max_length=30, widget=forms.TextInput(attrs={'size':'80'}))
but the username field width does not change. How can I increase it?
Try specifying widgets in the form, as in the following example:
models.py
class Photo(models.Model):
caption = models.CharField(max_length=80)
admin.py
class PhotoAdmin(admin.ModelAdmin):
list_display = (u'preview', u'caption')
search_fields = (u'caption')
form = forms.PhotoAdminForm
forms.py
class PhotoAdminForm(forms.ModelForm):
class Meta:
widgets = { 'caption': forms.TextInput(attrs={'size': 80})}
As alternative, you can use the following:
forms.py
class PhotoAdminForm(forms.ModelForm):
caption = forms.CharField(widget=forms.TextInput(attrs={'size':80}))
Since 1.7 you can solve it like this:
admin.py
class PhotoAdmin(admin.ModelAdmin):
list_display = (u'preview', u'caption')
search_fields = (u'caption')
formfield_overrides = {
models.CharField: {'widget': TextInput(attrs={'size': '80'})}
}
Related
I am attempting to use drf-nested-routers to create a simple nested Django REST API given the following models:
# models.py
class Podcast(models.Model):
title = models.CharField(max_length=125)
class Episode(models.Model):
podcast = models.ForeignKey(Podcast, on_delete=models.CASCADE)
title = models.CharField(max_length=125)
Based on the readme domains/nameservers example, I have the following routers defined, expecting a URL structure like:
/podcasts[/{podcast_pk}[/episodes[/{episode_pk}]]]
# urls.py
router = routers.DefaultRouter()
router.register(r'podcasts', PodcastViewSet)
episode_router = routers.NestedDefaultRouter(
router, r'podcasts', lookup='podcast'
)
episode_router.register(
r'episodes', EpisodeViewSet, basename='podcast-episodes'
)
# serializers.py
class PodcastSerializer(HyperlinkedModelSerializer):
episodes = HyperlinkedIdentityField(
view_name='podcast-episodes-list',
lookup_url_kwarg='podcast_pk'
)
class Meta:
model = Podcast
fields = '__all__'
class EpisodeSerializer(NestedHyperlinkedModelSerializer):
parent_lookup_kwargs = {
'podcast_pk': 'podcast__pk',
}
class Meta:
model = Episode
fields = '__all__'
# exclude = ('url',) # works without reference to self
# views.py
class PodcastViewSet(viewsets.ModelViewSet):
queryset = Podcast.objects.all()
serializer_class = PodcastSerializer
class EpisodeViewSet(viewsets.ModelViewSet):
serializer_class = EpisodeSerializer
def get_queryset(self):
return Episode.objects.filter(
podcast=self.kwargs['podcast_pk'],
)
Accessing /podcasts/1/episodes/, when url is included, raises the following error:
Exception Type: ImproperlyConfigured at /podcasts/1/episodes/
Exception Value: Could not resolve URL for hyperlinked
relationship using view name "episode-detail". You may
have failed to include the related model in your API,
or incorrectly configured the `lookup_field` attribute
on this field.
Why does it not identify the correct view name, or is there something else obvious I am missing
In my case using 'id' instead of 'pk' is solved my problem.
parent_lookup_kwargs = {
'podcast_pk': 'podcast_id',
}
I am trying to implement the Django filter in my views class. But the problem is when I am using the filter_class then filter_fields & 'search_fields' is not working and vice versa.
My views.py code is :
from django_filters.rest_framework import DjangoFilterBackend
from rest_framework.filters import OrderingFilter, SearchFilter
class CustomLoggerAPIView(generics.ListAPIView):
authentication_classes = (authentication.TokenAuthentication,)
permission_classes = (permissions.IsAuthenticated,permissions.IsAdminUser,)
serializer_class = serializers.CustomLoggerSerializer
filter_class = filters.LogsFilter
queryset = models.CustomLogger.objects.all().order_by('-id')
filter_backends = (DjangoFilterBackend, SearchFilter,)
pagination_class = pagination.PostLimitOffsetPagination
filter_fields = ('user','user_sensor','sensor_type',)
search_fields = ('message')
and my filters.py class:
class LogsFilter(django_filters.rest_framework.FilterSet):
start_date = django_filters.DateTimeFilter(field_name='created_at', lookup_expr='gte')
end_date = django_filters.DateTimeFilter(field_name='created_at', lookup_expr='lte')
class Meta:
model = models.CustomLogger
fields = ('start_date', 'end_date')
I want both filters. I am not sure what I am doing wrong here. Any help will be highly appreciated. Thanks in advance
That is right, if you specify a filterser_class, then the filter_fields in the view are ignored. The solution is easy, just put those filter_fields in the fields of your LogsFilter Meta class:
class LogsFilter(django_filters.rest_framework.FilterSet):
start_date = django_filters.DateTimeFilter(field_name='created_at', lookup_expr='gte')
end_date = django_filters.DateTimeFilter(field_name='created_at', lookup_expr='lte')
class Meta:
model = models.CustomLogger
fields = ('start_date', 'end_date', 'user','user_sensor','sensor_type')
I use Django REST and I would know if it is possible to customise the display of attributes in the json response.
Exemple :
class MyModel(models.Model):
name = models.CharField(max_length=300)
and my serializer :
class MyModelSerializer(serializers.ModelSerializer):
class Meta:
model = MyModel
fields = ['name']
But instead to see {'name' : 'its value'}, I would see {'My customed model name' : 'its value'}.
Do you think that it's possible?
Thank you very much.
You can override the to_representation method of the serializer to change the name of the field:
class MyModelSerializer(serializers.ModelSerializer):
class Meta:
model = MyModel
fields = ['name']
def to_representation(self, instance):
ret = super().to_representation(instance)
# ret is an OrderedDict, so this will change the order of the result.
ret['custom_name'] = ret.pop('name')
return ret
def to_internal_value(self, data):
# if you want to write to the serializer using your custom name.
data['name'] = data.pop('custom_name')
return super().to_internal_value(data)
One way you could do it is using a SerializerMethodField (https://www.django-rest-framework.org/api-guide/fields/#serializermethodfield)
class MyModelSerializer(serializers.ModelSerializer):
my_customed_model_name = serializers.SerializerMethodField()
def get_my_customed_model_name(self, obj):
return obj.name
class Meta:
model = MyModel
Although if you want the field name to have spaces in it, this solution won't work for you.
You can do this in this way
class MyModelSerializer(serializers.ModelSerializer):
other_name = serializers.CharField(source='name')
class Meta:
model = MyModel
fields = ['other_name']
I want to add an extra field (column) that is not in the model. So, I created a model form in which the new extra field is defined.
admin.py
class WorkingHourForm(forms.ModelForm):
extra_field = forms.CharField(max_length=100)
class Meta:
model = WorkingHour
fields = ['day', 'period', 'time_range', 'extra_field']
class WorkingHourInline(admin.TabularInline):
model = WorkingHour
form = WorkingHourForm
This should work because it's pretty much a copy of an example in the documentation.
However, this raises the error: Unable to lookup 'extra_field' on WorkingHour or WorkingHourInline
What did I do wrong?
class WorkingHourForm(forms.ModelForm):
extra_field = forms.CharField(label='extra_field', max_length=100)
class Meta:
model = WorkingHour
fields = ['day', 'period', 'time_range', 'extra_field']
class WorkingHourInline(admin.TabularInline):
model = WorkingHour
form = WorkingHourForm
Adding label='extra_field' solved this for me in a similar use of tabularinline.. I think the django admin example works as is but when used in conjunction with the admin.TabularInline, it does not. Hope that helps.
remove extra_field from fields = ['day', 'period', 'time_range', 'extra_field']. If you do like that django will tries to get value for the extra_field from model. so, it will raises an error.
After modification, Above code will look like
class WorkingHourForm(forms.ModelForm):
extra_field = forms.CharField(max_length=100)
class Meta:
model = WorkingHour
fields = ['day', 'period', 'time_range']
class WorkingHourInline(admin.TabularInline):
model = WorkingHour
form = WorkingHourForm
Try adding this in your form's Meta:
labels = {"extra_field": "blah"}
I have a model and serializer like this:
models.py
class CalendarEvent(BaseMixin):
title = models.TextField(blank=True, null=True)
class CalendarEventReminder(BaseMixin):
event = models.ForeignKey(CalendarEvent, related_name = 'reminders')
minutes = models.CharField()
class Meta:
managed = False
db_table = 'calendar_event_reminder'
def __str__(self):
return self.minutes
serializer.py
class CalendarEventSerializer(serializers.ModelSerializer):
reminders = serializers.StringRelatedField(many=True)
class Meta:
model = CalendarEvent
fields = ('title', 'reminders')
In my view, I do the following:
def test(request):
#...
event = CalendarEvent.objects.filter(id__in = [930, 935])
serializer = CalendarEventSerializer(event, many = True)
print (serializer.data)
#...
When I open the Debug Toolbar, I see that the database hits reminders table twice for each of the calendar events.
The question is, how this behavior could be optimized.
The most straight-forward way would be prefetching the CalendarEventReminders of the CalendarEvents in your view:
# views.py
def get(request):
event = CalendarEvent.objects.filter(id__in = [930, 935]) \
.prefetch_related('reminders')
# ...
This will prefetch all CalendarEventReminders while getting the CalendarEvents.
Note that this will not trigger a sql join like select_related() would do. We can't use select_related() in this case because we're following the relation backwards. :)
Check out the Django Docs regarding prefetch_related.