我想弄清楚为什么当我提交表单时,我的标签不会保存在我的数据库中。 django-rest-framework和Django-taggit也很新,我想我做错了什么:)
首先,在使用rest-framework创建API之前,我使用通用视图(CreateView和UpdateView)来注册/验证我的事件。它工作正常,但我决定进一步尝试构建一个API,因为我现在正在使用Angularjs。
现在我的模型事件已创建,但没有我的标签,我有一些错误。我放了一些代码,然后我将描述我的错误。
事件/ models.py
class Event(models.Model):
[...]
title = models.CharField(max_length=245, blank=False)
description = models.TextField(max_length=750, null=True, blank=True)
start = models.DateTimeField()
end = models.DateTimeField()
created_at = models.DateTimeField(editable=False)
updated_at = models.DateTimeField(editable=False)
slug = AutoSlugField(populate_from='title', unique=True, editable=False)
expert = models.BooleanField(choices=MODE_EXPERT, default=0)
home = models.BooleanField(choices=HOME, default=0)
nb_participant = models.PositiveSmallIntegerField(default=1)
price = models.PositiveSmallIntegerField(default=0)
cancelled = models.BooleanField(default=0)
user = models.ForeignKey(User, editable=False, related_name='author')
address = models.ForeignKey('Address', editable=False, related_name='events')
participants = models.ManyToManyField(User, related_name='participants', blank=True, editable=False,
through='Participants')
theme_category = models.ForeignKey('EventThemeCategory', unique=True, editable=False)
tags = TaggableManager(blank=True)
class Meta:
db_table = 'event'
def save(self, *args, **kwargs):
if not self.pk:
self.created_at = timezone.now()
self.updated_at = timezone.now()
super(Event, self).save(*args, **kwargs)
[...]
我正在使用serializers.HyperlinkedModelSerializer。
API / serializer.py
from taggit.models import Tag
class TagListSerializer(serializers.HyperlinkedModelSerializer):
class Meta:
model = Tag
fields = ('url', 'id', 'name')
class EventSerializer(serializers.HyperlinkedModelSerializer):
address = AddressSerializer()
user = UserSerializer(required=False)
tags = TagListSerializer(blank=True)
class Meta:
model = Event
fields = ('url', 'id', 'title', 'description', 'start', 'end', 'created_at', 'updated_at', 'slug', 'expert','home', 'nb_participant', 'price', 'address', 'user', 'theme_category', 'tags')
depth = 1
API /视图/ tags_views.py
from rest_framework import generics
from api.serializers import TagListSerializer
from taggit.models import Tag
class TagsListAPIView(generics.ListCreateAPIView):
queryset = Tag.objects.all()
model = Tag
serializer_class = TagListSerializer
class TagsDetailAPIView(generics.RetrieveUpdateDestroyAPIView):
queryset = Tag.objects.all()
model = Tag
serializer_class = TagListSerializer
API /视图/ events_views.py
class EventListAPIView(generics.ListCreateAPIView):
queryset = Event.objects.all()
model = Event
serializer_class = EventSerializer
paginate_by = 100
def pre_save(self, obj):
"""
Set the object's owner, based on the incoming request.
"""
obj.user = self.request.user
return super(EventListAPIView, self).pre_save(obj)
API / urls.py
url(r'^events/(?P<slug>[0-9a-zA-Z_-]+)/$', EventDetailAPIView.as_view(), name='event-detail'),
首先,当我打电话给 / api / events / name-of-my-event 时,API会向我发送带有我的标签的好资源。 GET方法运行正常。
我认为rest-framework遵循查询集。因此,如果我可以使用我的所有标签获取资源,为什么当我使用POST时,我的标签不会注册?
实际上我对POST方法有两个问题:
我想我必须在我的tags_views中制作一个自定义的get_queryset(self),但我不确定。 我会继续调查。如果有人已经这样做并有一些建议,我会非常API。感谢。
答案 0 :(得分:10)
遇到同样的问题。但我只是想通过TaggableManager直接保存标签列表(没有TagListSerializer和TagsListAPIView)。我的解决方案是:
class MyModel(models.Model):
...
tags = TaggableManager(blank=True)
def get_tags_display(self):
return self.tags.values_list('name', flat=True)
class MyModelSerializer(serializers.HyperlinkedModelSerializer):
...
tags = serializers.Field(source='get_tags_display') # more about: http://www.django-rest-framework.org/api-guide/fields#generic-fields
...
class MyModelViewSet(viewsets.ModelViewSet):
...
def post_save(self, *args, **kwargs):
if 'tags' in self.request.DATA:
self.object.tags.set(*self.request.DATA['tags']) # type(self.object.tags) == <taggit.managers._TaggableManager>
return super(MyModelViewSet, self).post_save(*args, **kwargs)
标签数据的发布数据将是[&#39; tagA&#39;,&#39; tagB&#39;,...],TaggableManager将处理它。 THX。
对于DRF&gt; 3.1,您只需要在ModelSerializer类中覆盖创建和更新:
class StringListField(serializers.ListField): # get from http://www.django-rest-framework.org/api-guide/fields/#listfield
child = serializers.CharField()
def to_representation(self, data):
return ' '.join(data.values_list('name', flat=True)) # you change the representation style here.
class MyModelSerializer(serializers.ModelSerializer):
tags = StringListField()
class Meta:
model = models.MyModel
def create(self, validated_data):
tags = validated_data.pop('tags')
instance = super(MyModelSerializer, self).create(validated_data)
instance.tags.set(*tags)
return instance
def update(self, instance, validated_data):
# looks same as create method
答案 1 :(得分:2)
http://blog.pedesen.de/2013/07/06/Using-django-rest-framework-with-tagged-items-django-taggit/
随着Django Rest Framework 3.0的发布,TagListSerializer的代码略有改变。 serializers.WritableField被折旧,有利于serializers.Field,用于创建自定义序列化器字段,例如this。以下是Django Rest Framework 3.0的更正代码。
class TagListSerializer(serializers.Field):
def to_internal_value(self, data):
if type(data) is not list:
raise ParseError("expected a list of data")
return data
def to_representation(self, obj):
if type(obj) is not list:
return [tag.name for tag in obj.all()]
return obj
我现在使用https://github.com/glemmaPaul/django-taggit-serializer库。
答案 2 :(得分:0)
我有一堆错误,但我找到了解决问题的方法。也许不是最好的,因为我对所有这些都很新,但现在它可以工作。
我会尝试描述我的所有错误,也许它会帮助某人。
首先我的angularjs发送一个json,它与查询集匹配
例如,下面我的模型事件,angularjs发送到API:
现在让我们从我的所有错误开始:
当我重新使用标签时,我有这个错误。不知道为什么,因为没有API的经典验证,一切都工作正常。
当我尝试在事件事件模型上使用新标记时,数据库中没有保存任何内容。 Angularjs收到了一个带有标签名称的响应,但id为null(请参阅原始问题的pitcure)
现在,我正在考虑注册我的标签,我需要创建一个事件实例。多亏了,我将能够像在文档中描述的那样添加我的标签。
apple.tags.add(“红色”,“绿色”,“水果”)
所以我决定在我的events_views.py中添加一个post_save:
class EventListAPIView(generics.ListCreateAPIView):
queryset = Event.objects.all()
model = Event
serializer_class = EventSerializer
paginate_by = 100
def pre_save(self, obj):
"""
Set the object's owner, based on the incoming request.
"""
obj.user = self.request.user
return super(EventListAPIView, self).pre_save(obj)
def post_save(self, obj, created=False):
print 'tags', self.request.DATA
obj.tags.add(self.request.DATA['tags'])
return super(EventListAPIView, self).post_save(obj)
但现在我说我有这个错误 AttributeError:'RelationsList'对象没有属性'add'。 实际上,很明显,因为obj.tags是一个对象列表,而不再是TaggableManager。
所以我决定重新开始并将标签发送到“标签”中,而不是另一个自定义属性“标记”,以避免使用TaggableManager进行混淆。
新错误:)我找到了这个django-taggit-unhashable-type-list
的解决方案def post_save(self, obj, created=False):
map(obj.tags.add, self.request.DATA['tagged'])
return super(EventListAPIView, self).post_save(obj)
现在,我发现我发送的标签格式不正确。我改变它(在angularjs一侧)发送一个像['jazz','rock']而不是[object,object]这样的数组。来自初学者的愚蠢错误。
现在魔术发生了,angularjs收到的反应很好:
抱歉我的英文。我知道它可能不是最好的解决方案,当我找到另一种解决方案时,我会尝试更新它。