I export products in excel format using xlwt.But foreign key fields are exported as id.
How can I export foreign key fields with their actual values?
I want to export brand_id and author fields with their actual values.
Here is my product model :
class Product(models.Model):
id = models.AutoField(primary_key=True)
author = models.ForeignKey(User,on_delete= models.CASCADE, verbose_name='Product Author', null=True)
brand_id = models.ForeignKey(Brand,on_delete=models.CASCADE, verbose_name="Brand Names")
name = models.CharField(max_length=255, verbose_name="Product Name")
barcode = models.CharField(max_length=255, verbose_name="Barcode")
unit = models.CharField(max_length=255,verbose_name="Product Unit")
def __str__(self):
return self.name
Here is my export view:
def export_excel(request):
response = HttpResponse(content_type='application/ms-excel')
response['Content-Disposition'] = "attachment; filename=Products-" + str(datetime.datetime.now().date())+".xls"
wb = xlwt.Workbook(encoding="utf-8")
ws = wb.add_sheet('Products')
row_num = 0
font_style = xlwt.XFStyle()
font_style.font.bold = True
columns = ["Product Id","Product Author","Product Brand","Product Name","Product Barcode","Product Unit"]
for col_num in range(len(columns)):
ws.write(row_num,col_num,columns[col_num],font_style)
font_style = xlwt.XFStyle()
rows = Product.objects.filter(author = request.user).values_list("id","author","brand_id","name","barcode","unit")
for row in rows:
row_num +=1
for col_num in range(len(row)):
ws.write(row_num,col_num,str(row[col_num]), font_style)
wb.save(response)
Thanks for your help. Kind regards
You could use django-import-export to export the data from a model to an excel file. This library also supports other data types in case you need them in the future.
As described in the documentation of django-import-export you can create a resource, which can then be used to both import and export data into a model. Start by creating a resource:
from import_export import resources
from import_export.fields import Field
from .models import Product
class ProductResource(resources.ModelResource):
author = Field() # for field with foreignkeys you need to add them here
brand_id = Field() # for field with foreignkeys you need to add them here
fields = ["id", "author", "brand_id", "name", "barcode", "unit"]
export_order = ["id", "author", "brand_id", "name", "barcode", "unit"]
def dehydrate_author(self, product: Product) -> str:
return f"{product.author.name}" # probably need to adapt the name of the field
def dehydrate_brand_id(self, product: Product) -> str:
return f"{product.brand_id.brand}" # probably need to adapt the name of the field
This is also documented here: django-import-export advanced manipulation
Now you can use this ModelResource to export your data to any supported format, in your case an Excel file. Import your resource you've created earlier all you need to do to return this in your view is the following:
from django.http import HttpResponse
from .resource import ProductRes
#... other code in your view
project_resource = ProjectResource()
dataset = project_resource.export()
response = HttpResponse(dataset.xlsx, ontent_type="application/vnd.openxmlformats-officedocument.spreadsheetml.sheet")
response["Content-Disposition"] = 'attachment; filename="projects_export.xlsx"'
Related
I am working with Django,i need to retrieve data from multiple database, which has different database name but with same table column structure.
So I use model.using(database).all()to get queryset and merge them into one.
I want to add extra databasename to indicate the data's database name, this is my code.
model:
class Sections(models.Model):
apply_id = models.PositiveIntegerField()
pathology_id = models.CharField(max_length=128)
user_id = models.PositiveIntegerField()
updated_at = models.DateTimeField(blank=True, null=True)
get_queryset:
def get_queryset(self):
slideset = []
database_config = ['database1', 'database2', 'database3']
for i, x in database_config:
slides = Sections.objects.using(x).all()
#### I want to add extra databasename column in every query object.
for x1 in slides:
x1.databasename = x
######
slideset.append(slides)
# merge QuerySet
query = functools.reduce(lambda a, b: a|b, slideset)
return query.order_by("updated_at").reverse()
the one return will be :
{
"apply_id": 1123,
"pathology_id": 1235,
"user_id": 1,
"updated_at": "202106011430",
# add extra databasename.
"databasename": "database1".
}
Because the column can't be modify, so I had to leave Sections model unchange, just add extra key-value to query, can someone help me on that?
thanks to #Abdul Aziz Barkat
use annotate
from django.db.models import CharField, Value
slides = Sections.objects.using(x).annotate(databasename=Value(databasename, output_field=CharField())
I am reading a json file from a website and if the record is not in my Customers queryset I want to create a new Customer for that record. What is happening is when I iterate over the queryset, Django is trying to create a new Customer even when it is already in the queryset.
Please see my code below:
from rest_framework import generics
from customer.models import Customers
from .serializers import CustomersSerializer
import json
import urllib.request
class CustomerAPIView(generics.ListAPIView):
j = urllib.request.urlopen("https://web.njit.edu/~jsd38/json/customer.json")
customer_data = json.load(j)
queryset1 = Customers.objects.values_list('CustomerId', flat=True)
for customer in customer_data:
if customer["#Id"] not in queryset1.iterator():
CustomerId = customer["#Id"]
Name = customer["Name"]
PhoneNumber = customer["PhoneNumber"]
EmailAddress = customer["EmailAddress"]
StreetLine = customer["Address"]["StreetLine1"]
City = customer["Address"]["City"]
StateCode = customer["Address"]["StateCode"]
PostalCode = customer["Address"]["PostalCode"]
cus = Customers()
cus.CustomerId = CustomerId
cus.Name = Name
cus.PhoneNumber = PhoneNumber
cus.EmailAddress = EmailAddress
cus.StreetLine = StreetLine
cus.City = City
cus.StateCode = StateCode
cus.PostalCode = PostalCode
cus.save()
queryset = Customers.objects.all()
serializer_class = CustomersSerializer
Your JSON is returning strings for the "#Id" key, I'm assuming your model Customers has integers as CustomerId field.
You should convert them to str or int:
if int(customer["#Id"]) not in queryset1:
...
I parsed excel and get row data in list. It is like
[empty:'', text:’1', text:’1’, text:’40’, text:'']
[empty:'', text:’2’, text:’5’, text:’23’, text:’●’]
[empty:'', text:’3’, text:’9’, text:’52’, text:'']
My excel(data.xlsx) is
so list output is ok.Now I wanna put this list to model(User).
User model in models.py is
class User(models.Model):
user_id = models.CharField(max_length=200)
name_id = models.CharField(max_length=200)
age = models.CharField(max_length=200)
man = models.BooleanField()
The last code of man = models.BooleanField() means man or woman,if ’●’ in excel,it means the user is man and true wanna be put in man variable.
Now views.py is
#coding:utf-8
from django.shortcuts import render
import xlrd
book = xlrd.open_workbook('../data/data.xlsx')
sheet = book.sheet_by_index(1)
for row_index in range(sheet.nrows):
row = sheet.row(row_index)
print(row)
# I had to add codes connect controller & model
I do not know how to send these list data to model and model has these data.Strictly speaking,I wanna write these list data to sqlite3.Is this code
import app.models
for x in row:
User.user_id = row[1]
User.name_id = row[2]
User.age = row[3]
User.man = row[4]
good way to write model?(or is it wrong way?)
Is there other more efficient way to do it?
Assuming you have the whole row and columns thing right, this should work:
for row in rows:
# if the man column is not empty, we assume it's a male:
is_man = row[4] != ""
user = User(user_id=row[1], name_id=row[2], age=row[3], man=is_man)
user.save()
Thanks for being here reading my question.
I am doing a webshop for a photography company and I need to read a csv file to update the products on the database. I am using django-adaptors to iterate the file and save the information, now is working good by the first time, but if run the command again the app creates new objects instead of overwrite the existing.
The problem is that I don't know what is the correct way to use the Update meta option. (You can see it in the documentation)
This is the code that I have right now:
from models import Type, Vendor, Product
from adaptor.model import CsvModel
from adaptor import fields as adaptor_fields
# Prepare functions here, but are not relevant information
class csv(CsvModel):
mfr_code = adaptor_fields.CharField()
main_photo_url = adaptor_fields.CharField()
name = adaptor_fields.CharField()
product_url = adaptor_fields.CharField()
vendor = adaptor_fields.CharField(prepare=get_or_create_vendor)
type = adaptor_fields.CharField(prepare=get_or_create_type)
subtype = adaptor_fields.IgnoredField()
description = adaptor_fields.CharField()
specs = adaptor_fields.CharField()
tags = adaptor_fields.CharField()
stock = adaptor_fields.IntegerField(prepare=get_stock_value)
price = adaptor_fields.IntegerField(prepare=format_usd)
class Meta:
delimiter = ','
dbModel = Product
update = {
'keys': ['D1 Basic Kit 250/500', 'D1 Studio Kit 250/250']
}
As you can see above I have the dictionary with the 'keys' value, but I don't know how to define the list of 'natural keys' and I am getting a KeyError exception when trying to run the command.
Can someone explain me what is the method to do it the right way?
Thanks for answering.
Cristian
'keys' should point out to a field name, not a field value. I guess 'D1 Basic Kit 250/500' or 'D1 Studio Kit 250/250' are names, then you should have something like:
class csv(CsvModel):
mfr_code = adaptor_fields.CharField()
main_photo_url = adaptor_fields.CharField()
name = adaptor_fields.CharField()
product_url = adaptor_fields.CharField()
vendor = adaptor_fields.CharField(prepare=get_or_create_vendor)
type = adaptor_fields.CharField(prepare=get_or_create_type)
subtype = adaptor_fields.IgnoredField()
description = adaptor_fields.CharField()
specs = adaptor_fields.CharField()
tags = adaptor_fields.CharField()
stock = adaptor_fields.IntegerField(prepare=get_stock_value)
price = adaptor_fields.IntegerField(prepare=format_usd)
class Meta:
delimiter = ','
dbModel = Product
update = {
'keys': ['name'] # or mfr_code, main_photo_url, etc..., price
}
I'm a little confused on how I would populate the following csv function with the information in my models.py for a given user. Can anyone point me in the right direction? Do I need to process the information in a separare py file, or can I do it in my views?
My view to download the info
def download(request):
response = HttpResponse(mimetype='text/csv')
response['Content-Disposition'] = 'attachment; filename=UserData.csv'
writer = csv.writer(response)
writer.writerow(['Date', 'HighBGL', 'LowBGL', 'Diet', 'Weight', 'Height', 'Etc'])
writer.writerow(['Info pertaining to date 1'])
writer.writerow(['info pertaining to date 2'])
return response
One of the models who's info i'm interesting in saving
class DailyVital(models.Model):
user = models.ForeignKey(User)
entered_at = models.DateTimeField()
high_BGL = models.IntegerField()
low_BGL = models.IntegerField()
height = models.IntegerField(blank = True, null = True)
weight = models.IntegerField(blank = True, null = True)
First you need to query your django model, something like: DailyVital.objects.all() or DailyVital.objects.filter(user=request.user)
Then you can either transform the objects manually into tuples, or you can use Django QuerySet's values_list method with a list of field names to return tuples instead of objects. Something like:
def download(request):
response = HttpResponse(mimetype='text/csv')
response['Content-Disposition'] = 'attachment; filename=UserData.csv'
writer = csv.writer(response)
writer.writerow(['Date', 'HighBGL', 'LowBGL', 'Weight', 'Height'])
query = DailyVital.objects.filter(user=request.user)
for row in query.values_list('entered_at', 'high_BGL', 'low_BGL', 'weight', 'height'):
writer.writerow(row)
return response
If you didn't need it in Django, you might also consider the sqlite3 command line program's -csv option.
An easy way to do this would be to convert your models into a list of lists.
First you need an object to list function:
def object2list(obj, attr_list):
" returns values (or None) for the object's attributes in attr_list"
return [getattr(obj, attr, None) for attr in attr_list]
Then you just pass that to the csvwriter with a list comprehension (given some list_of_objects that you've queried)
attr_list = ['date', 'high_BGL', 'low_BGL', 'diet', 'weight', 'height']
writer.writerows([object2list(obj, attr_list) for obj in list_of_objects])