You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

236 regels
6.8 KiB

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