Копирование только атрибутов, не относящихся к отношениям django/python

Я копирую объект модели в другой, но хочу, чтобы при этом не копировались отношения

Например, предположим, что у вас есть такая модель:

class Dish(models.Model):
    name = models.CharField(max_length=100)
    description = models.CharField(max_length=500)
    category = models.ForeignKey(Category, on_delete=models.CASCADE, default=1)

    def __str__(self):
        return self.name

Тогда я делаю:

            my_dish = Dish.objects.get(pk=dish.id)
            serializer = Dish_Serializer(my_dish)
            my_new_object = serializer.data

Я хочу, чтобы my_new_object включал только те атрибуты, которые не являются отношениями, в данном случае, имя и описание.

Как это сделать без прямого доступа к имени и описанию?

Предполагаю, что в вашем сериализаторе вы не хотите явно определять, какое поле сериализовать. В противном случае вы могли бы сделать следующее:

class Dish_Serializer(serializers.ModelSerializer):
    class Meta:
        model = Dish
        fields = ['id','name', 'description']

Вероятно, вы можете определить эти поля динамически:

        fields = [f.name for f in Dish._meta.concrete_fields]                                                                                         

или

        fields = [f.name for f in Dish._meta.fields if not isinstance(f,ForeignKey)]

В конечном итоге, вы хотите получить my_new_object в формате словаря, а по условию pk даст вам только один объект dish. Поэтому вместо этого вы можете сделать следующее :

my_new_object = Dish.objects.filter(pk=dish.id).values("name", "description")[0]

Это даст вам именно то, что вы хотите, просто объявите нужные вам поля в значениях как атрибут fields.

Вы можете удалить поле из вашего сериализатора, используя .fields.pop(field_name) метод, как в примере ниже Согласно тому, что я взял из Dynamically modifying fields [drf-docs]:

class DynamicFieldsModelSerializer(serializers.ModelSerializer):
   """
   A ModelSerializer that takes an additional `fields` argument that
   controls which fields should be displayed.
   """

   def __init__(self, *args, **kwargs):
       # Don't pass the 'fields' arg up to the superclass
       fields = kwargs.pop('fields', None)

       # Instantiate the superclass normally
       super().__init__(*args, **kwargs)

       if fields is not None:
           # Drop any fields that are not specified in the `fields` >argument.
           allowed = set(fields)
           existing = set(self.fields)
           for field_name in existing - allowed:
               self.fields.pop(field_name)

Также вы можете сделать это в вашем view, как показано ниже в фрагменте кода:

my_dish = Dish.objects.get(pk=dish.id)
serializer = Dish_Serializer(my_dish)
desired_fields = {'id', 'name', 'description'}
all_fields = set(serializer.fields)
for field in all_fields:
    if field not in desired_fields:
        serializer.fields.pop(field)
my_new_object = serializer.data
Вернуться на верх