Creating new table while iterating through a queryset in django - python

This is a newbie question, but despite reading https://docs.djangoproject.com/en/dev/ref/models/instances/#saving-objects , I'm not quite sure how to do this. I have an existing table where I would like to iterate through all its records, and save certain info to a second table. I have the following model:
class myEmails(models.Model):
text = models.CharField(max_length=1200)
In my view I have:
def getMyMessages(request):
from django_mailbox.models import Message
from get_new_emails.models import myEmails
import re
qs = Message.objects.all()
count = 0
output = ""
for i in qs:
count += 1
output = output + str(count) + " TEXT: " + i.text + '<br>' + '<br>'
return HttpResponse(output)
How can I modify my view to save "i.text" to the text field of the 'myEmails' table

You can create new objects and save them to the database afterwards using save():
for i in qs:
obj = myEmails(text=i.text)
obj.save()

Related

Django Foreign Key Related Objects Not Saving Changes, Cannot Edit

I have two models, Movie and Review. Review has a foreign key field related to Movie. I have been trying to edit the Review objects associated with an instance of Movie.
models.py
class Movie(models.Model):
title = models.CharField(max_length=160)
class Review(models.Model):
movie = models.ForeignKey(Movie, on_delete=models.CASCADE, related_name='reviews')
author = models.CharField(max_length=150)
active = models.BooleanField(default=True)
views.py
# Create and save movie object
movie = Movie(title="Nightcrawler")
movie.save()
# Create and save two review objects
review1 = Review(movie=movie, author="John", active=True)
review2 = Review(movie=movie, author="Rob", active=False)
review1.save()
review2.save()
print("Before: " + movie.title + " has " + str(len(movie.reviews.all())) + " reviews.")
active_reviews = movie.reviews.filter(active=True)
print("There are " + str(len(active_reviews)) + " active reviews.")
movie.reviews.set(active_reviews)
movie.reviews.first().author = "Abby"
# Try and save both objects just for good measure.
# Not sure if it is necessary to do this. Does not
# seem to work anyway
movie.reviews.first().save()
movie.save()
print("After: " + movie.title + " has " + str(len(movie.reviews.all())) + " reviews.")
print("Author of the first review is: " + str(movie.reviews.first().author))
The output of the views.py code is as follows:
Before: Nightcrawler has 2 reviews.
There are 1 active reviews.
After: Nightcrawler has 2 reviews.
Author of the first review is: John
I want and expected the changes made to movies.reviews to be saved, but the output reveals that neither the set() method or changing the author value actually alters the Movie instance. Why are none of these edits being preserved?
Interestingly, the line movies.reviews.first().delete() does seem to actually remove the first review. I am curious why this works and the other changes do not.
Thank you for your time!
If you want to manipulate the object, you should store it in a variable first
movie = Movie(title="Nightcrawler")
movie.save()
# Create and save two review objects
review1 = Review(movie=movie, author="John", active=True)
review2 = Review(movie=movie, author="Rob", active=False)
review1.save()
review2.save()
print("Before: " + movie.title + " has " + str(len(movie.reviews.all())) + " reviews.")
active_reviews = movie.reviews.filter(active=True).all()
print("There are " + str(len(active_reviews)) + " active reviews.")
movie.reviews.clear()
movie.reviews.set(active_reviews)
first_review = movie.reviews.first()
first_review.author = "Abby"
first_review.save()
movie.save()
It's not being saved because the object you updated is not the same with the object you saved because you ran another query by calling first() again.
If you intend to only keep the "active" reviews, you can use remove instead to remove inactive reviews.
movie.reviews.remove(*movie.reviews.filter(active=False))
set does not have any effect here because the active_reivews you passed as parameter is already linked or already set. If you want to stick with set, do a clear first.

PyQT Deleting QVBoxLayout In Order To Accomodate Updated Values from DB

