I am trying to follow django tutorial but with my own task.
Models.py file looks like
from django.db import models
class User(models.Model):
nickname = models.CharField(max_length=30)
password = models.CharField(max_length=30)
email = models.EmailField()
reg_date = models.DateField()
class Question(models.Model):
head = models.CharField(max_length=50)
content = models.TextField()
author = models.ForeignKey(User)
date = models.DateField()
class Answer(models.Model):
content = models.TextField()
question = models.ForeignKey(Question)
author = models.ForeignKey(User)
date = models.DateField()
validity = models.BooleanField()
I made "python manage.py shell" and wrote something like:
>>> u1 = User(nickname='Alex', password='123', email='alex#mail.ru', reg_date='2013-01-07')
>>> u1.save()
>>> u2 = User(nickname='Kate', password='abcde', email='kitten#mail.ru', reg_date='2012-12-15')
>>> u2.save()
User_list gave me
[<User: User object>, <User: User object>]
But then I made a quit and did some changes in the code. After this I cannot make u1.delete() or u2.delete() because it tells NameError: name 'u1' is not defined, but still shows me list of two users there. I can also create new u1 and u2 and delete them. How can I apply to those previous users now to clear database?
If you want to delete all User rows:
User.objects.all().delete()
If you want to find and delete the two your code created:
User.objects.get(nickname='Alex').delete()
User.objects.get(nickname='Kate').delete()
Related
I have 2 model classes in Django:
class Notification(models.Model):
receiver = models.ForeignKey(User, null=True, blank=True)
content = models.CharField(max_length=500)
object_id = models.IntegerField(blank=True, null=True)
type = models.TextField(max_length=200, blank=True, null=True)
Class Notification stores notification about users activity. Field "content" is like: "welcome you registered Business Course successfully", or "5ASC is your voucher code". Field type stores types of object: course, promotion.
class PaymentTransaction(models.Model):
course = models.ForeignKey(Course)
student = models.ForeignKey(User)
PAYMENT_STATUS = ( SUCCESS, FAILURE, PROCESSING)
payment_status = models.CharField(max_length=50, choices=PAYMENT_STATUS, default=PROCESSING)
In notification pop up, when he clicks to paid Course then go to Course detail page and start learning, when he clicks to unpaid Course then go to Course register page, when he clicks to promotion code then go to promotion code page
How to have a QuerySet return all fields of Notification and PaymentTransaction tables, and condition is Notification.receiver_id = PaymentTransaction.student_id .
For each Course notification, i want to get Course payment status.I did:
user = request.user
p_list = PaymentTransaction.objects.filter(student=user)
n_list = Notification.objects.filter(receiver=user).intersection(p_list)
But it did't work
I can't understand why you create the Models like this but:
I think it should be:
class Book:
title = models.CharField(max_length=500)
price = models.FloatField()
class User:
name= models.CharField(max_length=500)
something = models.CharField()
class Book_User:
user = models.ForeignKey(User)
book = models.ForeignKey(User)
detail = models.CharField()
And i what is noti for?Just show up the list?
~> it should be the list of Book_User in page of user
~> Problem solve
Here are the models:
class Teacher(models.Model):
login = models.CharField(max_length=10, primary_key=True)
fname = models.CharField(max_length=30)
mname = models.CharField(max_length=30)
lname = models.CharField(max_length=30)
class Course(models.Model):
semester = models.ForeignKey(Semester, on_delete=models.CASCADE)
title = models.CharField(max_length=40)
teachers = models.ManyToManyField(Teacher.login, through='TeacherCourse')
credits = models.IntegerField()
numberEnrolled = models.IntegerField()
nomenclature = models.CharField(max_length=128)
lectures = models.IntegerField()
class TeacherCourse(models.Model):
teacher = models.ForeignKey(Teacher.login, on_delete=models.CASCADE)
course = models.ForeignKey(Course, on_delete=models.CASCADE)
allotedLectures = models.IntegerField()
Just added these to fresh project and tried to runserver. I'm getting the following:
AttributeError: type object 'Teacher' has no attribute 'login'
I'm missing something obvious?
I later found your bug from Uday Bhatye's answer:
teacher = models.ForeignKey(Teacher.login, on_delete=models.CASCADE)
is a syntax error in django.
You should do:
teacher = models.ForeignKey(Teacher, on_delete=models.CASCADE)
And to reference the login status of teachers assigned to a particular TeacherCourse:
teachercourse = TeacherCourse.objects.filter(id=teachercourse_id).select_related('teacher')
login_status = course.teacher.login
Hits the database once with select_related and fetches the login status of all teachers assigned to the TeacherCourse.
As the login field in teacher model is already declared as primary key, I need not reference it in the other two models as Teacher.login. Only referencing as Teacher suffices.
i am trying to make a simple profile edit form for users on a website. I've followed the standard advice for updating, in the docs it says that Django detects the instances primary key and knows to update instead of insert.
only problem is, i get an insert when i am trying to update. I pre populate a form with a model instance (the instance that im trying to edit) but when i try and save it, i get a new instance. When i add the 'force_update=True' line, i get an error message that tells me that no primary key is detected. Not sure why, because im pre populating the form with a model instance, although, obviously the pk is not a part of the form. is there something im missing?
some code:
the model:
class profile(models.Model):
user = models.ForeignKey(User)
first_name = models.CharField(max_length=20, null=True)
last_name = models.CharField(max_length=20, null=True)
DOB = models.DateField(null=True)
age = models.IntegerField(null=True)
public_email = models.EmailField(null=True)
county = models.CharField(max_length=20, null=True)
town = models.CharField(max_length=30, null=True)
the form:
class profileForm(forms.ModelForm):
class Meta:
model = profile
exclude = ['user']
the view:
#login_required()
def edit_profile(request):
if request.POST:
proform = profileForm(request.POST)
if proform.is_valid():
prof = proform.save(False)
prof.user = request.user
prof.save(force_update=True)
return HttpResponseRedirect('/accounts/view_profile/')
else:
c = {}
if profile.objects.filter(user=request.user).exists():
prof = profile.objects.get(user=request.user)
c['proform'] = profileForm(instance=prof)
else:
c['proform'] = profileForm()
return render(request, 'edit_profile.html', c)
any help greatly appreciated!
i got it, turns out i was trying to just calling save() on the form without specifying the particular instance that the form relates to.
code:
#login_required()
def edit_profile(request):
c = {}
if profile.objects.filter(user=request.user).exists():
profModel = profile.objects.get(user=request.user)
c['proform'] = profileForm(instance=profModel)
else:
c['proform'] = profileForm()
if request.POST:
# this line here, added 'instance=profModel' to specify
# the actual instance i want to save
proform = profileForm(request.POST, instance=profModel)
if proform.is_valid():
prof = proform.save(False)
prof.user = request.user
prof.save()
return HttpResponseRedirect('/accounts/view_profile/')
else:
return render(request, 'edit_profile.html', c)
works!
I would like to create movies database, where user will be able to mark movies he/she watched and liked:
class Movies(ndb.Model):
watched = ndb.UserProperty()
liked = ndb.UserProperty()
Will that work? I use Google accounts.
How should I choose later all movies user liked?
Upd. I've followed systempuntoout approach and use the following code to save user choices:
user = users.get_current_user()
if user:
userschoices = models.UsersChoices(
movie=ndb.Key(models.Movies, movie_id), # TODO: what if movie_id is wrong?
watched=True,
user_id=user.user_id()
)
try:
userschoices.put()
self.response.out.write('1')
except:
self.response.out.write('0')
But if user makes his choice several times, then several records are added to the datastore...
Wouldn't be it better just to save user id and movie id as keyname?
userschoices = models.UsersChoices.get_by_id(user.user_id() + '-' + movie_id)
if userschoices is None:
userschoices = models.UsersChoices(id=user.user_id() + '-' + movie_id)
userschoices.movie = ndb.Key(models.Movies, movie_id) # TODO: what if movie_id is wrong?
userschoices.user_id = user.user_id()
if option == 'liked':
userschoices.liked = True
elif option == 'watched':
userschoices.watched = True
However, with such approach if I don't pass liked, then it overwrites its value with None (the same with watched, if not passed, None is used).
I would go with two different Models, one that stores all the Movies details and one to store the UserChoices :
class Movies(ndb.Model):
title = ndb.StringProperty(required=True)
director = ndb.StringProperty()
whatever = ndb.StringProperty()
class UsersChoices(ndb.Model):
movie = ndb.KeyProperty(kind=Movies, required=True)
watched = ndb.BooleanProperty(required=True)
liked = ndb.BooleanProperty(required=True)
user_id = ndb.StringProperty(required=True)
#classmethod
def get_liked_movies(cls, user_id):
return cls.query(cls.user_id == user_id, cls.liked == true).fetch(10)
#classmethod
def get_watched_movies(cls, user_id):
return cls.query(cls.user_id == user_id, cls.watched == true).fetch(10)
#classmethod
def get_by(cls, user_id, movie_key):
return cls.query(cls.user_id == user_id, cls.movie == movie_key).get()
If you need to store informations about users you should create your UserInfo Model, keyed by user_id from the users API, with all the details Properties your application needs.
class UserInfo(ndb.Model):
#Keyed by user_id
nickname = ndb.StringProperty()
email = ndb.StringProperty()
To create a new UserInfo, you could do:
from google.appengine.api import users
user = users.get_current_user()
userinfo = UserInfo(
id = user.user_id(),
nickname = user.keyname(),
email = user.email()
)
userinfo.put()
Then, when the user is logged in, use his/her user_id to retrieve the watched/liked movies.
from google.appengine.api import users
user = users.get_current_user()
userinfo = ndb.Key(UserInfo, user.user_id()).get()
watched_movies = UsersChoices.get_watched_movies(userinfo.key.id())
liked_movies = UsersChoices.get_liked_movies(userinfo.key.id())
It appears you are trying to model a many-to-many relationship. There are a few ways to model this relationship (see the Many-to-Many section). See also Nick's blog. (Unfortunately, neither of those references are written for NDB, so, for example, you can't use collection_name, i.e., back-references. But they are still useful in showing you how to break up the data into different models.)
Here's one way you could do it, using "join tables"/"relationship models":
class Movie(ndb.Model):
title = ndb.StringProperty(required=True)
class LikedMovie(ndb.Model):
movie = ndb.KeyProperty(kind=Movie, required=True)
user = ndb.StringProperty(required=True) # user.user_id()
class WatchedMovie(ndb.Model):
movie = ndb.KeyProperty(kind=Movie, required=True)
user = ndb.StringProperty(required=True) # user.user_id()
...
movies_user_likes = LikedMovie.query(LikedMovie.user == user.user_id()).fetch()
Depending on how many users your application will support, and how often the database will be updated, it may be more efficient to use repeated properties (i.e., lists of users) instead of join tables:
class Movie(ndb.Model):
title = ndb.StringProperty(required=True)
users_who_watched = ndb.StringProperty(repeated=True) # list of user.user_id()s
users_who_liked = ndb.StringProperty(repeated=True) # list of user.user_id()s
...
movies_user_likes = Movie.query(Movie.users_who_liked == user.user_id()).fetch(projection=[Movie.title])
Note that I used a projection query above, so that the users_who_watched lists are not returned with the query results. You probably don't need these, and this should make fetching significantly faster.
If you expect, say, less than 1,000 users to watch or like a particular movie, the list approach might be better.
For a more advanced technique, see Building Scalable, Complex Apps on App Engine, where Brett shows how to move the repeated/list property into a separate model, using parent keys.
Here are my models:
class User(db.Model):
id = db.StringProperty(required=True)
created = db.DateTimeProperty(auto_now_add=True)
updated = db.DateTimeProperty(auto_now=True)
name = db.StringProperty(required=True)
email = db.StringProperty()
class Page(db.Model):
id = db.StringProperty(required=True)
created = db.DateTimeProperty(auto_now_add=True)
updated = db.DateTimeProperty(auto_now=True)
name = db.StringProperty(required=True)
link = db.StringProperty(required=True)
class UserPage(db.Model):
user = db.ReferenceProperty(User, collection_name='pages')
page = db.ReferenceProperty(Page, collection_name='users')
How would I construct a query to find a users pages?
I found an article that describes a method to do it but is this the best way? http://blog.arbingersys.com/2008/04/google-app-engine-better-many-to-many.html
Your answer will work, but it will perform 7 calls to the datastore:
1 for the call to User.get_by_key_name()
1 for the call to UserPage...fetch()
5 for each dereference of x.page.id inside the loop
An alternative approach which only does 3 calls to the datastore would be something like this:
myuser = User.get_by_key_name("1")
up = UserPage.all().filter('user =', myuser).fetch(5)
keys = [UserPage.page.get_value_for_datastore(x) for x in up]
pages = db.get(keys)
for p in pages:
self.response.out.write(p.id)
See http://blog.notdot.net/2010/01/ReferenceProperty-prefetching-in-App-Engine for more details.
After some testing, it appears I can use:
myuser = User.get_by_key_name("1")
up = UserPage.all().filter('user =', myuser).fetch(5)
for x in up:
self.response.out.write(x.page.id)
I would recommend a different approach, that is less "relational-oriented" than your UserPage relationship:
class User(db.Model):
id = db.StringProperty(required=True)
created = db.DateTimeProperty(auto_now_add=True)
updated = db.DateTimeProperty(auto_now=True)
name = db.StringProperty(required=True)
email = db.StringProperty()
class Page(db.Model):
id = db.StringProperty(required=True)
created = db.DateTimeProperty(auto_now_add=True)
updated = db.DateTimeProperty(auto_now=True)
name = db.StringProperty(required=True)
link = db.StringProperty(required=True)
# Users linking to this page
users = db.ListProperty(db.Key)
And then you can get all pages of a specific user with the following query:
Page.gql("WHERE users = :1", user.key())
Please note that you should place the list property of keys on the side where you expect less items. I've assumed you will have less users liked to a page, than pages linked to a user, so I've put it on the Page side, but that will depend on your specific use case.
See here for official recommendations on the many-to-many topic: http://code.google.com/appengine/articles/modeling.html