I am using the django-import-export package. I need, everytime the user send a .csv table, to create a column in the .csv file and fill every row with the logged user. What I did is:
In my resources.py file:
class ProductListResource(resources.ModelResource):
class Meta:
model = ProductList
skip_unchanged = True
report_skipped = True
exclude = ('id',)
import_id_fields = ('sku',)
In my models.py file:
class ProductList(models.Model):
sku = models.CharField(primary_key=True, max_length=200)
client = models.ForeignKey(get_user_model(), default=1, on_delete=models.CASCADE)
name = models.CharField(max_length=256)
description = models.CharField(max_length=1000)
storage = models.CharField(max_length=256)
cost_price = models.CharField(max_length=256)
sell_price = models.CharField(max_length=256)
ncm = models.CharField(max_length=256)
inventory = models.IntegerField(null=True)
And finally in my views.py file:
def simple_upload(request):
if request.method == 'POST':
product_resource = ProductListResource()
product_resource.Meta.model.client = request.user.id
dataset = Dataset()
new_product_table = request.FILES['myfile']
dataset.load(new_product_table.read().decode('utf-8'), format='csv')
result = product_resource.import_data(dataset, dry_run=True) # Test the data import
if not result.has_errors():
product_resource.import_data(dataset, dry_run=False) # Actually import now
context = {'product_list': ProductList.objects.filter(client=request.user.id).all()} #.filter(client=request.user.username)
return render(request, 'Clientes/import.html', context)
My problem is that in the table appears that the value was changed, but if I click in the object, at the admin's page, the user that is selected is the first one.
The solution to that problem was simply that I was looking to change the wrong variable. To fix this and add another column to the dataset I did the following:
def simple_upload(request):
if request.method == 'POST':
product_resource = ProductListResource()
dataset = Dataset()
new_product_table = request.FILES['myfile']
dataset.load(new_product_table.read().decode('utf-8'), format='csv')
dataset.append_col([request.user.id]*dataset.height, header='client') # This code add another column to the imported csv.
result = product_resource.import_data(dataset, dry_run=True) # Test the data import
if not result.has_errors():
product_resource.import_data(dataset, dry_run=False) # Actually import now
context = {'product_list': ProductList.objects.filter(client=request.user.id).all()} #.filter(client=request.user.username)
return render(request, 'Clientes/import.html', context)
Related
I have a ModelForm called ListingForm. It takes data from a user but I have stopped some of the model attributes from appearing in this form as I want to feed data to those myself. I have put print statements in my createlisting function in views.py to inspect if the data is actually being saved correctltly, it turns out the data is being saved. Here is the createlisting function:
def create_listing(request):
if request.method == 'POST':
import datetime
listing_form = ListingForm(request.POST, request.FILES)
if listing_form.is_valid():
bid = listing_form.cleaned_data['starting_bid']
print(bid)
listing_form.save(commit=False)
listing_form.user = request.user
print(listing_form.user)
listing_form.date_made = datetime.datetime.today()
listing_form.is_active = True
listing_form.category = Category.objects.get(name=listing_form.cleaned_data['listing_category'])
print(listing_form.category)
#The form is being saved correctly here, and the print statements give the correct results in my terminal
listing_form.save()
Bid.objects.create(user= request.user, value=bid, listing=listing_form.instance)
all_listings = Listing.objects.all()
return render(request, 'auctions/index.html', {
'all_listings': all_listings })
else:
listing_form = ListingForm()
return render(request, 'auctions/createlisting.html',{
'listing_form':listing_form
})
However, when I try to access the data from the model Listing from which the ListingForm is inheriting, the print statements I have put for debugging return the default values for certain fields (category and user) instead of the values I have saved in the ListingForm.
Here is the code that allows me to view the data for the model instance I have created. Mind you, all the other fields have saved correctly except for the fields category and user:
def view_listing(request, listing_id):
listing = Listing.objects.get(pk=listing_id)
#the print results return the default values for the fields category and user instead of the values I saved in my ModelForm
print(listing.category)
print(listing.user)
if request.user == listing.user:
return render(request, 'auctions/view_listing.html', {
'listing': listing,
'flag':True,
'count': listing.bids.all().count()
})
else:
return render(request, 'auctions/view_listing.html',{
'listing':listing,
'count': listing.bids.all().count()
})
What could be the problem with my code?
Also, let me provide the code for some of my models and a form as the error might be embedded in those:
Listing Model:
class Listing(models.Model):
NAME_CHOICES = [
('Fashion', 'Fashion'),
('Toys','Toys'),
('Electronics','Electronics'),
('Home', 'Home'),
('Other', 'Other')
]
title = models.CharField(max_length= 64)
date_made = models.DateTimeField(auto_now_add=True)
description = models.TextField()
user = models.ForeignKey(User, to_field='username', on_delete=models.CASCADE, related_name='user_listings', null=True)
starting_bid = models.DecimalField(decimal_places=2, max_digits=264, default=10.00)
upload_image = models.ImageField(blank=True, upload_to='media/media')
category = models.ForeignKey(Category, on_delete=models.CASCADE, to_field='name', related_name='category_listings', default=NAME_CHOICES[4][0], db_constraint=False)
listing_category = models.CharField(max_length=12, choices=NAME_CHOICES, null=True, default=NAME_CHOICES[4][0])
is_active = models.BooleanField(default=True)
watchlist = models.ForeignKey('Watchlist', on_delete=models.DO_NOTHING, related_name='listings', null=True)
Category Model:
class Category(models.Model):
NAME_CHOICES = [
('Fashion', 'Fashion'),
('Toys','Toys'),
('Electronics','Electronics'),
('Home', 'Home'),
('Other', 'Other')
]
name = models.CharField(max_length=12, choices= NAME_CHOICES, unique=True)
User Model:
class User(AbstractUser):
def __str__(self):
return f'{self.username} '
ListingForm`` (ModelForm```):
class ListingForm(ModelForm):
class Meta:
model = Listing
exclude = [
'date_made',
'user',
'category',
'is_active',
'watchlist'
]
Any form of help would be greatly appreciated.
When you call listing_form.save(commit=False) it returns an unsaved model instance with the submitted values. If you assign that to a variable, you can use it to set the other field values and save:
def create_listing(request):
if request.method == 'POST':
import datetime
listing_form = ListingForm(request.POST, request.FILES)
if listing_form.is_valid():
bid = listing_form.cleaned_data['starting_bid']
listing = listing_form.save(commit=False)
listing.user = request.user
listing.date_made = datetime.datetime.today()
listing.is_active = True
listing.category = Category.objects.get(name=listing_form.cleaned_data['listing_category'])
listing.save()
Bid.objects.create(user=request.user, value=bid, listing=listing)
# You should probably use HttpResponseRedirect to an `all_listings` page, rather than displaying them here
all_listings = Listing.objects.all()
return render(request, 'auctions/index.html', {
'all_listings': all_listings })
Here's a link to the ModelForm.save() docs.
I have created two models Leads and Deals, and I have coded some logic such that if you click a button the Lead becomes a Deal, so what I want it is that a new form is presented to the user but that form already contains the information from the Leads model.
#login_required
def close_lead(request):
if request.method == 'POST':
deal_form = DealForm(request.POST)
if deal_form.is_valid():
deal_form.save()
messages.success(request, 'You have successfully updated the status from open to Close')
id = request.GET.get('project_id', '')
obj = Leads.objects.get(project_id=id)
obj.status = "Closed"
obj.save(update_fields=['status'])
return HttpResponseRedirect(reverse('dashboard'))
else:
messages.error(request, 'Error updating your Form')
else:
id = request.GET.get('project_id', '')
obj = get_object_or_404(Leads, project_id=id)
print(obj.expected_revenue)
form = NewDealForm(request.POST or None, instance=obj)
return render(request,
"account/close_lead.html",
{'form':form})
I have done some debug and printed to the console the queryset and the information is fine, so the queryset is no the problem, the problem is that the NewForm doesn't prepopulate the new values.
models.py (only 2 models shown)
class Leads(models.Model):
CHOICES = (
('Illumination Studies','Illumination Studies'),
('Training','Training'),
('Survey Design','Survey Design'),
('Software License','Software License')
)
STATUS = (('Open','Open'),
('Closed','Closed'),
('Canceled', 'Canceled')
)
project_id = models.BigAutoField(primary_key=True)
company = models.ForeignKey(Company, on_delete=models.CASCADE)
agent = models.ForeignKey(Profile, on_delete=models.CASCADE, default="agent")
created_at = models.DateTimeField(auto_now_add=True)
point_of_contact = models.ForeignKey(Client, on_delete=models.CASCADE)
expected_revenue = MoneyField(max_digits=14, decimal_places=2, default_currency='USD')
expected_licenses = models.IntegerField(blank=True)
country = CountryField(blank_label='(select country)')
status = models.CharField(max_length=10,choices=STATUS)
estimated_closing_date = models.DateField(blank=True)
services = models.CharField(max_length=20,choices=CHOICES)
def __str__(self):
return f'{self.company}'
class Deal(models.Model):
project_id = models.ForeignKey(Leads, on_delete=models.CASCADE, default='id')
agent = models.ForeignKey(Profile, on_delete=models.CASCADE, default="agent")
service = models.ForeignKey(Leads, on_delete=models.CASCADE, related_name='service')
closing_date = models.DateField(auto_now_add=True)
client = models.ForeignKey(Client, on_delete=models.CASCADE,default='client')
licenses = models.ForeignKey(Leads,on_delete=models.CASCADE, related_name='licenses')
revenue = MoneyField(max_digits=14, decimal_places=2, default_currency='USD')
comments = models.TextField(blank=True,null=True)
Now, it could be that I have to inherit from a different form?
forms.py (only NewDealForm)
class NewDealForm(forms.ModelForm):
class Meta:
model = Deal
fields = ['agent','client','project_id','service', 'licenses','revenue', 'comments']
Obviously, worst-case scenario is to create a dictionary to extract the data from the queryset and then pass it to the form, but I'm sure Django has a more elegant way to handle this process.
Well, I guess sometimes Stack Overflow pushes you to solve your own issues, this is the solution.
Essentially, the initial=queryset value was not initializing the form mainly because I have very specific relationships in my model, so what I did is to create a dictionary (key:value) with the form field as key, and my queryset from my model as the value, the code is as below:
'''
def close_lead(request):
if request.method == 'POST':
deal_form = DealForm(request.POST)
if deal_form.is_valid():
deal_form.save()
messages.success(request, 'You have successfully updated the status from open to Close')
id = request.GET.get('project_id', '')
obj = Leads.objects.get(project_id=id)
obj.status = "Closed"
obj.save(update_fields=['status'])
return HttpResponseRedirect(reverse('dashboard'))
else:
messages.error(request, 'Error updating your Form')
else:
id = request.GET.get('project_id', '')
obj = get_object_or_404(Leads, project_id=id)
m = obj.__dict__
keys = Leads.objects.get(project_id=m['project_id'])
form_dict = {'project_id':keys.project_id,
'agent':keys.agent,
'client':keys.point_of_contact,
'company':keys.company,
'service':keys.services
}
form = NewDealForm(request.POST or None,initial = form_dict)
return render(request,
"account/close_lead.html",
{'form':form})
'''
As you can see, I create an object dictionary because the forms are different, so they share some common values not all, and then I simply adapt the dictionary, nice and easy, but I somehow expected that Django somehow finds relationships by name?, but maybe the batteries are not included for this.
I got 3 models, one with auctions, second with watchlist, third with users
class Auctions(models.Model):
lot = models.CharField(max_length=64)
owner = models.CharField(max_length=64)
url = models.CharField(max_length=256, blank = True)
startBid = models.IntegerField()
description = models.CharField(max_length=64)
category = models.CharField(max_length=64, blank = True)
class User(AbstractUser):
pass
class Watchlist(models.Model):
user = models.CharField(max_length=64)
watchlist = models.CharField(max_length=64, blank = True)
Views:
def addToWatchlist(request, id):
print(id, "ID")
user = request.user
watchlist = Watchlist.objects.filter(user = user, watchlist = id)
data = list(watchlist)
if data == []:
createWatchList = Watchlist(
user = request.user,
watchlist = id
)
createWatchList.save()
else:
watchlist.delete()
return redirect('listing', id=id)
def watchlist(request):
id = Watchlist.objects.filter(user = request.user)
auctions = Auctions.objects.filter(id = id)
return render(request, "auctions/watchlist.html", {
"auctions": auctions
})
I receive an error "ValueError: The QuerySet value for an exact lookup must be limited to one result using slicing."
Can someone explain how to pass multiple QuerySet values into filter()
As a result, I need all auctions, that's a match the watchlist
Thank you!
Try this:
watchlist_id = Watchlist.objects.filter(user = request.user).values('id')
auctions = Auctions.objects.filter(id__in = watchlist_id).all()
Here we first filter watchlist_id and then it contain (id__in) in auctions table.
I have this model.
class Country(models.Model):
countryname = models.TextField(null=True)
countryincharge = models.ForeignKey(Employees, on_delete=models.CASCADE,null = True)
createdby = models.TextField(null=True)
createdtime = models.TextField(null=True)
modifiedby = models.TextField(null=True)
modifiedtime = models.TextField(null=True)
deletedby = models.TextField(null=True)
deletedtime = models.TextField(null=True)
isdeleted = models.IntegerField(null=True)
tenantid = models.TextField(null=True)
And create and update functions as following.
#Create
def countrycreate(request):
if request.user.is_authenticated:
if request.method == 'POST':
id = request.POST.get('id')
modelwithdata = Country(
countryname=request.POST.get('countryname'),
countryincharge_id=request.POST.get('countryincharge'),
createdtime = timezone.now(),
createdby = request.user.id
)
if Country.objects.filter(countryname=request.POST.get('countryname')).exists():
messages.info(request, 'Country already exists!')
return HttpResponseRedirect(request.META.get('HTTP_REFERER'))
else:
modelwithdata.save()
return redirect('/admin/countrylistview')
#Update
def countryupdate(request):
if request.user.is_authenticated:
if request.method == 'POST':
id = request.POST.get('id')
modelwithdata = Country(
countryname=request.POST.get('countryname'),
countryincharge_id=request.POST.get('countryincharge'),
modifiedtime = timezone.now(),
modifiedby = request.user.id
)
modelwithdata.id = id
modelwithdata.save()
return redirect('/admin/countrylistview')
The problem is when a record is created the createdtime value is saved as intended. But when running the update function the createdtime value is set to None. For unknown reasons. Other fields are working fine. The db is SQLite. Same behaviour happens when use DateTimeField(auto_now_add=True, null=True) and DateTimeField(auto_now=True, null=True).
The problem is you are creating a new object, first grab the original and change only what is required.
#Update
// Change this to get the object
modelwithdata = get_object_or_404(Country, pk=id)
// Change only the fields you need to
modelwithdata.countryname=request.POST.get('countryname')
modelwithdata.countryincharge_id=request.POST.get('countryincharge')
modelwithdata.modifiedtime = timezone.now()
modelwithdata.modifiedby = request.user.id
//Dont need this
// modelwithdata.id = id
//Save the new model
modelwithdata.save()
You should use PUT or PATCH method to update the data instead of POST
For your code we can also use .update()
# Update
def countryupdate(request):
if request.user.is_authenticated:
if request.method == 'POST':
Country.objects.filter(pk=request.POST.get('id')).update(
countryname=request.POST.get('countryname'),
countryincharge_id=request.POST.get('countryincharge'),
modifiedtime = timezone.now(),
modifiedby = request.user.id
)
return redirect('/admin/countrylistview')
I'm making a stock portfolio app as a personal project. I have a form StockSymbolForm used for buying stocks. It has the fields: username, stock_symbol, and stock_qty.
I've set username to be the current user that's currently using the app - so they only need to fill stock_symbol and stock_qty.
After a valid form is submitted, I go to my admin page to check, but I don't see my new stock_symbol and stock_qty added to my model.
Here's my code:
views.py:
class PortfolioStockListView(ListView):
model = StockPortfolio
template_name = 'stocks.html'
def post(self, request):
current_user = StockPortfolioUser.objects.filter(username=request.user).first()
if request.method == 'POST':
symbol_form = StockSymbolForm(request.POST, initial={'username': current_user})
if symbol_form.is_valid():
symbol_form = StockSymbolForm(request.POST, instance=current_user)
model_instance = symbol_form.save(commit=True)
model_instance.timestamp = timezone.now()
model_instance.save()
return redirect('/')
else:
return render(request, 'stocks.html', {'symbol_form': symbol_form})
else:
symbol_form = StockSymbolForm()
return render(request, 'stocks.html', {'symbol_form': symbol_form})
models.py:
class StockPortfolioUser(models.Model):
username = models.OneToOneField(User, on_delete=models.CASCADE)
usercash = models.PositiveIntegerField(default=100000)
class StockPortfolio(models.Model):
username = models.ForeignKey(StockPortfolioUser, on_delete=models.CASCADE)
stock_symbol = models.CharField(max_length=5)
stock_qty = models.PositiveIntegerField(default=0)
forms.py:
class StockSymbolForm(ModelForm):
class Meta:
model = StockPortfolio
fields = ('stock_symbol' , 'stock_qty')
labels = {'stock_symbol': 'Stock Symbol', 'stock_qty': 'Quantity'}
How do I save the model instance properly? and why is it not saving at the moment?
In your views.py file change this
model_instance = symbol_form.save(commit=False)
model_instance.username = request.user.id
model_instance.timestamp = timezone.now()
model_instance.save()
In StockSymbolForm change this
fields = ('username', 'stock_symbol' , 'stock_qty')
Well, you don't ever seem to be setting the username. You set a timestamp, which doesn't exist as a field, but not the actual username field.
model_instance = symbol_form.save(commit=True)
model_instance.userame = request.user
model_instance.save()
As an aside, that field should be called user, as it points to the whole User object not just the username.