Ви не можете вибрати більше 25 тем Теми мають розпочинатися з літери або цифри, можуть містити дефіси (-) і не повинні перевищувати 35 символів.

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229
  1. from django.conf import settings
  2. from rest_framework import serializers
  3. from rest_framework.exceptions import ValidationError
  4. from rest_framework.validators import UniqueTogetherValidator
  5. from taggit.models import Tag
  6. from core.models import Image, Board
  7. from core.models import Pin
  8. from django_images.models import Thumbnail
  9. from users.serializers import UserSerializer
  10. class ThumbnailSerializer(serializers.HyperlinkedModelSerializer):
  11. class Meta:
  12. model = Thumbnail
  13. fields = (
  14. "image",
  15. "width",
  16. "height",
  17. )
  18. class ImageSerializer(serializers.ModelSerializer):
  19. class Meta:
  20. model = Image
  21. fields = (
  22. "id",
  23. "image",
  24. "width",
  25. "height",
  26. "standard",
  27. "thumbnail",
  28. "square",
  29. )
  30. extra_kwargs = {
  31. "width": {"read_only": True},
  32. "height": {"read_only": True},
  33. }
  34. standard = ThumbnailSerializer(read_only=True)
  35. thumbnail = ThumbnailSerializer(read_only=True)
  36. square = ThumbnailSerializer(read_only=True)
  37. def create(self, validated_data):
  38. image = super(ImageSerializer, self).create(validated_data)
  39. Thumbnail.objects.get_or_create_at_sizes(image, settings.IMAGE_SIZES.keys())
  40. return image
  41. class TagSerializer(serializers.SlugRelatedField):
  42. class Meta:
  43. model = Tag
  44. fields = ("name",)
  45. queryset = Tag.objects.all()
  46. def __init__(self, **kwargs):
  47. super(TagSerializer, self).__init__(
  48. slug_field="name",
  49. **kwargs
  50. )
  51. def to_internal_value(self, data):
  52. obj, _ = self.get_queryset().get_or_create(
  53. defaults={self.slug_field: data, "slug": data},
  54. **{self.slug_field: data}
  55. )
  56. return obj
  57. class PinSerializer(serializers.HyperlinkedModelSerializer):
  58. class Meta:
  59. model = Pin
  60. fields = (
  61. settings.DRF_URL_FIELD_NAME,
  62. "id",
  63. "submitter",
  64. "url",
  65. "origin",
  66. "description",
  67. "referer",
  68. "image",
  69. "image_by_id",
  70. "tags",
  71. )
  72. submitter = UserSerializer(read_only=True)
  73. tags = TagSerializer(
  74. many=True,
  75. source="tag_list",
  76. required=False,
  77. )
  78. image = ImageSerializer(required=False, read_only=True)
  79. image_by_id = serializers.PrimaryKeyRelatedField(
  80. queryset=Image.objects.all(),
  81. write_only=True,
  82. required=False,
  83. )
  84. def create(self, validated_data):
  85. if 'url' not in validated_data and\
  86. 'image_by_id' not in validated_data:
  87. raise ValidationError(
  88. detail={
  89. "url-or-image": "Either url or image_by_id is required."
  90. },
  91. )
  92. submitter = self.context['request'].user
  93. if 'url' in validated_data and validated_data['url']:
  94. url = validated_data['url']
  95. image = Image.objects.create_for_url(
  96. url,
  97. validated_data.get('referer', url),
  98. )
  99. else:
  100. image = validated_data.pop("image_by_id")
  101. tags = validated_data.pop('tag_list', [])
  102. pin = Pin.objects.create(submitter=submitter, image=image, **validated_data)
  103. if tags:
  104. pin.tags.set(*tags)
  105. return pin
  106. def update(self, instance, validated_data):
  107. tags = validated_data.pop('tag_list', None)
  108. if tags:
  109. instance.tags.set(*tags)
  110. # change for image-id or image is not allowed
  111. validated_data.pop('image_by_id', None)
  112. return super(PinSerializer, self).update(instance, validated_data)
  113. class PinIdListField(serializers.ListField):
  114. child = serializers.IntegerField(
  115. min_value=1
  116. )
  117. class BoardAutoCompleteSerializer(serializers.HyperlinkedModelSerializer):
  118. class Meta:
  119. model = Board
  120. fields = (
  121. settings.DRF_URL_FIELD_NAME,
  122. 'id',
  123. 'name',
  124. )
  125. class BoardSerializer(serializers.HyperlinkedModelSerializer):
  126. class Meta:
  127. model = Board
  128. fields = (
  129. settings.DRF_URL_FIELD_NAME,
  130. "id",
  131. "name",
  132. "pins",
  133. "pins_detail",
  134. "published",
  135. "submitter",
  136. "pins_to_add",
  137. "pins_to_remove",
  138. )
  139. read_only_fields = ('submitter', 'published')
  140. extra_kwargs = {
  141. 'submitter': {"view_name": "users:user-detail"},
  142. }
  143. submitter = UserSerializer(read_only=True)
  144. pins_detail = PinSerializer(source="pins", many=True, read_only=True)
  145. pins = serializers.HyperlinkedRelatedField(
  146. write_only=True,
  147. queryset=Pin.objects.all(),
  148. view_name="pin-detail",
  149. many=True,
  150. required=False,
  151. )
  152. pins_to_add = PinIdListField(
  153. max_length=10,
  154. write_only=True,
  155. required=False,
  156. allow_empty=False,
  157. help_text="only patch method works for this field",
  158. )
  159. pins_to_remove = PinIdListField(
  160. max_length=10,
  161. write_only=True,
  162. required=False,
  163. allow_empty=False,
  164. help_text="only patch method works for this field"
  165. )
  166. @staticmethod
  167. def _get_list(pins_id):
  168. return tuple(Pin.objects.filter(id__in=pins_id))
  169. def update(self, instance: Board, validated_data):
  170. pins_to_add = validated_data.pop("pins_to_add", [])
  171. pins_to_remove = validated_data.pop("pins_to_remove", [])
  172. if Board.objects.filter(
  173. submitter=instance.submitter,
  174. name=validated_data.get('name', None)
  175. ).exists():
  176. raise ValidationError(
  177. detail={'name': "Board with this name already exists"}
  178. )
  179. instance = super(BoardSerializer, self).update(instance, validated_data)
  180. changed = False
  181. if pins_to_add:
  182. changed = True
  183. for pin in self._get_list(pins_to_add):
  184. instance.pins.add(pin)
  185. if pins_to_remove:
  186. changed = True
  187. for pin in self._get_list(pins_to_remove):
  188. instance.pins.remove(pin)
  189. if changed:
  190. instance.save()
  191. return instance
  192. def create(self, validated_data):
  193. validated_data.pop('pins_to_remove', None)
  194. validated_data.pop('pins_to_remove', None)
  195. user = self.context['request'].user
  196. if Board.objects.filter(name=validated_data['name'], submitter=user).exists():
  197. raise ValidationError(
  198. detail={"name": "board with this name already exists."}
  199. )
  200. validated_data['submitter'] = user
  201. return super(BoardSerializer, self).create(validated_data)