I am using django and I want to link two models. The first model is comment and the second model is image. I want to have multiple images for one comment and an image should be linked with only one comment.
Comment model has its fields and image model looks like this:
class Image(models.Model):
image = models.ImageField(upload_to=f'{hash(id)}/', null=True, blank=True)
def __str__(self):
return self.image.name
And this is the model that I used to link comment and image:
class CommentImage(models.Model):
comment = models.OneToOneField(Comment, models.CASCADE, null=True)
image = models.ForeignKey(Image, models.CASCADE, null=True)
class Meta:
ordering = ["-id"]
verbose_name = _("Image")
verbose_name_plural = _("Images")
def __str__(self):
return self.image.image.name
Here is the admin panel of django:
enter image description here
As you can see I could be able add only one image and there is no button as well to add multiple image. What should I change to be able to add multiple images?
I have tried using ManytoManyField and removing comment field from CommentImage but it did not work.
I think you are overcomplicating things. Why not just add a text field to your ImageComment:
class Image(models.Model):
def upload_to(self, filename):
return f'{hash(self)}/{filename}'
image = models.ImageField(upload_to=upload_to, null=True, blank=True)
comment = models.ForeignKey(
'ImageComment', on_delete=models.SET_NULL, null=True
)
def __str__(self):
return self.image.name
class CommentImage(models.Model):
comment = models.TextField()
Or in case an Image can have multiple ImageComments as well, use a ManyToManyField:
class Image(models.Model):
def upload_to(self, filename):
return f'{hash(self)}/{filename}'
image = models.ImageField(upload_to=upload_to, null=True, blank=True)
comments = models.ManyToManyField(
'ImageComment'
)
def __str__(self):
return self.image.name
class CommentImage(models.Model):
comment = models.TextField()
You can even add an InlineModelAdmin to make editing comments at the same location as the image possible:
from django.contrib import admin
class ImageCommentInline(admin.TabularInline):
model = ImageComment
#admin.site.register(Image)
class ImageAdmin(admin.ModelAdmin):
inlines = [
ImageCommentInline,
]
You can try using this via manytomanyfields:
class CommentImage(models.Model):
comment = models.ForeignKey(Comment, models.CASCADE)
image = models.ForeignKey(Image, models.CASCADE)
class Comment(models.Model):
# other fields here
images = models.ManyToManyField(Image, through='CommentImage', related_name='comments')
Related
i have two models ImageShoot and Image.
models.py:
class ImageShoot(models.Model):
name = models.CharField(max_length=100)
# image = models.URLField(name=None)
created_at = models.TimeField(auto_now_add=True)
def __str__(self):
return self.name
class Image(models.Model):
license_type = (
('Royalty-Free','Royalty-Free'),
('Rights-Managed','Rights-Managed')
)
image_number = models.CharField(default=random_image_number,max_length=12)
title = models.CharField(max_length = 100)
image = models.ImageField(upload_to = 'home/tboss/Desktop/image' , default = 'home/tboss/Desktop/image/logo.png')
category = models.ForeignKey('Category', null=True, blank=True, on_delete=models.CASCADE)
shoot = models.ForeignKey(ImageShoot, on_delete=models.CASCADE)
image_keyword = models.TextField(max_length=1000)
credit = models.CharField(max_length=150, null=True)
location = models.CharField(max_length=100, null=True)
license_type = models.CharField(max_length=20,choices=license_type, default='')
uploaded_at = models.TimeField(auto_now_add=True)
def __str__(self):
return self.title
admin.py:
class Imageset(admin.ModelAdmin):
associated_images = ImageShoot.image_set.all()
return associated_images
admin.site.register(Image)
admin.site.register(ImageShoot,Imageset)
what i am trying to achieve that when i create a image it should show on imageshoot also like when i create image in shoot 1. this image should show on shoot 1.
i am not sure which field should i add on imageshoot.
Use Reverse lookup
In Your views you can get all the images associated with the ImageShoot Obj using set.Try this in your shell after briefly going through the docs
associated_images = ImageShoot.image_set.all()
You can also use django orm methods for querysets like filter, count, etc.
Edit:
To display related images you can use this in admin:
#admin.register(ImageShoot)
class Imageset(admin.ModelAdmin):
list_display = ('name', 'created_at', 'associated_images')
def associated_images(self, obj):
return obj.image_set.all() #<----edit
associated_images.admin_order_field = 'imageshoot_image'
I'm trying to figure it out on how I can show only a specific set of dynamic fields in eav to a unique registered model in my apps.models. But I don't know how to this, I've also read the documents but I can't seem to find anything about it, or maybe I've come across it and didn't understand.
Now, what is happening is that, when I add an attribute in the django admin. It also adds the dynamic field in all the models registered in the eav.
What I want to do is that;
model 1 - dynamic_field1, dynamic_field2, dynamic_field3
model 2 - dynamic_field4, dynamic_field5, dynamic_field6
Btw, I'm currently using the django-eav2 the documentation is in the link. I've found my solution for my initial use case here link
Below codes are basically on how to register my models to the eav. Here is my sample models
class ClientName(models.Model):
name = models.CharField(max_length=250, null=True, blank=True)
description = models.TextField(null=True, blank=True)
is_active = models.BooleanField(default=True)
def __str__(self):
return str(self.name)
class CallDetails(models.Model):
client_name = models.ForeignKey(ClientName, on_delete=models.PROTECT, null=True, blank=True, db_index=True)
letter_info = models.TextField(null=True, blank=True)
def __str__(self):
return str(self.client_name)
class Meta:
verbose_name = 'Call Detail'
ordering = ['client_name']
eav.register(ClientName)
eav.register(CallDetails)
below is my admin.py
class CallDetailsAdminForm(BaseDynamicEntityForm):
model = CallDetails
class CallDetailsAdmin(BaseEntityAdmin):
form = CallDetailsAdminForm
admin.site.register(CallDetails, CallDetailsAdmin)
First of all, please forgive for my newbie questions. I did copy most of the code, and try to understand from Django documents.
Code as below:
models.py
class Order(models.Model):
ORDER_CHOICES = (
('import', 'IMPORT'),
('export', 'EXPORT')
)
storage = models.ForeignKey(Storage, on_delete=models.PROTECT)
order_type = models.CharField(max_length=6, choices=ORDER_CHOICES)
created_at = models.DateTimeField(auto_now_add=True)
updated_at = models.DateTimeField(auto_now_add=True)
class Item(models.Model):
def random_barcode():
return str(random.randint(10000000, 99999999))
type = models.ForeignKey(Type, on_delete=models.CASCADE)
order = models.ForeignKey(Order, on_delete=models.CASCADE, null=True)
brand = models.ForeignKey(Brand, on_delete=models.CASCADE)
item_name = models.CharField(max_length=50, help_text='Name of goods, max 50 characters')
barcode = models.CharField(max_length=8, default=random_barcode, unique=True)
production_date = models.DateField()
expired_date = models.DateField()
def __str__(self):
return self.item_type
forms.py
class ItemForm(ModelForm):
class Meta:
model = Item
exclude = ['order',]
fields = ['type', 'brand', 'item_name', 'production_date', 'expired_date']
ItemFormSet = inlineformset_factory(Order, Item, form=ItemForm, extra=1)
views.py
class CreatePO(CreateView):
model = Order
context_object_name = 'orders'
template_name = 'storages/create_po.html'
fields = ['order_type', 'storage',]
*#dun't know how to write below code....*
1st question: how to use inline formset to write the CreatePO view?
2nd question: I need my create PO template as below picture, how to add a "Quantity" field?
This kind of template need Javascript, right? Any alternative solution? I have no knowledge with javascript.
First of all, move the def random_barcode(): before def __str__(self): it looks so ugly formated code.
Then let's have a look in your pic, if you haven't proper experience with Javascript you can use Admin Views from Django, it's much more simple and supported by Django 2.1. Read more if you would like to give permission to everyone in a admin-views page https://docs.djangoproject.com/el/2.1/releases/2.1/#model-view-permission
So quantity will be just added inside Item class
quantity = models.PositiveSmallIntegerField(default=1)
Also for your form, in my opinion, you need modelform_factory, so I suggest to read this one https://docs.djangoproject.com/en/2.1/topics/forms/modelforms/#modelform-factory-function
I want to show an small preview image in Django Admin. I have made this hack, which works when the key is in the actual model itself.
class Product(models.Model):
prod_name = models.CharField ("Name", max_length=130)
image = models.URLField(max_length=340, blank=True, null=true)
def admin_image(self):
return '<center><img src="%s"/width="100px"></center>' %(self.image, self.image)
admin_image.allow_tags = True
However, I want it to show an image (read a URL) from a Foreign Key. I tried the following but no luck:
class Product_Option(models.Model):
colour = models.CharField (max_length=80, blank=True, null=True)
size = models.CharField (max_length=80, blank=True, null=True)
image_default = models.URLField(max_length=340, blank=True, null=True) # SHOW this image by
class Product(models.Model):
prod_name = models.CharField ("Name", max_length=130)
image = models.URLField(max_length=340, blank=True, null=true)
Default_Image = models.ForeignKey(Product_Option, blank=True, null= True)
Admin.py
class ProductAdmin(ImportExportModelAdmin):
resource_class = ProductResource
def admin_image(self, obj):
return '<center><img src="%s"/width="100px"></center>' %(obj.Stock_Image.image_default.url, obj.Stock_Image.image_default.url)
admin_image.allow_tags = True
list_display = ('prod_name','admin_image')
readonly_fields = ('admin_image',)
Your code is a little confusing, and you should be careful about putting HTML type code in your models. That being said, assuming you are trying to add thumbnails to your admin via foreignkey relations, this would be the easiest approach:
from django.utils.html import format_html
class ProductAdmin(ImportExportModelAdmin):
resource_class = ProductResource
list_display = ('prod_name', 'admin_image')
readonly_fields = ('admin_image',)
def admin_image(self, obj):
return format_html('<center><img src="{1}"/width="100px"></center>', obj.Default_Image.image_default, obj.Default_Image.image_default)
admin_image.allow_tags = True
Note: Notice the use of format_html(). Always use it in these cases to avoid vulnerabilities, as it escapes possibly malicious code.
Also, you were trying to use image_default.url, which only exists on an ImageField, not a URLField. I removed that as well in favor of just image_default.
I am working on multiple django sites and have been limited in making my project look nice for clients.
For example in the same app I have two models images and image galleries. It would be so much nicer to just have an admin entry for galleries and in that a table of images.
That's exactly what InlineModelAdmin is for. Taken a models.py like this:
class Gallery(models.Model):
name = models.CharField(max_length=100)
class Image(models.Model):
image = models.ImageField()
gallery = models.ForeignKey(Gallery)
You create an admin.py like this and only register an admin class for the Gallery:
class ImageInline(admin.TabularInline):
model = Image
class GalleryAdmin(admin.ModelAdmin):
inlines = [ImageInline]
admin.site.register(Gallery, GalleryAdmin)
This is my solution thanks to Dirk's help.
from django.db import models
PHOTO_PATH = 'media_gallery'
class Gallerys(models.Model):
title = models.CharField(max_length=30, help_text='Title of the image maximum 30 characters.')
slug = models.SlugField(unique_for_date='date', help_text='This is automatic, used in the URL.')
date = models.DateTimeField()
class Meta:
verbose_name_plural = "Image Galleries"
ordering = ('-date',)
def __unicode__(self):
return self.title
class Images(models.Model):
title = models.CharField(max_length=30, help_text='Title of the image maximum 30 characters.')
content = models.FileField(upload_to=PHOTO_PATH,blank=False, help_text='Ensure the image size is small and it\'s aspect ratio is 16:9.')
gallery = models.ForeignKey(Gallerys)
date = models.DateTimeField()
class Meta:
verbose_name_plural = "Images"
ordering = ('-date',)
def __unicode__(self):
return self.title
import models
from django.contrib import admin
class ImageInline(admin.TabularInline):
model = Images
class GallerysAdmin(admin.ModelAdmin):
list_display = ('title', 'date', 'slug')
inlines = [ImageInline]
admin.site.register(models.Gallerys,GallerysAdmin)