I a having following setup in which my Model classes look like following
from django.db import models
from User.models import UserProfile
class Advertisement(models.Model):
owner = models.ForeignKey(UserProfile, related_name='advertisements', on_delete=models.CASCADE)
title = models.CharField(max_length=500, blank=False, default='')
location = models.CharField(max_length=300, blank=False, default='')
rent = models.IntegerField(blank=False)
status = models.CharField(max_length=100, blank=False)
no_of_bedrooms = models.IntegerField(blank=False)
no_of_bathrooms = models.IntegerField(blank=False)
posted_by = models.CharField(max_length=100, blank=True)
date_ad_posted = models.DateTimeField(null=True, blank=True)
contact = models.CharField(max_length=13, blank=False)
description = models.CharField(max_length=1000, blank=False)
security_deposit = models.IntegerField(default=0, blank=False)
def save(self, *args, **kwargs):
super(Advertisement, self).save(*args, **kwargs)
class File(models.Model):
Ad = models.ForeignKey(Advertisement, related_name='ad-photo', on_delete=models.CASCADE)
file = models.FileField(blank=False, null=False)
remark = models.CharField(max_length=20)
timestamp = models.DateTimeField(auto_now_add=True)
and my serializers look like following
class AdvertisementSerializer(serializers.HyperlinkedModelSerializer):
owner = serializers.ReadOnlyField(source='owner.email')
class Meta:
model = Advertisement
fields = ('id', 'owner', 'title', 'location', 'rent', 'status', 'no_of_bedrooms', 'no_of_bathrooms',
'date_ad_posted', 'posted_by', 'contact', 'description')
kwargs = {
'url': {'view_name': 'advertisement-detail'}
}
class FileSerializer(serializers.ModelSerializer):
class Meta:
model = File
fields = ('Ad', 'file', 'remark', 'timestamp')
i am registering my model in admin.py in following way
from django.contrib import admin
from .models import Advertisement, AdContract, File
class FileInline(admin.TabularInline):
model = File
class PropertyAdmin(admin.ModelAdmin):
inlines = [FileInline, ]
admin.site.register(Advertisement, File)
admin.site.register(AdContract)
but upon making migrations i am getting following error
i have tried a few solutions i got after googling but the error is still there. Any help is appreciated.
To register multiple models at once you need to pass them as iterable:
admin.site.register([Advertisement, File])
instead of
admin.site.register(Advertisement, File)
admin.site.register is used to register a model class with an admin class.
This is it's function signature:
AdminSite.register(model_or_iterable, admin_class=None, **options)
In you admin.py you're passing File model instead of the your custom admin class: admin.site.register(Advertisement, File)
Try this:
from django.contrib import admin
from .models import Advertisement, AdContract, File
class FileInline(admin.TabularInline):
model = File
class PropertyAdmin(admin.ModelAdmin):
inlines = [FileInline, ]
admin.site.register(File, FileInline)
admin.site.register(AdContract)
I encountered a similar problem. Like you, I was registering the Model, not the admin model.
Try This:
admin.site.register(File, FileInLine)
Related
so what i'm trying to do is add a new product to my data base using django's restapi
but a product may contain multiple categories which are related throught a third many to many
model and extra pictures which are ForeignKeyed to the product
this is my models.py
class Products(models.Model):
product_id = models.AutoField(primary_key=True)
name = models.CharField(max_length=35, null=False, unique=True)
description = models.CharField(max_length=255)
price = models.DecimalField(max_digits=10, decimal_places=2, default=0.)
main_image = models.FileField(upload_to='shop/images')
created_on = models.DateTimeField(blank=True, default=datetime.now)
class Category(models.Model):
category_id = models.AutoField(primary_key=True)
category = models.CharField(max_length=20, null=True, blank=True)
created_on = models.DateTimeField(blank=True, default=datetime.now)
class Meta:
db_table = 'Category'
class ProductsCategory(models.Model):
productscategory_id = models.AutoField(primary_key=True)
category = models.ForeignKey(to=Category, on_delete=models.CASCADE)
product = models.ForeignKey(to=Products, on_delete=models.CASCADE)
created_on = models.DateTimeField(blank=True, default=datetime.now)
class Meta:
db_table = 'ProductsCategory'
class Pictures(models.Model):
picture_id = models.AutoField(primary_key=True)
image = models.FileField(upload_to='shop/images')
product = models.ForeignKey(to=Products, on_delete=models.CASCADE)
created_on = models.DateTimeField(blank=True, default=datetime.now)
class Meta:
db_table = 'Pictures'
and heres what i've tryed:
#api_view(['POST'])
#permission_classes([IsModerator])
def create_product(request):
product_details = ProductsSerializer(request.POST, request.FILES)
pictures = PicturesSerializer(request.POST, request.FILES, many=True)
category_list = request.POST.getlist("category")
if product_details.is_valid() and validate_file_extension(request.FILES.get("main_image")):
try:
product = product_details.save()
if len(category_list) > 0:
for i in category_list:
category = Category.objects.get(category=i)
ProductsCategory.objects.create(category=category, product=product)
if pictures:
for image in request.FILES.getlist("image"):
if validate_file_extension(image):
Pictures.objects.create(image=image, product=product)
else:
error = {"error": "invalid extra pictures extension"}
return Response(error)
return Response((product_details.data, pictures.data, category_list), status=status.HTTP_201_CREATED)
except Exception as e:
return Response(e)
else:
return Response((product_details._errors, pictures._errors), status=status.HTTP_400_BAD_REQUEST)
and the output:
result
how am i supposed to use this content input?
or if you know a better for my main question of saving multiple models in the database and their relationships please leave an answer, thanks in advance
I suggest you change your models.py structure to this:
from django.db import models
class Category(models.Model):
category = models.CharField(max_length=20, null=True, blank=True)
created_on = models.DateTimeField(auto_now=True)
class Meta:
verbose_name_plural = "Categories"
class Picture(models.Model):
image = models.FileField(upload_to='shop/images')
product = models.ForeignKey(to=Products, on_delete=models.CASCADE)
created_on = models.DateTimeField(blank=True, default=datetime.now)
class Product(models.Model):
name = models.CharField(max_length=35, null=False, unique=True)
description = models.CharField(max_length=255)
price = models.DecimalField(max_digits=10, decimal_places=2, default=0.)
main_image = models.FileField(upload_to='shop/images')
more_images = models.ManyToManyField(Pictures, on_delete=models.CASCADE)
category = models.ForeignKey(Category, on_delete=models.CASCADE)
created_on = models.DateTimeField(auto_now=True)
Then in your serializer.py add:
from rest_framework import serializers
from .models import Category, Picture, Product
class CategorySerializer(serializers.ModelSerializer):
class Meta:
model = Category
fields = "__all__"
class PictureSerializer(serializers.ModelSerializer):
class Meta:
model = Picture
fields = "__all__"
class ProductSerializer(serializers.ModelSerializer):
class Meta:
model = Product
fields = "__all__"
In your views, I suggest you use ViewSets:
views.py
from .models import Category, Picture, Product
from .serializer import CategorySerializer, PictureSerializer, ProductSerializer
from rest_framework import viewsets
# import custom permissions if any
class CategoryViewSet(viewsets.ModelViewSet):
serializer_class = CategorySerializer
queryset = Category.objects.all()
class PictureViewSet(viewsets.ModelViewSet):
serializer_class = PictureSerializer
queryset = Picture.objects.all()
class ProductViewSet(viewsets.ModelViewSet):
serializer_class = ProductSerializer
queryset = Product.objects.all()
permission_classes = [IsModerator]
In your app's urls.py, add the router for your viewsets and it will create the paths for your views automatically:
from django.urls import path
from rest_framework.routers import DefaultRouter
router = DefaultRouter()
router.register(r'category', views.CategoryViewSet, basename='category')
router.register(r'picture', views.PictureViewSet, basename='picture')
router.register(r'product', views.ProductViewSet, basename='product')
urlpatterns = [
path('', include(router.urls)),
]
Changes log:
You do not need to add an ID field to every model, Django does that for you. Unless it's a particular case.
Your database tables are named after your model by default. So no need to specify that too.
I simplified your models' structure to make it cleaner. But it still does what you want it to do.
Django adds an s to create a plural name for every model. So you can name it in singular form unless needed to specify. eg. categories.
The viewsets will reduce your work by providing you with listing and retrieval actions.
To access a specific instance of eg. a product, you will just add a /<product id> after the product listing and creation endpoint.
Note: You have to add the id without the brackets.
I also suggest you go through this DRF tutorial. It will improve your understanding of Django REST framework.
I am trying to make a model that stores favorite shows for users, and I have been using viewsets. I have a users and shows viewset that work just like I expect them to, and I have another model that simply stores relationships between users and shows. When I add that as a viewset though, I get the id, and user, and I don't get a show.
Here are the results for the favorites:
[
{
"id":2,
"user":{
"username":"poduck",
"first_name":"",
"last_name":"",
"email":"poduck#gmail.com",
"image":null,
"url":"http://0.0.0.0:8000/api/users/poduck/?format=json"
}
}
]
There isn't even a show field. It's not like the data isn't there either. I have been able to use queries on the data with no trouble. I have access to both the show and the user from the favorite.
I thought that maybe that the fact that the show points to a user, and the favorite points to a user that there may be some circular conflict there, but beyond excluding the user field from the Show serializer, I don't know what to do to fix that, and yes, I did try excluding it from the Show serializer.
shows.models:
from django.db import models
from django.utils.translation import gettext_lazy as _
from localflavor.us.models import USStateField, USZipCodeField
from users.models import User
from phonenumber_field.modelfields import PhoneNumberField
# Create your models here.
class Show(models.Model):
# Information
title = models.CharField(_("Title"), blank=False, max_length=255)
location = models.CharField(_("Location Name"), blank=False, max_length=255)
image = models.ImageField(upload_to='show_images', blank=True)
description = models.TextField(_("Description"), blank=False)
start_date = models.DateField(_("Start Date"), blank=False)
end_date = models.DateField(_("End Date"), blank=False)
registration_start = models.TimeField(_("Registration Start Time"), blank=False)
registration_end = models.TimeField(_("Registration End Time"), blank=False)
start_time = models.TimeField(_("Spectator Start Time"), blank=False)
end_time = models.TimeField(_("Spectator End Time"))
address = models.CharField(_("Show Address"), blank=False, max_length=255)
city = models.CharField(_("City"), blank=False, max_length=255)
state = USStateField(_("State"), blank=False, max_length=2)
zip = USZipCodeField(_("Zip Code"), blank=False)
contact_name = models.CharField(_("Contact name"), blank=True, max_length=255)
contact_email = models.EmailField(_("Contact Email"), blank=True, max_length=255)
contact_phone = PhoneNumberField(_("Contact Phone"), blank=True)
website = models.URLField(_('Official website'), blank=True)
entry_fee = models.DecimalField(_('Entry fee'), default=0.00, blank=False, decimal_places=2, max_digits=10)
spectator_entry_fee = models.DecimalField(_('Spectator entry fee'), default=0.00, blank=False, decimal_places=2, max_digits=10)
trophies = models.BooleanField(_("Trophies or Ribbons Awarded"), default=False)
dash_plaques = models.BooleanField(_("Dash Plaques Given"), default=False)
dash_plaque_quantity = models.IntegerField(_("Quantity of dash plaques to be given"), null=True, blank=True)
door_prizes = models.BooleanField(_("Door Prizes"), default=False)
judging = models.BooleanField(_("Professional Judging"), default=False)
user = models.ForeignKey(User, on_delete=models.CASCADE)
created = models.DateTimeField(auto_now_add=True)
modified = models.DateTimeField(auto_now=True)
def __str__(self):
return f"{self.title}"
class Favorite(models.Model):
show = models.ForeignKey(Show, on_delete=models.CASCADE)
user = models.ForeignKey(User, on_delete=models.CASCADE)
def __str__(self):
return f"{self.show.title}"
shows.api.serializers:
from rest_framework import serializers
from shows.models import Show, Favorite
from users.api.serializers import UserSerializer
class ShowSerializer(serializers.ModelSerializer):
user = UserSerializer()
class Meta:
model = Show
fields = '__all__'
class FavoriteSerializer(serializers.ModelSerializer):
show = ShowSerializer(many=True, read_only=True)
user = UserSerializer()
class Meta:
model = Favorite
fields = '__all__'
shows.api.viewsets:
from car_show_helper.shows.models import Show
from .serializers import ShowSerializer, FavoriteSerializer
from rest_framework import viewsets
class ShowViewSet(viewsets.ModelViewSet):
queryset = Show.objects.all()
serializer_class = ShowSerializer
class FavoriteViewSet(viewsets.ModelViewSet):
queryset = Show.objects.all()
serializer_class = FavoriteSerializer
And finally the api_router:
from django.conf import settings
from rest_framework.routers import DefaultRouter, SimpleRouter
from car_show_helper.users.api.views import UserViewSet
from car_show_helper.shows.api.viewsets import ShowViewSet, FavoriteViewSet
if settings.DEBUG:
router = DefaultRouter()
else:
router = SimpleRouter()
router.register("users", UserViewSet)
router.register("shows", ShowViewSet, basename="shows")
router.register("favorites", FavoriteViewSet, basename="favorites")
app_name = "api"
urlpatterns = router.urls
Any help would be appreciated.
First, change queryset inside FavoriteViewSet
class FavoriteViewSet(viewsets.ModelViewSet):
queryset = Show.objects.all()
serializer_class = FavoriteSerializer
to
queryset = Favorite.objects.all()
Second, remove many=True from:
show = ShowSerializer(read_only=True, many=True)
I am new to Django and working on a project.
I have these models
class Test(models.Model):
name = models.CharField(max_length=255)
description = models.CharField(max_length=255, blank=True)
applicable_device = models.ManyToManyField(Device)
applicable_platform = models.ManyToManyField(Platform)
class Meta:
verbose_name = 'Test'
verbose_name_plural = 'Tests'
def __str__(self):
return self.name
class Event(models.Model):
name = models.CharField(max_length=255)
test = models.ManyToManyField(Test)
applicable_devices = models.ManyToManyField(Device)
class Meta:
verbose_name = 'Event'
verbose_name_plural = 'Events'
def __str__(self):
return self.name
class Property(models.Model):
name = models.CharField(max_length=255)
description = models.CharField(max_length=255)
applicable_events = models.ManyToManyField(Event)
applicable_devices = models.ManyToManyField(Device)
applicable_platform = models.ManyToManyField(Platform)
property_type = models.CharField(max_length=20, choices=TYPE_CHOICES)
expected_value = ArrayField(models.CharField(max_length=200), blank=True)
When I go to the Event section in the Django Admin Panel I am able to edit the events. But I want to be able to see a list of all the properties that apply to it underneath where I edit the event.
Is this possible?
I am not sure of what you have allready done in your admin .py. Did you modify your admin.py file and your form.py ?
form.py
from . import models
from django.forms.models import ModelForm
class EventForm(ModelForm):
class Meta:
model = models.Event
fields = ('id','name','test', 'applicable devices')
admin.py
from . import models
from . import forms
from django.contrib import admin
class EventAdmin(admin.ModelAdmin):
form = forms.EventForm
list_display = ['name','test', 'applicable devices']
# then to register your ModelAdmin
admin.site.register(Event, EventAdmin)
````
Currently I have a site, and I want the user to be able to view their liked articles. I want this to be included in the user api view that is already set up. I have tried the tracks = serializers.StringRelatedField(many=True)that is in the drf docs yet this didn't work. I have also tried the following:
from rest_framework import serializers
from articles.models import Article, CustomUser,FavoriteArticles
class ArticleSerializer(serializers.ModelSerializer):
class Meta:
model = Article
fields = ('title', 'content')
class UserSerializer(serializers.ModelSerializer):
class Meta:
model = CustomUser
fields = '__all__'
class FavoriteArticleSerializer(serializers.ModelSerializer):
class Meta:
model = FavoriteArticles
fields = '__all__'
class UserProfileSerializer(serializers.ModelSerializer):
fav_title = FavoriteArticleSerializer(read_only=False)
class Meta:
model = CustomUser
fields = 'username, git, email, fav_article, fav_title, homepage'
and my models:
from django.db import models
# users/models.py
from django.contrib.auth.models import AbstractUser
from django.db.models.signals import post_save
from django.dispatch import receiver
import uuid
class ProgrammingLanguage(models.Model):
programming_language = models.CharField(max_length=120, null=False, primary_key=True, default="React")
def __str__(self):
return self.programming_language
class Article(models.Model):
title = models.CharField(max_length=25, primary_key=True)
content = models.TextField()
usedfor = models.TextField()
url=models.CharField(max_length=200, null=True)
article_programming_language = models.ForeignKey(ProgrammingLanguage, on_delete=models.CASCADE, related_name="article_programming_language", default="react")
score = models.IntegerField(max_length=5, null=0)
def __str__(self):
return self.title
class CustomUser(AbstractUser):
username = models.CharField(max_length=50, unique=True, primary_key=True)
git = models.CharField(max_length=200, null=True)
homepage = models.CharField(max_length=250, null=True)
user_programming_language = models.ForeignKey(ProgrammingLanguage, on_delete=models.CASCADE, related_name="most_used_programming_language", default="react")
def __str__(self):
return str(self.username)
class FavoriteArticles(models.Model):
id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False)
fav_title = models.ForeignKey(Article, on_delete=models.CASCADE, related_name='fav_title')
reasons_liked = models.CharField(max_length=120, null=True)
user = models.ForeignKey(CustomUser, on_delete=models.CASCADE, related_name="user", default="tom" )
def __unicode__(self):
return '%s: %s' % (self.fav_title, self.reasons_liked)
I think you misunderstood what related_name means. It specifies how you would access a model from its reverse relationship. So I'd recommend you remove it from fields in your FavoriteArticles model and use the default Django already provides (in this case favoritearticles_set):
class FavoriteArticles(models.Model):
id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False)
fav_title = models.ForeignKey(Article, on_delete=models.CASCADE)
reasons_liked = models.CharField(max_length=120, null=True)
user = models.ForeignKey(CustomUser, on_delete=models.CASCADE, default="tom")
def __unicode__(self):
return '%s: %s' % (self.fav_title, self.reasons_liked)
This way, you can access favorite articles of a user via my_user.favoritearticles_set.all(). Then, you can change your UserSerializer to include a liked_articles field which is populated from the favoritearticles_set reverse relationship to a user's FavoriteArticles using a source attribute:
class UserSerializer(serializers.ModelSerializer):
liked_articles = FavoriteArticleSerializer(source='favoritearticles_set', many=True, read_only=True)
class Meta:
model = CustomUser
# explicitly include other fields as required
fields = ('username', 'git', 'user_programming_language', 'liked_articles')
Note that we've made this a read_only field, so it will only get populated if you perform a GET request.
I'm trying to serialize nested relations, but got an error during create model from request: 'MeasureUnit' object has no attribute 'unit'
What am I doing wrong? I'm just trying to create model MeasureItem, but got error in MeasureUnit somehow.
My models:
from django.db import models
from measure_unit.models import MeasureUnit
from main_user.models import MainUser
class Item(models.Model):
code = models.CharField(unique=True, max_length=15)
current_code = models.CharField(blank=True, null=True, max_length=15)
title = models.CharField(default='', max_length=100)
description = models.TextField(blank=True, null=True)
measure_units = models.ManyToManyField(MeasureUnit, through='MeasureItem', through_fields=('item', 'unit'), blank=True)
class Meta:
ordering = ('created_at',)
class MeasureItem(models.Model):
item = models.ForeignKey(Item, on_delete=models.CASCADE, blank=True, null=True)
unit = models.ForeignKey(MeasureUnit, on_delete=models.CASCADE, blank=True, null=True)
quantity = models.IntegerField(default=0)
created_at = models.DateTimeField(auto_now_add=True)
updated_at = models.DateTimeField(auto_now=True)
class Meta:
ordering = ('created_at',)
My serializer:
from rest_framework import serializers
from .models import Item, MeasureItem
class MeasureUnitSerializer(serializers.ModelSerializer):
class Meta:
model = MeasureItem
fields = ('id', 'unit')
class ItemAdminSerializer(serializers.ModelSerializer):
measure_units = MeasureUnitSerializer(many=True)
class Meta:
model = Item
fields = ('id', 'code', 'current_code', 'title', 'description', 'measure_units')
def create(self, validated_data):
units_data = validated_data.pop('measure_units')
item = Item.objects.create(**validated_data)
for unit_data in units_data:
try:
measure_unit = unit_data['unit']
MeasureItem.objects.create(unit=measure_unit, item=item)
except Exception as e:
print(str(e))
return item
return item
MeasureUnitSerializer is ModelSerializer for MeasureItem model, but you use it for MeasureUnit model in ItemAdminSerializer:
measure_units = MeasureUnitSerializer(many=True)
Since MeasureUnit doesn't have unit field you see error.
You could try to specify source argument of measure_units field:
measure_units = MeasureUnitSerializer(source='measureitem_set', many=True)