I'm building an inventory list that includes the fields listed below in my Django model. I have a folder full of images that the name of the images correspond to the the Item Number. For install, the item number may be 4119, then the image file name will be 4119.jpg.
I would like to write a script that iterated over the items in the database and uploads the corresponding image. Any thoughts on where to start are greatly appreciated.
from django.db import models
def directory_path(instance, filename):
return '{0}/{1}/{2}'.format(supplier.name, pricelist.item_number, filename)
class Supplier(models.Model):
name = models.CharField(max_length=80)
def __str__(self):
return self.name
class PriceList(models.Model):
supplier = models.ForeignKey('Supplier', on_delete=models.CASCADE)
item_number = models.CharField(max_length=80)
description = models.CharField(max_length=120)
case_quantity = models.CharField(max_length=80)
piece_list_amount = models.CharField(max_length=80)
partner_list_amount = models.CharField(max_length=80)
upload = models.ImageField(upload_to=directory_path)
def __str__(self):
return self.item_number
You can look at my code and implement exactly what you need ... I hope this will be helpful for you:
import os
from Project.settings import BASE_DIR
from apps.showcase.models import Product
from django.core.files import File
obj_id_to_img_filename_mapping = (
(175, 'full_ef58c1a5af252d4459055481b1bbfa76.jpg'),
(176, 'full_2111856a6a092a3c65639aff56070aef.jpg'),
(177, 'full_b8154e9b348561ee295c2d1651ecca3c.gif'),
# ...
)
def update_product_images():
print('Starting upload products images...\n')
for product_id, file_name in obj_id_to_img_filename_mapping:
if file_name:
product = Product.objects.get(pk=product_id)
absolute_filename = os.path.join(BASE_DIR, 'apps/showcase/static/showcase/images/initial_data/product', file_name)
local_file = open(absolute_filename, 'r')
django_file = File(local_file)
product.image.save(file_name, django_file, save=True)
print(absolute_filename + '\n')
Related
So i need to post on page price-row like: name: medicalservice --> contains this prices --->
1# --- name --- price --- quantity
2# --- 2name --- 2price --- 2quantity
And i want to post them in one page
i need to take price rows exactly declared for this medical service
I cant get the idia how to get it done through admin panel (i dont know how to insert quantity value quantity into it)
I created an intermidiate model (services_count) but i think its not best idea :0
from django.db import models
from tinymce import models as tiny_models
from django.urls import reverse
class Medservices(models.Model):
public = 'pub'
private = 'priv'
status_post = [(public,'public'),(private,'private')]
position = models.IntegerField(default=1, verbose_name="Позиція")
status = models.CharField(max_length=10,default=public,choices=status_post, verbose_name="Статус показу")
photo = models.ImageField(verbose_name='Фото послуги або акції', upload_to='services_images', max_length=None)
date_start = models.DateField(verbose_name='Дата початку', auto_now=False, auto_now_add=False)
date_expire = models.DateField(verbose_name='Дата початку', auto_now=False, auto_now_add=False)
title = models.CharField(verbose_name='Назва послуги або акції', max_length=300)
text = text = tiny_models.HTMLField()
slug = models.SlugField(max_length=255,unique=True,verbose_name="URL",db_index=True)
def __str__(self):
return f"{self.price.all} - to {self.status}"
def get_absolute_url(self):
return reverse('service_page', kwargs={'post_slug': self.slug})
class services_count(models.Model):
quantity = models.IntegerField(verbose_name='Кількість цієї послуги у сервісі')
service = models.ForeignKey("medservices.Medservices", verbose_name='Послуга або акція', on_delete=models.CASCADE)
prices = models.ManyToManyField("price.Price", verbose_name='Ціни')
admin panel:
from django.contrib import admin
from medservices.models import Medservices, services_count
# Register your models here.
class MedservicesAdmin(admin.ModelAdmin):
list_filter = ('status','date_expire',)
list_display = ('title','date_start','date_expire')
prepopulated_fields = {"slug": ("title",)}
admin.site.register(Medservices, MedservicesAdmin)
class ServicesCountAdmin(admin.ModelAdmin):
list_display = ('quantity',)
admin.site.register(services_count, ServicesCountAdmin)
views.py :
from django.shortcuts import render
from . import models
# Create your views here.
def services_page(request):
services_list = models.Medservices.objects.filter(status__contains='pub').order_by('position').all()
services_list_dict = {
'service_rows':services_list,
'title': 'Послуги МЦ "Сторожик"'
}
return render(request, 'medservices/index.html', context=services_list_dict)
def service_page(request):
pass
Model Price from other app
from django.core import validators
from django.db import models
# Create your models here.
class Price(models.Model):
price_all_menu = 'Загальні'
doc_cons = 'Консультації'
analises = 'Аналізи'
UZD = 'УЗД'
Urology = 'Урологія'
Gynekology = 'Гінекологія'
price_menu = [(price_all_menu,'Загальні'),(doc_cons,'Консультації'),(analises,'Аналізи'),(UZD, 'УЗД'), (Urology, 'Урологія'), (Gynekology, 'Гінекологія')]
public = 'pub'
private = 'priv'
status_post = [(public,'public'),(private,'private')]
code = models.CharField(max_length=10)
name = models.CharField(max_length=300)
price = models.CharField(max_length=40)
position = models.IntegerField(default=1)
status = models.CharField(max_length=10,default=public,choices=status_post)
menu = models.CharField(max_length=100,default=price_all_menu,choices=price_menu)
def __str__(self):
return f"{self.code} -- {self.name} -- {self.price} - [{self.position}] - [{self.status}]"
I am using Django 3.2
I have a model like this:
Foo class
class Foo(models.Model):
name = models.CharField(max_length=124)
owner = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.CASCADE)
description = models.TextField()
bio = models.TextField()
attachment = models.FileField()
photo = models.ImageField()
recorded_date = models.DateField()
time_of_day = models.TimeField()
timestamp = models.DateTimeField()
duration = models.DurationField()
website = models.URLField()
pseudo_array = models.CharField(max_length=256)
pseudo_tags = models.CharField(max_length=128)
Snippet of Unit test
import glob
import os
import json
from datetime import datetime, timedelta
from django.utils.timezone import make_aware
from model_bakery import baker
from django.test import TestCase
from django.core.exceptions import ValidationError
from django.core.files.base import ContentFile
image_mock =ContentFile(b"R0lGODlhAQABAIAAAP///wAAACH5BAEAAAAALAAAAAABAAEAAAICRAEAOw==", name='photo.png')
file_mock = ContentFile("Some random text", name='archive.txt')
class TestModels(TestCase):
def setUp(self):
current_timestamp = datetime.now(timezone.utc)
self.foo = Foo.objects.create( name='Accepted Object',bio='For accepted testing',
owner=self.pattysmith,
description='Object for accepted testing',
attachment = file_mock,
photo = image_mock,
recorded_date = datetime.strptime('20200101','%Y%m%d'),
time_of_day = datetime.strptime('10:00','%H:%M'),
timestamp = make_aware(timezone.now().strptime('20200101 10:00','%Y%m%d %H:%M')),
duration = timedelta(days=20, hours=10),
website = 'https://www.accepted.com',
moderation_status=1,
pseudo_tags='approved,nice, accepted'
)
def tearDown(self):
Foo.objects.all().delete()
User.objects.all().delete()
for f in glob.glob("*.png"):
os.remove(f)
for f in glob.glob("*.txt"):
os.remove(f)
def test_change_moderated_char_field(self):
self.foo.name='My new name'
self.foo.save(update_fields=['name'])
# test for number of changed fields ...
When I run the test test_change_moderated_char_field I see that the file and image field names have changed - looks like Django is auto-generating the file names.
Here is what my console printout looks like:
moderated_field_current_field_value: 'My new name' != 'Accepted Object' for moderated field: name
moderated_field_current_field_value: /path/to/archive_Fo8NWLI.txt != /path/to/archive.txt for moderated field: attachment
moderated_field_current_field_value: /path/to/photo_mVEyGtI.png != /path/to/photo.png for moderated field: photo
######### changed_fields: ["name", "attachment", "photo"] #####
I am currently accessing the name of the file/image by accessing the path attribute on the field. How do I get the name of the file when it is actually uploaded (since some name mangling seems to be taking place?
I made a patient register form. I added two patient to database. And i wanna save each patient informations to text file. And i wanna make all txt file is uniqe name. So i am using this code for save txt file;
file_name must be each patient name, and i am having problem in this line... I didnt filter or pull data from model
def deneme(request):
dir_path = Path('/Users/emr/Desktop/ngsaglik/homeo/patient/templates/kayitlar')
file_name = str(Post.objects.get(???)) # i wanna pull each patient name as a txt file name
f = open (dir_path.joinpath(file_name),'w')
testfile = File(f)
kayitlar = Post.objects.all()
lines = []
for kayit in kayitlar:
lines.append(f'{kayit.soru1}\n{kayit.soru2}\n')
testfile.write(str(lines))
testfile.close
f.close
return HttpResponse()
my models.py
from django.db import models
from django.contrib.auth.models import User
from django.urls import reverse
#from datetime import datetime, date
class Post(models.Model):
name = models.CharField(verbose_name='Ad Soyad',max_length=10000, default="")
surname = models.CharField(verbose_name='Tarih', max_length=10000, default="")
soru3 = models.CharField(verbose_name='Doğum Tarihi', max_length=10000, default="")
soru4 = models.CharField(verbose_name='Doğum Yeri', max_length=10000, default="")
soru5 = models.CharField(verbose_name='Medeni Hali', max_length=10000, default="")
Iterate through all Post objects, and create a new file for each of them.
def deneme(request):
dir_path = Path('/Users/emr/Desktop/ngsaglik/homeo/patient/templates/kayitlar')
kayitlar = Post.objects.all()
for kayit in kayitlar:
file_name = str(kayit.name)
f = open (dir_path.joinpath(file_name),'w')
testfile = File(f)
lines = []
lines.append(f'{kayit.soru1}\n{kayit.soru2}\n')
testfile.write(str(lines))
testfile.close
f.close
return HttpResponse()
I'm relatively new to Django and not an advanced programmer, so please pardon my ignorance.
What is working:
I have a Django application that uses one main model which connects to two secondary models with foreign keys. The application can correctly create companies from template and from admin, and can correctly display the "niche" drop-down field using a foreign key to the Category model and can correctly display the images using a foreign key from the CompanyImage model.
What is not working:
The django-import-export library can correctly import an XLS document from front end and from admin, but ONLY if I disable the Category and CompanyImage model that are relying on foreign keys. The library does import correctly with the default user=models.ForeignKey(User) in my main Company model, but the foreign keys that connect to the secondary models are causing a foreign key error: IntegrityError at /import/ FOREIGN KEY constraint failed.
What I need
The XLS sheet I am importing does not import the fields that use a foreign key, so I would like to disable those fields to avoid the foreign key error. It would be nice to import a niche/category field, but I can do without.
What I've tried
I've spent two days trying to fix this problem.
I've tried reading the django-import-export documentation.
I've tried adding list_filter and exclude in class Meta for the Resource model.
I've read through Dealing with import of foreignKeys in django-import-export.
I've read through foreign key in django-import-export.
I would be very grateful someone can help steer me in the right direction. Thank you.
Models.py
from django.db import models
from django.contrib.auth.models import User
from phonenumber_field.modelfields import PhoneNumberField
#had to use pip install django-phone-verify==0.1.1
from django.utils import timezone
import uuid
from django.template.defaultfilters import slugify
class Category(models.Model):
kind = models.CharField(verbose_name='Business Type',max_length=100,blank=True,)
class Meta:
verbose_name_plural = "Categories"
def __str__(self):
return self.kind
class Company(models.Model):
#BASIC
title = models.CharField(verbose_name='company name',max_length=100,blank=True)
contact = models.CharField(verbose_name='director',max_length=100,blank=True)
phone_number = PhoneNumberField(blank=True)
email = models.EmailField(max_length=200,blank=True)
email_host = models.CharField(max_length=200,blank=True)
website = models.URLField(max_length=200,blank=True)
facebook = models.URLField(max_length=200,blank=True)
memo = models.TextField(blank=True)
niche = models.ForeignKey(Category, default=0000,on_delete=models.SET_DEFAULT)
#UPLOADS
profile_picture = models.ImageField(upload_to='prospects/images/', blank=True)
image = models.ImageField(upload_to='prospects/images/', blank=True)
file = models.FileField(upload_to='prospects/uploads', blank=True)
#TIME
date = models.DateField(default=timezone.now)
created = models.DateTimeField(auto_now_add=True)
updated = models.DateTimeField(auto_now=True)
datecompleted = models.DateTimeField(null=True, blank=True) #null for datetime object
#BOOLIANS
important = models.BooleanField(default=False)
cold = models.BooleanField(default=False, verbose_name='these are cold leads')
warm = models.BooleanField(default=False, verbose_name='these are warm leads')
hot = models.BooleanField(default=False, verbose_name='these are hot leads')
#USER
user = models.ForeignKey(User, on_delete=models.CASCADE,null=True,blank=True)
#TEST MODEL
decimal = models.DecimalField(max_digits=5, decimal_places=2, blank=True, default=00.00)
integer = models.IntegerField(blank=True, default=0000)
positive_int = models.PositiveIntegerField(null=True, blank=True, default=0000)
positive_small_int = models.PositiveSmallIntegerField(null=True, blank=True, default=0000)
#ADMIN CONSOLE
class Meta:
verbose_name_plural = "Companies"
def __str__(self):
if self.title == "":
print('empty string')
return "No Name"
elif type(self.title) == str:
return self.title
else:
return "No Name"
# this makes the title appear in admin console instead of object number
class CompanyImage(models.Model):
company = models.ForeignKey(Company, default=None, on_delete=models.CASCADE)
image = models.FileField(upload_to = 'prospects/images/',blank=True)
def __str__(self):
return self.company.title
resource.py
from import_export import resources
# from import_export import fields
from import_export.fields import Field
from import_export.fields import widgets
from .models import Company
from django.utils.encoding import force_str, smart_str
# The following widget is to fix an issue with import-export module where if i import any number from an xls file, it imports as a float with a trailing ,0
#could keep it a number and use trunc function to take away decimal but will make string
class DecimalWidget(widgets.NumberWidget):
def clean(self, value, row=None, *args, **kwargs):
print()
print(f"type of value is {type(value)}")
print()
if self.is_empty(value):
return ""
elif type(value) == float:
new_string = force_str(value)
seperator = '.'
new_string_witout_0 = new_string.split(seperator, 1)[0]
print()
print(f"the new type of value is {type(value)}")
print(f"the new value is {value}")
print()
return new_string_witout_0
else:
print("Aborting! it's not a float or empty string. will just return it as it is.")
return value
print()
print(f"type of value is {type(value)}")
print(f" the value returned is {value}")
print()
class CompanyResource(resources.ModelResource):
title = Field(attribute='title', column_name='name',widget=DecimalWidget())
contact = Field(attribute='contact', column_name='contact',widget=DecimalWidget())
phone_number = Field(attribute='phone_number', column_name='phone',widget=DecimalWidget())
# niche = Field(attribute='niche', column_name='niche',widget=DecimalWidget())
class Meta:
model = Company
exclude = ('niche')
fields = ('id','title','contact','phone_number', 'email','email_host','website','facebook')
export_order = ['id','title','contact','phone_number', 'email','email_host','website','facebook']
# fields = ( 'id', 'weight' )
admin.py
from django.contrib import admin
from import_export.admin import ImportExportModelAdmin
from import_export.fields import Field
from import_export import resources
# from import_export import resources
from .models import Company,Category, CompanyImage
from.resources import CompanyResource
class CompanyResource(resources.ModelResource):
class Meta:
model = Company
class CompanyImageAdmin(admin.StackedInline):
model = CompanyImage
class CompanyAdmin(ImportExportModelAdmin):
resource_class = CompanyResource
inlines = [CompanyImageAdmin]
# Register your models here.
admin.site.register(Category)
admin.site.register(Company,CompanyAdmin)
#admin.register(CompanyImage)
class CompanyImageAdmin(admin.ModelAdmin):
pass
views.py
def importcompanies(request):
if request.method == 'GET':
return render(request, 'prospects/import.html')
else:
file_format = request.POST['file-format']
company_resource = CompanyResource()
dataset = Dataset()
new_companies = request.FILES['myfile']
if file_format == 'CSV':
imported_data = dataset.load(new_companies.read().decode('utf-8'),format='csv')
result = company_resource.import_data(dataset, dry_run=True, raise_errors=True)
elif file_format == 'XLSX':
imported_data = dataset.load(new_companies.read(),format='xlsx')
result = company_resource.import_data(dataset, dry_run=True, raise_errors=True)
elif file_format == 'XLS':
imported_data = dataset.load(new_companies.read(),format='xls')
result = company_resource.import_data(dataset, dry_run=True, raise_errors=True)
if result.has_errors():
messages.error(request, 'Uh oh! Something went wrong...')
else:
# Import now
company_resource.import_data(dataset, dry_run=False)
messages.success(request, 'Your words were successfully imported')
return render(request, 'prospects/import.html')
You have CompanyResource defined in two places, so this could be the source of your problem. Remove the declaration from admin.py and see if that helps.
As you say, fields and exclude are used to define which model fields to import. fields is a whitelist, whilst exclude is a blacklist, so you shouldn't need both.
Set up a debugger (if you haven't already) and step through to find out what is going on (this can save days of effort).
If it is still not working, please update your answer and try to be specific about the nature of the issue (see how to ask).
Good day SO.
I want to make my folder name(s) to be renamed based on the ID/username of the uploader.
My setup is as follows:
class Account(AbstractBaseUser):
username= models.CharField(...) # As per our setup, user cant enter their own username but will be auto created based on a separate py file on my view during registration
...
class Type01Account(models.Model):
account = models.OneToOneField(Account, on_delete=models.CASCADE)
...
imgPath = ""
images= models.ImageField(upload_to=imgPath, null=False, blank=False)
How should I assign imgPath? Should I assign it on models or on view? If so, how should I save it?
The upload_to argument can be a function which takes the model instance and filename and returns the path to upload:
def img_path(instance, filename):
return f"{instance.account.username}/{filename}"
class Type01Account(models.Model):
account = models.OneToOneField(Account, on_delete=models.CASCADE)
...
imgPath = ""
images= models.ImageField(upload_to=img_path, null=False, blank=False)
Reference: FileField.upload_to
A class to handle the all upload_to for any field that contains a file
import os
from django.utils import timezone
class UploadTo:
def __init__(self, name):
self.name = name
def __call__(self, instance, filename):
base_filename, file_extension = self.generate_name(filename)
path = f'files/{instance.__class__.__name__}/{self.name}/{timezone.now().strftime("%y-%m-%d")}/{base_filename}{file_extension}'
# any custom action on path
return path
def generate_name(self, filename):
base_filename, file_extension = os.path.splitext(filename)
# any custom action on file name
return base_filename, file_extension
def deconstruct(self):
# you can add some static value from model like `self.name`
return 'path.to.this.UploadTo', [self.name], {}
# Usage example
class ExampleModel(models.Model):
# add here some static value to class `news_image`
news_image = models.ImageField(_("news image"), upload_to=UploadTo('news_image'), blank=True)