Trim a dajango model attributes - django

I have a project in django, witch uses database first. The problem is the data format, because they have a lot of blank space. As I am using rest_framework, I would like to trim the objects before pass it to the serializer, because if I try to do something like
nombre = serializers.CharField(source='nombre.strip')
it says that I cannot use build-in functions. So, if anyone can help me I it would be great.

you need SerializerMethodField.
More here: https://www.django-rest-framework.org/api-guide/fields/#serializermethodfield
In your case:
class MySerializer(serializers.Serializer):
# any staff here
nombre = serializers.SerializerMethodField(read_only=True)
# other staff here
def get_nombre(self, obj):
return f'{obj.nombre}'.strip()

Related

Django REST Framework, display specific foreign key data objects

I'll get straight to my point
Here is my API output:
In pictures, I need to display objects that have primary_placeholder set to True.
I can't find answer on how to do it, I've tried searching in REST Api documentation but nothing seems to work, it always displays every single picture
serializers.py:
views.py
Models.py (Theese two that I'm currently working with)
Does anyone know what is the easiest and fastest way to do it? I have absolutely no idea and I've been trying figure it out for about 2 days now.
Database currently has no pictures with primary_placeholder set to True if anyone is confused
If want to show product pictures with primary_placeholder=True, we can use prefetch_related with Prefetch, please read this.
In your case above, i suggest:
views.py
from django.db import models
from your_app.models import Product, ProductPictures
class ProductList(APIView):
def get(self, request, format=None):
products = Product.objects.all().prefetch_related(
models.Prefetch(
"pictures",
queryset=ProductPictures.objects.filter(primary_placeholder=True)
)
)
serializer = ProductSerializer(products, many=True)
return Response(serializer.data)
Another suggest: In model ProductPictures field model, better if change the field name to product.
Good luck.
write a serializer method field and filter products in it.
class ProductSerializer(serializers.ModelSerializer):
filtered_pictures = serializers.MethodField()
class Meta:
model = Product
fields = ['brand','model','prize','filtered_pictures']
def get_filtered_pictures(self,obj):
if obj.pictures.exists():
queryset = obj.pictures.filter(primary_placeholder=True)
return ProductPictureSerializer(queryset, many=True).data
else:
return None

Creating Custom Display Fields in Django Admin (that don't exist in models.py)

I have two fields in models.py
numberOfUsers = IntegerField()
numberOfUserCredits = IntegerField()
In Django admin, instead of viewing two columns with
list_display = ['numberOfUsers', 'numberOfUserCredits']
I'd like to instead clean this up a bit and concatenate these two fields for simpler viewing:
str(numberOfUsers) + '/' + str(numberOfUserCredits)
How can I create a custom field like this in Django admin? I could create a new field in models.py that creates this field automatically on model save, but I am wondering if there is an easier way to go about doing this.
I found a similar question already asked, but the answer below was exactly what I was looking for.
You can add it to your ModelAdmin class something like following, also i would suggest using f strings instead of concatenation
class SomeAdmin(admin.ModelAdmin):
list_display = (..., 'user_field')
def user_field(self, obj):
return f'{obj.numberOfUsers}/{obj.numberOfUserCredits}'
user_field.short_description = 'userShort'

Altering the listview of the django admin portal

I've read, extensively, how to change the admin site of Django. I have it mostly figured out -- I think. However there are still a few things that elude me in my understanding. I am using the default registered admin urls; so they are not customized, only what is exposed automatically.
The easiest way to explain this is through imagery...
Here's what I have:
Here's what I want:
I'm fairly certain the changes should be fairly simple. But I don't know exactly which model to alter and template to adjust to get it to look how I want. The [number] -- [name] are fields in my model.
I have extended other pieces of the admin interface to get customized forms for editing particular elements -- by registering my model and customizing the field for it.
#admin.register(Course)
class CourseAdmin(admin.ModelAdmin):
form = CourseAdminForm
fieldsets = (
('Course Info:', {'fields': ('course_number', 'name', 'description', 'units')}),
('Load Info:', {'fields': ('lecture_hours', 'lab_hours', 'discussion_hours', 'work_hours')})
)
in my app/admin.py file.
I'm a bit confused because there technically isn't a model to register here. So I'm not 100% sure how to do this. Do I wrap each one of my modifications inside the CourseAdmin class as different classes/methods with registered URLs or is there some other way I need to be doing this?
You need edit your Course model class:
# models.py
class Course(models.Model):
# fields here
name = ...
# ...
# add a unicode method
# __str__ method if you are using python 3.x
def unicode(self):
return '%s - %s' % (self.pk, self.name)

Django forms.ChoiceField without validation of selected value

Django ChoiceField "Validates that the given value exists in the list of choices."
I want a ChoiceField (so I can input choices in the view) but I don't want Django to check if the choice is in the list of choices. It's complicated to explain why but this is what I need. How would this be achieved?
You could create a custom ChoiceField and override to skip validation:
class ChoiceFieldNoValidation(ChoiceField):
def validate(self, value):
pass
I'd like to know your use case, because I really can't think of any reason why you would need this.
Edit: to test, make a form:
class TestForm(forms.Form):
choice = ChoiceFieldNoValidation(choices=[('one', 'One'), ('two', 'Two')])
Provide "invalid" data, and see if the form is still valid:
form = TestForm({'choice': 'not-a-valid-choice'})
form.is_valid() # True
Best way to do this from the looks of it is create a forms.Charfield and use a forms.Select widget. Here is an example:
from django import forms
class PurchaserChoiceForm(forms.ModelForm):
floor = forms.CharField(required=False, widget=forms.Select(choices=[]))
class Meta:
model = PurchaserChoice
fields = ['model', ]
For some reason overwriting the validator alone did not do the trick for me.
As another option, you could write your own validator
from django.core.exceptions import ValidationError
def validate_all_choices(value):
# here have your custom logic
pass
and then in your form
class MyForm(forms.Form):
my_field = forms.ChoiceField(validators=[validate_all_choices])
Edit: another option could be defining the field as a CharField but then render it manually in the template as a select with your choices. This way, it can accept everything without needing a custom validator

Can I create a custom django modelchoicefield with a default queryset

I have an order model with a followed_by field:
class order(models.Model):
followed_by = models.ForeignKey(User, limit_choices_to={'groups__name': "Managers"})
I have several such models and forms for those models. By default the form displays a modelchoicefield listing users that are mangers. This is fine. But the display isn't nice: it gives the username, and I want first+last name. This would work nicely: Change Django ModelChoiceField to show users' full names rather than usernames
except that now in everyform I must declare the queryset to limit users to managers. Can I use the above method so that the custom modelchoicefield defaults to my filtered queryset. so then from a form I can just say:
followed_by = ManagerUserModelChoiceField()
Can you define the queryset on your ModelChoiceField child class?
class UserModelChoiceField(ModelChoiceField):
# Query that returns set of valid choices
queryset = User.objects.filter(group__name='Managers')
def label_from_instance(self, obj):
return obj.get_full_name()
Try passing in the queryset as an argument to the ManagerUserModelChoiceField class.
followed_by = ModelChoiceField(queryset = User.objects.filter(groups__name="Managers")
After my comment to #Enrico this thought occurred to me: I overwrote the "init" class on my custom field like so:
class UserModelChoiceField(forms.ModelChoiceField):
def __init__(self, *args, **kwargs):
super(UserModelChoiceField, self).__init__(queryset=User.objects.filter(groups__name="Managers"), *args, **kwargs)
I've seen stuff like this done in python before but I'm new to python so I'm not sure if this is a bad thing to do or if I should make this better somehow? I'd appreciate some feedback. That being said, it seems to be working correctly.