So I have a problem with my PyQT5 interface is that when I load values from the database, it duplicates the in the view as it is being looped after button click.
Here is the code the populates a view when an item is inserted from the DB, it takes values from the DB. And displays it via loop.
def restart_program(self):
total, items = fetch_items()
for item in items:
item = str(item[0]) + ' - ' + str(item[2]) +'x'
self.b3 = QtWidgets.QPushButton(item)
self.v_box.addWidget(self.b3)
self.b3.clicked.connect(self.btn_click1)
curr_budget = fetch_budget()
curr_budget = curr_budget[0]
self.message2.setText("Total: " + str(total))
self.budget_status.setText("Budget: " + str(curr_budget))
self.message3.setText(" ")
The problem here is that.
Because of the view it doesnt delete the previous values. Resulting to something like this in the photo.
What I tried so far:
Getting the items and their frequencies and put them in a dictionary
Clearly didnt work as it just populated the db
had an idea to clear the view QVBoxLayout before so that when the view laods the data from db again, it wouldn't show the past inputs
But I'm not sure on how to implement #2. My full code can be seen here in the so_revision.py file
You could check how many elements you already have in your QVBoxLayout and remove them (just be careful not to remove your label etc) for eg:
def restart_program(self):
total, items = fetch_items()
for i in range(1, self.v_box.count()):
existing_item = self.v_box.itemAt(i).widget()
if existing_item:
existing_item.setParent(None)
for item in items:
item = str(item[0]) + ' - ' + str(item[2]) +'x'
self.b3 = QtWidgets.QPushButton(item)
self.v_box.addWidget(self.b3)
self.b3.clicked.connect(self.btn_click1)
curr_budget = fetch_budget()
curr_budget = curr_budget[0]
self.message2.setText("Total: " + str(total))
self.budget_status.setText("Budget: " + str(curr_budget))
self.message3.setText(" ")

django model building table name wrong

