I m trying to make a form on the basis of a model. Trouble is that when i create a category via django shell, let's say "Wedding" category, having id=1 and name = "weddings", when i display it in a dropdown(in html form) it shows as Categories object (1) and i would like it to be shown by the name, which is weddings.
As in the documentation i understand that i can attach labels when in the Meta form class but i don't fully understand how i can display dynamically all the category names instead of Categories object 1,2,3,4.
Models.py
class categories(model.Model):
id = models.AutoField(primary_key =True)
name = models.Charfield(max_length = 50)
class Event(models.Model):
id = models.AutoField(primary_key =True)
category = models.ForeignKey(Categories,on_delete=models.SET_NULL,null = True)
owner = models.Charfield(max_length = 50)
Forms.py
class EventForm(forms.ModelForm):
class Meta:
model = Event
fields = ['category','person','owner']
So the actual result when rendering the form is :
Category:(dropdown) - Categories object (1)
Desired result:
Category:(dropdown) - weddings
class categories(model.Model):
id = models.AutoField(primary_key =True)
name = models.Charfield(max_length = 50)
def __str__(self):
return self.name
class Event(models.Model):
id = models.AutoField(primary_key =True)
category = models.ForeignKey(Categories,on_delete=models.SET_NULL,null = True)
owner = models.Charfield(max_length = 50)
def __str__(self):
return self.owner
just add this little magic functions to your model classes.
Related
I want to post a movie into the collection's movie field( list of movies).
I define the model as
class Movie(models.Model):
# collection = models.ForeignKey(Collection, on_delete = models.CASCADE) #, related_name='reviews'
title = models.CharField(max_length=200)
description = models.CharField(max_length=200)
genres = models.CharField(max_length=200)
uuid = models.CharField(max_length=200)
def __str__(self):
return self.title
class Collection(models.Model):
title = models.CharField(max_length=200)
uuid = models.CharField(max_length=200, primary_key = True)
description = models.CharField(max_length=200)
movie = models.ForeignKey(Movie, on_delete = models.CASCADE)
def __str__(self):
return self.title
this is how i am using the viewset
class CollectionViewSet(viewsets.ModelViewSet):
queryset = models.Collection.objects.all()
serializer_class = serializers.CollectionSerializer
but i am not able to enter values for the movie field
enter image description here
also my serializer
class CollectionSerializer(serializers.ModelSerializer):
class Meta:
model = Collection
fields = '__all__'
By default, DRF will represent the relationship with a PrimaryKeyRelatedField, thus expecting a movie ID.
To achieve what you want (create an instance of movie with a collection), you need to overwrite the foreign key field in your serializer with your own Movie serializer.
class MovieSerializer(serializers.ModelSerializer):
class Meta:
model = Movie
fields = '__all__'
class CollectionSerializer(serializers.ModelSerializer):
movie = MovieSerializer()
class Meta:
model = Collection
fields = '__all__'
def create(self, validated_data):
movie = validated_data.pop('movie')
movie = Movie .objects.create(**movie )
collection = Collection.objects.create(movie=movie, **validated_data)
return collection
You need to overwrite the create method so when creating a Collection, you also create a movie.
However, I am not sure the foreign key is set in the right model in your model. (a movie belongs to many collection but not the other way around?) If that's not what you want, just reverse the logic for the serializer.
Edit:
Sending the following should work fine:
{ "uuid": "1001",
"title": "Action",
"description": "Action Movies",
"movie": { "title": "The Burkittsville 7",
"description": "The story of Rustin Parr.",
"genres": "Horror",
"uuid": "5e904"
}
}
The only problem as I mentionned earlier is in your model you defined the foreign key field in collection. So it expects one single movie instance and not a list, thus I took off the brackets you put around movie. Maybe you should consider setting the foreign key in the Movie model, or use a Many to many relationship.
#models.py
class Movie(models.Model):
# collection = models.ForeignKey(Collection, on_delete = models.CASCADE) #, related_name='reviews'
title = models.CharField(max_length=200)
description = models.CharField(max_length=200)
genres = models.CharField(max_length=200)
uuid = models.CharField(max_length=200)
def __str__(self):
return self.title
class Collection(models.Model):
title = models.CharField(max_length=200)
uuid = models.CharField(max_length=200, primary_key = True)
description = models.CharField(max_length=200)
movie = models.ManyToManyField(Movie, on_delete = models.CASCADE)
def __str__(self):
return self.title
serializers.py:
class MovieSerializer(serializers.ModelSerializer):
class Meta:
model = Movie
fields = '__all__'
class CollectionSerializer(serializers.ModelSerializer):
movie = MovieSerializer(read_only=True, many=True)
class Meta:
model = Collection
fields = '__all__'
hope this will give you better unserstand this will work for you
i have three models for a blog , shown blow:
class Author(models.Model):
name = models.CharField(max_length = 50)
class BlogPost(models.Model):
title = models.CharField(max_length = 250)
body = models.TextField()
author = models.ForeignKey(Author,on_delete = models.CASCADE)
date_created = models.DateTimeField(auto_now_add = True)
def copy():
pass
class Comment(models.Model):
blog_post = models.ForeignKey(BlogPost, on_delete = models.CASCADE)
text = models.TextField(max_length = 500)
i want to define a copy() method for BlogPost model that copies a BlogPost instance with copieng related comment instances . how can i do this?
You can iterate through the related comments of a given BlogPost instance and make a copy of each comment by nulling its pk attribute, then assign the blog_post foreign key to self and save.
def copy(self, post):
for comment in post.comment_set.all():
comment.pk = None
comment.blog_post = self
comment.save()
In my app i need to store invoices (Invoice) of known products (Product) to calculate points for each seller (User). I'm trying to create form to insert basic invoice data plus inline form with sold products info. To handle it i create model like this:
class Product(models.Model):
group = models.CharField(max_length = 200, blank = False)
mark = models.CharField(max_length = 200, blank = True)
points = models.IntegerField(blank = False)
class Invoice(models.Model):
price = models.FloatField(blank=False)
file = models.FileField(blank=False)
product = models.ManyToManyField(Product, through='Sold')
user = models.ForeignKey(User, on_delete=models.CASCADE)
date = models.DateField()
date_created = models.DateField(auto_now_add=True)
date_updated = models.DateField(auto_now=True)
class Sold(models.Model):
invoice = models.ForeignKey(Invoice, on_delete=models.CASCADE)
product = models.ForeignKey(Product, on_delete=models.CASCADE)
quantity = models.PositiveIntegerField(default=1)
I tried to manage it via django-admin and it work fine with admin.py:
class ProductTabular(admin.TabularInline):
model = Invoice.product.through
class InvoiceAdmin(admin.ModelAdmin):
inlines = [ProductTabular]
exclude = ('product', )
class Meta:
model = Invoice
admin.site.register(Invoice, InvoiceAdmin)
but i'm unable to create such form in own templates. Please, can you help me with views.py and template to get same result as for the django-admin?
I tried via invoce form with inlineformset_factory for the Sold model, but i can't figure out how to save it. Thanks for any help!
I've been trying to use a nested serializer with DRF but it won't display the related item in the output.
Here's my model.py :
class Categorie(models.Model):
nom = models.CharField(max_length=100)
def __unicode__(self):
return unicode(self.nom)
class Item(models.Model):
nom = models.CharField(max_length=100)
disponible_a_la_vente = models.BooleanField(default = True)
nombre = models.IntegerField()
prix = models.DecimalField(max_digits=5, decimal_places=2)
history = HistoricalRecords()
categorie = models.ForeignKey(Categorie, models.CASCADE)
class Meta:
verbose_name = "item"
verbose_name_plural = u"inventaire"
ordering = ['categorie', 'nom']
def __unicode__(self):
return u'{nom} - {nombre}'.format(nom = self.nom, nombre = self.nombre)
and my serializers.py
class ItemSerializer(serializers.ModelSerializer):
class Meta:
model = Item
fields = ('nom',)
class CategorieSerializer(serializers.ModelSerializer):
items = ItemSerializer(many=True)
class Meta:
model = Categorie
fields = ('nom', 'id', 'items')
The view i'm currently testing is very basic :
class InventaireDetail(generics.RetrieveAPIView):
queryset = Categorie.objects.all()
serializer_class = CategorieSerializer
but it gives the error:
AttributeError: Got AttributeError when attempting to get a value for
field items on serializer CategorieSerializer. The serializer
field might be named incorrectly and not match any attribute or key on
the Categorie instance. Original exception text was: 'Categorie'
object has no attribute 'items'.
I've been looking for a while now but i can't get it working even with the help of the doc.
Categorie.items does not exist. By default the reverse relation would get the name Categorie.item_set. You can fix that in two ways.
EITHER: add related_name to your foreign key.
class Item(models.Model):
categorie = models.ForeignKey(Categorie, models.CASCADE, related_name='items')
OR: another solution is to change the CategorieSerializer
class CategorieSerializer(serializers.ModelSerializer):
items = ItemSerializer(many = True, read_only=True, source='item_set')
I have a resources like these:
models.py
class Place(models.Model):
id = models.CharField(max_length = 256, primary_key = True)
name = models.CharField(max_length = 1024)
class Review(models.Model):
id = models.CharField(max_length = 256, primary_key = True)
p_id = models.ForeignKey(Place, related_name = 'place_review')
text = models.TextField()
api.py
class ReviewResource(ModelResource):
class Meta:
queryset = Review.objects.all()
resource_name = 'place_review'
class PlaceResource(ModelResource):
place_review = fields.OneToManyField(ReviewResource,
'place_review',
full=True)
class Meta:
queryset = Place.objects.all()
resource_name = 'place'
Using above model and resource, I want to limit number of reviews in list view of Place to 3, in detail/show view I want to show more reviews (possible different style, e.g. if review contains image, show it in detail view, hide it in list view)
I have tried to put attribute=lambda bundle: Review.objects.all()[:3], but whenever I don't have any reviews for place it fails with The model '' has an empty attribute ' at 0x7f0a180d0de8>' and doesn't allow a null value. message.
What can you suggest for this case, are there any workarounds for this problem?