I recently started playing with flask and to do so I have been developing a little sandbox web app that will serve as a container for other projects I have in mind. So far I focused on implementing a user system and I everything seems to be working. I also implemented my version of user roles control.
Now I want to start to develop the other aspects of the web app. Let's say, for example, I want to develop a blog, my own image storage, an achievement system for a group of my friends, etc. My intention is to use the same User model for all of the sub applications and I've been trying to draw how such relationship would look like, but I haven't thought of anything different then adding all of them into my main User class. My concern is that by doing so the User class will end up being too big, with many relationships attached; besides, not every user will have access/need for each of the sub applications.
Is there a better way to 'link' my user with other sub applications?
File structure
-- MyApp
-- auth_blueprint
-- forms.py
-- routes.py
-- models.py
-- utils.py
-- achievements_blueprint
-- forms.py
-- routes.py
-- models.py
[static, templates, etc]
User Class
from myapp import db, login_manager
from flask_login import UserMixin
from flask import url_for
from random import randint
from os import listdir
__PROFILE_PICS_PATH = 'myapp/static/media/img/profile_pics/'
def new_profile_pic():
pics = listdir(__PROFILE_PICS_PATH)
if '.DS_Store' in pics:
pics.remove('.DS_Store')
n_pics = len(pics)
return '/static/media/img/profile_pics/'+ str(randint(1, n_pics)) +'.png'
#login_manager.user_loader
def load_user(user_id):
return User.query.get(int(user_id))
# Define a base model for other database tables to inherit
class Base(db.Model, UserMixin):
__abstract__ = True
id = db.Column(db.Integer, primary_key=True)
date_created = db.Column(db.DateTime, default=db.func.current_timestamp())
date_modified = db.Column(db.DateTime, default=db.func.current_timestamp(),
onupdate=db.func.current_timestamp())
# Define a User model
class User(Base):
__tablename__ = 'users'
first_name = db.Column(db.String(20), nullable=False, default='First Name')
last_name = db.Column(db.String(30), nullable=False, default='Last Name')
email = db.Column(db.String(120), unique=True, nullable=False)
username = db.Column(db.String(20), unique=True, nullable=False)
password = db.Column(db.String(60), nullable=False)
image_file = db.Column(db.String(20), nullable=False, default=new_profile_pic())
# Define the relationship to Role via UserRoles
roles = db.relationship('Role', secondary='user_roles')
def __repr__(self):
return f"User('{self.username}','{self.email}','{self.image_file}')"
def has_roles(self, role_names):
return len([role for role in self.roles if role.name in role_names])
# Define the Role data-model
class Role(Base, db.Model):
__tablename__ = 'roles'
name = db.Column(db.String(50), unique=True)
# Define the UserRoles association table
class UserRoles(Base, db.Model):
__tablename__ = 'user_roles'
user_id = db.Column(db.Integer(), db.ForeignKey('users.id', ondelete='CASCADE'))
role_id = db.Column(db.Integer(), db.ForeignKey('roles.id', ondelete='CASCADE'))
If I were to add, for instance, a mini blog This is what I would do:
-- MyApp
-- blog_blueprint
-- forms.py
-- routes.py
-- models.py
[etc]
1. Create the necessary models at blog_bluprint/models.py
class Post(db.Model):
id = db.Column(db.Integer, primary_key=True)
title = db.Column(db.String(100), nullable=False)
date_posted = db.Column(db.DateTime, nullable=False, default=datetime.utcnow)
content = db.Column(db.Text, nullable=False)
user_id = db.Column(db.Integer, db.ForeignKey('user.id'), nullable=False)
2. And then add the relationship to the User model
posts = db.relationship('Post', backref='author', lazy=True)
Thanks for any help!
Related
I am building a blog website and I am using Django rest framework
I want to fetch top 2 comments for a particular post along with their related data such as user details.
Now I have user details in two models
User
People
and the comments model is related to the user model using foreign key relationship
Models ->
Comments
class Comment(models.Model):
comment = models.TextField(null=True)
Created_date = models.DateTimeField(auto_now_add=True)
Updated_date = models.DateTimeField(auto_now=True)
post = models.ForeignKey(Post, on_delete=models.CASCADE,
related_name='comments_post')
user = models.ForeignKey(User, on_delete=models.CASCADE,
related_name='comments_user')
The People model is also connected to the user model with a foreign key relationship
People Model ->
class People(models.Model):
user = models.OneToOneField(User, on_delete=models.CASCADE,related_name='people')
Name = models.CharField(max_length=255,null=True)
following = models.ManyToManyField(to=User, related_name='following', blank=True)
photo = models.ImageField(upload_to='profile_pics', blank=True,null=True)
Phone_number = models.CharField(max_length=255,null=True,blank=True)
Birth_Date = models.DateField(null=True,blank=True)
Created_date = models.DateTimeField(auto_now_add=True)
Updated_date = models.DateTimeField(auto_now=True)
for fetching the comments I am using rest-framework and the serializers look like this
class UserSerializer(serializers.Serializer):
username = serializers.CharField(max_length=255)
class peopleSerializer(serializers.Serializer):
Name = serializers.CharField(max_length=255)
class commentsSerializer(serializers.Serializer):
id = serializers.IntegerField(read_only=True)
comment = serializers.CharField(max_length=255)
Created_date = serializers.DateTimeField()
user = UserSerializer()
people = peopleSerializer()
The query to fetch the comments look like this ->
post_id = request.GET.get('post_id')
comments = Comment.objects.filter(post_id=post_id).select_related('user').prefetch_related('user__people').order_by('-Created_date')[:2]
serializer = commentsSerializer(comments, many=True)
return Response(serializer.data)
I am getting this error ->
Got AttributeError when attempting to get a value for field `people` on serializer `commentsSerializer`. The serializer field might be named incorrectly and not match any attribute or key on the `Comment` instance. Original exception text was: 'Comment' object has no attribute 'people'.
Unable to find a way out.
The source is user.people, not people, so:
class commentsSerializer(serializers.Serializer):
# …
people = peopleSerializer(source='user.people')
In the .select_related(…) [Django-doc] to can specify user__people: this will imply selecting user and will fetch the data in the same query, not in an extra query as is the case for .prefetch_related(…) [Django-doc]:
post_id = request.GET.get('post_id')
comments = Comment.objects.filter(
post_id=post_id
).select_related('user__people').order_by('-Created_date')[:2]
serializer = commentsSerializer(comments, many=True)
return Response(serializer.data)
Note: normally a Django model is given a singular name, so Person instead of People.
Note: It is normally better to make use of the settings.AUTH_USER_MODEL [Django-doc] to refer to the user model, than to use the User model [Django-doc] directly. For more information you can see the referencing the User model section of the documentation.
Note: normally the name of the fields in a Django model are written in snake_case, not PascalCase, so it should be: created_date instead of Created_date.
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
After going through several stackoverflows I still have yet to find something that solves this. I'm hoping it's just syntax as I'm a novice.
Admin:
from django.contrib import admin
from team_editor.models import Player, Team, TeamMembers
class PlayerInline(admin.StackedInline):
model = Player
class TMAdmin(admin.ModelAdmin):
inlines = (PlayerInline,)
# Register your models here.
admin.site.register(Team)
admin.site.register(Player)
admin.site.register(TeamMembers, TMAdmin)
Models:
class Player(models.Model):
firstName = models.CharField(max_length=30)
lastName = models.CharField(max_length=30)
class Team(models.Model):
teamName = models.CharField(max_length=30, unique=True)
class TeamMembers(models.Model):
team = models.ForeignKey(Team)
player = models.ForeignKey(Player, unique=True)
Error: class has no foreign key to class
I am using this setup since I want to view players on a team easily and change teams from one team to another (never on multiple)
Moved to many to many relation in team and dropped teammember table:
players = models.ManyToManyField(Player, blank=True, null=True)
Django noob questions:
I want to create a site which allows users to share info about cars. Each car should have a collection of images, and the submitter should select one of the images to be used to represent the car on a listing page. A basic set of models is shown below:
class Manufacturer(models.Model):
name = models.CharField(max_length=255)
class ModelBrand(models.Model):
name = models.CharField(max_length=255)
class Car(models.Model):
created_at = models.DateTimeField(auto_now_add=True, editable=False)
updated_at = models.DateTimeField(auto_now=True, editable=False)
# identifying information
manufacturer = models.ForeignKey(Manufacturer)
model_brand = models.ForeignKey(ModelBrand)
model_year = models.PositiveIntegerField()
class CarImage(models.Model):
created_at = models.DateTimeField(auto_now_add=True, editable=False)
updated_at = models.DateTimeField(auto_now=True, editable=False)
car = models.ForeignKey(Car, related_name='images')
source_url = models.CharField(max_length=255, blank=True)
image = ImageField(upload_to='cars')
But how do I model the selected image? Do I put a 'selected' BooleanField on the CarImage class? And how do I configure the Car and CarImage admin classes to allow an admin site user to select and image for a car from its 'images' collection?
First, I would like to suggest you to refactor your class using an auxiliary TimeStampedClass
class TimeStampedModel(models.Model):
"""
Abstract class model that saves timestamp of creation and updating of a model.
Each model used in the project has to subclass this class.
"""
created_at = models.DateTimeField(auto_now_add=True, editable=False)
updated_at = models.DateTimeField(auto_now=True, editable=False)
class Meta:
abstract = True
ordering = ('-created_on',)
So you can use this class over your project, subclassing it.
One simple solution for your question is attach your image gallery to your car, and create one attribute that is a IntegerField that stores the picture position in the image gallery:
...
class CarImage(TimeStampedField):
source_url = models.CharField(max_length=255, blank=True)
image = ImageField(upload_to='cars')
class Car(TimeStampedModel):
image_gallery = models.ManyToManyField(CarImage)
selected_picture = models.IntegerField(default=0)
# identifying information
manufacturer = models.ForeignKey(Manufacturer)
model_brand = models.ForeignKey(ModelBrand)
model_year = models.PositiveIntegerField()
So, if selected_picture is n, you just need to get n-th picture inside image_gallery
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()