I have a postgresql RDS instance on aws free tier with my ec2 instance. I should have used EB, but didn't really know about it until I had a lot built out and am not excited about starting over on a new ami. I am trying to build my first interaction with the db, have a table there called server_config, created as:
CREATE TABLE SERVER_CONFIGS
(
config_key VARCHAR(63) NOT NULL,
config_value VARCHAR(63) NOT NULL,
UNIQUE (config_key)
);
INSERT INTO SERVER_CONFIGS (config_key,config_value)
VALUES ('ClientMustVerify','TRUE');
INSERT INTO SERVER_CONFIGS (config_key,config_value)
VALUES ('Auditing','FALSE');
COMMIT;
and in my django app, I have:
models.py:
from django.db import models
class serverConfig(models.Model):
config_key = models.CharField(max_length=63)
config_value = models.CharField(max_length=63)
excerpt of view.py:
from limbo.models import serverConfig
def editServer(request):
myConfigs = serverConfig.objects.all()
configHtml = ""
# for item in myConfigs #serverConfig.objects.values()
# configHtml += item.config_key + "\t" + item.config_value + "\n"
if request.method == 'POST':
form = serverForm(request.POST)
if form.is_valid():
integer = form.cleaned_data['int_field']
request.session['integer'] = integer
# call out to limboLogic.py to update values, add them to the session
message = 'The value \'' + str(integer) + '\' has been updated.'
return render(request, 'limboHtml/ServerConfiguration.html', {'form': form, 'SubmitMessage': message, 'CurrentConfigs': myConfigs})
else:
message = 'The server configuration has NOT been updated.' + '\n'
message += ', '.join("%s=%r" % (key,val) for (key,val) in form.errors.iteritems()) + '\n'
# message += ', '.join("%s=%r" % (key,val) for (key,val) in form.non_field_errors.iteritems()) + '\n'
return render(request, 'limboHtml/ServerConfiguration.html', {'form': form, 'SubmitMessage': message, 'CurrentConfigs': myConfigs})
# if a GET (or any other method) we'll create a blank form
try:
del request.session['integer']
except KeyError:
pass
form = serverForm()
return render(request, 'limboHtml/ServerConfiguration.html', {'form': form, 'SubmitMessage': '', 'CurrentConfigs': myConfigs})
error message:
File
"/home/ec2-user/limbo/limboenv/local/lib/python2.7/site-packages/django/db/backends/utils.py",
line 64, in execute
return self.cursor.execute(sql, params) ProgrammingError: relation "limbo_serverconfig" does not exist LINE 1: ...ig_key",
"limbo_serverconfig"."config_value" FROM "limbo_ser...
Why is it appending limbo_ at the start of the table? any way I can change this? should I just use my app name (or is that my project name? they're called the same thing...stupid polls tutorial) in the tables?
Django 1.10 and python 2.7 on a linux ami on ec2
Django creates a table for each of your models. The default name of the table will be app_name + '_' + model_name. If you do not want that to be the table's name, you can override it by specifying db_table in the models's Meta class
Ref: https://docs.djangoproject.com/en/1.10/ref/models/options/#db-table
Suggestion
Please do not use the app with the same name as the project to write your application logic. That app should always contain only the project settings

django returns none on web page

when I run this function in Django my output is none. what is wrong with the news() function?
Code:
import feedparser
from django.http import HttpResponse
def news():
YahooContent = feedparser.parse ("http://news.yahoo.com/rss/")
for feed in YahooContent.entries:
print feed.published
print feed.title
print feed.link + "\n"
return
def html(request):
html = "<html><body> %s </body></html>" % news()
return HttpResponse(html)
Error:
webpage shows None
You are printing the results, not returning them. In fact, the return statement will return None, just like all methods that don't have a return statement.
You should build the string in your method itself, like this:
def html(request):
head = '<html><body>'
foot = '</body></html>'
entries = []
for entry in feedparser.parse("http://news.yahoo.com/rss/").entries:
entries.append('{}<br />{}<br />{}<br />'.format(entry.published,
entry.title, entry.link))
return HttpResponse(head+''.join(entries)+foot)
Can you explain your code a little bit?
Imagine you have a list of "entries", like this:
entries = [a, b, c]
Each entry has a .published, .title, .link attribute that you want to print as a list in HTML.
You can do this easily by looping through it and using the print statement:
print('<ul>')
for entry in entries:
print('<li>{0.published} - {0.title} - {0.link}</li>'.format(entry))
print('</ul>')
However, what we need here is to send this data to the browser as a HTML response. We can build the HTML string by replacing print with a string that we keep adding to, like this:
result = '<ul>'
for entry in entries:
result += '<li>{0.published} - {0.title} - {0.link}</li>'.format(entry)
result += '</ul>'
This will work but is inefficient and slow, it is better to collect the strings in a list, and then join them together. This is what I did in my original answer:
result = ['<ul>']
for entry in entries:
result.append('<li>{0.published} - {0.title} - {0.link}</li>'.format(entry))
result.append('</li>')
Then I just joined them all up with a header and a footer, and then combined each individual string in the list with a space, and returned it as the response:
return HttpResponse('<html><body>'+''.join(result)+'</body></html>')
obviously your news() method returns nothing..
The right way should be:
def news():
YahooContent = feedparser.parse ("http://news.yahoo.com/rss/")
result = ''
for feed in YahooContent.entries:
result += feed.published + '\n'
result += feed.title + '\n'
result += feed.link + "\n"
return result
def html(request):
html = "<html><body> %s </body></html>" % news()
return HttpResponse(html)

Modified django form cleand_data do is not renedered in data

I want to add data to submitted data in a django form.
Until now I did something like this:
form = NewADServiceAccount(data=request.POST)
if form.is_valid():
data=request.POST.copy()
if not 'SVC' in data['Account_Name']:
data['Account_Name'] = 'SVC_'+data['Account_Name']
form = NewADServiceAccount(data=data)
This works, but I would like to do this check in a clean method, so I defined:
def clean_Account_Name(self):
data = self.cleaned_data['Account_Name']
if not 'SVC' in self.cleaned_data['Account_Name']:
data = 'SVC' + data
return data
However, when I run this code with the clean method, I see that clean_data does not match data,
and my rendered form does not contain a correct Account_Name (e.g. it does not have SVC in it):
ipdb> p form.cleaned_data['Account_Name']
u'SVCoz123'
ipdb> p form.data['Account_Name']
u'oz123'
The Account_Name from data is the one rendered to HTML, how can I fix this, so that Account_Name from cleaned_data is rendered?
update:
I found another way to do it, but I am still not sure it is the right way:
# inside forms.py
class NewADServiceAccount(NewAccount):
Account_Name = forms.CharField(min_length=3, max_length=21, required=True,
#initial="Please write desired name of "
#+ "this service account.",
help_text="Please write the desired name "
+ "of this account. The prefix 'SVC_' will"
+ " be added to this name",)
def set_prefix(self, prefix='SVC_'):
data = self.data.copy()
data['Account_Name'] = prefix+data['Account_Name']
self.data = data
# in views.py:
if form.is_valid():
form.set_prefix()
second update:
After looking at my solution I decided my clean method can be a bit better, so I did:
def clean_Account_Name(self):
data = self.data.copy()
if not 'SVC' in data['Account_Name']:
data['Account_Name'] = 'SVC' + data['Account_Name']
self.data = data
the above solution works, although the django documentation says:
Always return the cleaned data, whether you have changed it or not.
So, now I am quite confused.
I found a solution, but I need reaffirming it is a valid and good one. I would be happy if someone comments here about it.
If I understood you have been attempts uses the clean method. If I right, you did it a little wrong. Try use def clean() with a form's field:
forms.py
class AccountNameField(forms.CharField):
def clean(self, value):
value = u'SVC' + value
return value
class NewADServiceAccount(forms.Form):
Account_Name = AccountNameField(min_length=3, max_length=21, required=True,
#initial="Please write desired name of "
#+ "this service account.",
help_text="Please write the desired name "
+ "of this account. The prefix 'SVC_' will"
+ " be added to this name",)
views.py
form = NewADServiceAccount(request.POST or None)
if form.is_valid():
...
prefix is used only into a forms. If I am not mistaken prefix would be assign each fields of the form as prefix-namefield

Categories