Post made up of blocks (text, image, video) - django

I'm trying to create a image site with a similar form for adding posts as on Imgur. A post should be made up of unlimited number of blocks of various types (text, image, video) that create finished blog post.
User chooses with which block he wants to start (maybe upload an image) and then adds another block by clicking a button.
I can't figure out a sensible model for blocks that would make up a single post.
This is my Post model:
class Post(models.Model):
author = models.ForeignKey('auth.User')
text = models.TextField() #just a placeholder until blocks work
created_date = models.DateTimeField(
default=timezone.now)
isWaiting = models.BooleanField(default=True)
isLocked = models.BooleanField(default=False)
views = models.IntegerField(default=0)
tags = TaggableManager(help_text="")
I don't know if I should define separate models for textblock, imageblock and videoblock (all with ForeignKey to Post model) or if there's a better solution.
I thought of a universal model that would store a TextField (for text written by the user) and a FileField (for image and video upload) used for every block type but one of the Fields in every record would always be empty (user can only write text or upload a file per block) and it seems like a "waste of space".
I appreciate any ideas for solving this problem.

If anyone comes across a similar problem I chose a universal content block design with many fields (some are empty depending on a block type, ex. media is empty when adding text block). It was easier for me to implement and later add necessary JS for dynamically adding more PostBlocks to Post.
Relevant models:
class Post(models.Model):
author = models.ForeignKey('auth.User')
title = models.CharField(max_length=100)
slug = models.SlugField(unique=True)
created_date = models.DateTimeField(default=timezone.now)
views = models.IntegerField(default=0)
tags = TaggableManager(help_text="")
class PostBlock(models.Model):
POST_TYPE_CHOICES = (
('TXT', 'Text'),
('IMG', 'Image'),
('VID', 'Video'),
)
postid = models.ForeignKey('Post', on_delete=models.CASCADE)
text = models.TextField(max_length=1024, blank=True)
media = models.FileField(upload_to=content_path, blank=True, validators=[
validate_file_extension])
contenttype = models.CharField(
max_length=3,
choices=POST_TYPE_CHOICES,
default='IMG',
)
order = models.IntegerField(default=0)
One Post can have as many PostBlocks as you need.

Related

Is it better to make separate django models, or add various foreign keys to one model?

I have a model to capture comments from a user, DocumentComment. The comments are tied to a particular document in the database, and created/edited/displayed on the page that displays that particular document:
class DocumentComment(Model):
"""
Captures a user's comment about a document
"""
document_id = models.ForeignKey(Document, on_delete=models.CASCADE, verbose_name="document file name", related_name='document')
user = models.ForeignKey(User, on_delete=models.CASCADE)
comment = models.TextField('comment', blank=True)
moderated = models.BooleanField(default=False)
added_to_description = models.BooleanField(default=False)
marked_for_deletion = models.BooleanField(default=False)
created = models.DateTimeField(auto_now_add=True, editable=False, verbose_name="date created")
updated = models.DateTimeField(auto_now=True, editable=False, verbose_name="last update")
I now find I need to record comments based on other objects displayed on different pages in the site, e.g. albums (collections of document) is a page and word clouds (derived from all the words in various documents) is another page. Since these new comments are not tied to one document, but a collection of documents, I don't think they should be added to the DocumentComment model for every document_id in the collection. I wouldn't necessarily want the comments on a collection to be displayed on the page with one of the documents in that collection.
Which approach is better (django-yy or pythonic or idiomatic or by whatever standard you choose):
create separate models as above for each display object (i.e. word clouds, albums, maybe more?)
keep adding foreign keys to the various objects to the DocumentComment model and adding on_delete=models.SET_NULL, blank=True, null=True to each of the foreign key fields
Also, are there some hidden gotchas about option #2 that I have not thought of?
Thanks!
Mark
Model Abstraction is the solution
Class Comment(models.Model):
user = models.ForeignKey(User,on_delete=models.CASCADE)
comment = models.TextField('comment', blank=True)
moderated = models.BooleanField(default=False)
added_to_description = models.BooleanField(default=False)
marked_for_deletion = models.BooleanField(default=False)
created = models.DateTimeField(auto_now_add=True, editable=False, verbose_name="date created")
updated = models.DateTimeField(auto_now=True, editable=False, verbose_name="last update")
Class Meta:
abstract = True
Class DocumentComment(Comment):
document_id=Models.ForeignKey()
Class AlbumComment(Comment):
album_if = Models.ForeignKey()

Why is a Django model taking so long to load in admin?

I have a fairly simple Django set up for a forum, and one of the most basic models is this, for each thread:
class Post(models.Model):
created = models.DateTimeField(auto_now_add=True)
last_reply = models.DateTimeField(auto_now_add=True, blank=True, null=True)
username = models.ForeignKey(User, related_name="forumuser")
fixed = models.BooleanField(_("Sticky"), default=False)
closed = models.BooleanField(default=False)
markdown_enabled = models.BooleanField(default=False)
reply_count = models.IntegerField(default=0)
title = models.CharField(_("Title Post"), max_length=255)
content = models.TextField(_("Content"), blank=False)
rating = models.IntegerField(default=0)
followers = models.IntegerField(default=0)
ip_address = models.CharField(max_length=255)
def __unicode__(self):
return self.title
def get_absolute_url(self):
return "/post/%s/" % self.id
Then we have some replies:
class PostReply(models.Model):
user = models.ForeignKey(User, related_name='replyuser')
post = models.ForeignKey(Post, related_name='replypost')
created = models.DateTimeField(auto_now_add=True)
content = models.TextField()
ip_address = models.CharField(max_length=255)
quoted_post = models.ForeignKey('self', related_name='quotedreply', blank=True, null=True)
rating = models.IntegerField(default=0)
reply_order = models.IntegerField(default=1)
Now, currently there just over 1600 users, 6000 Posts, and 330,000 PostReply objects in the db for this setup. When I run this SQL query:
SELECT * FROM `forum_post` LIMIT 10000
I see that Query took 0.0241 sec which is fine. When I browse to the Django admin section of my site, pulling up an individual Post is rapid, as is the paginated list of Posts.
However, if I try and pull up an individual PostReply, it takes around 2-3 minutes to load.
Obviously each PostReply admin page will have a dropdown list of all the Posts in it, but can anyone tell me why this or anything else would cause such a dramatically slow query? It's worth noting that the forum itself is pretty fast.
Also, if it is something to do with that dropdown list, has anyone got any suggestions for making that more usable?
Try to add all foreign keys in raw_id_fields in admin
class PostReplyAdmin(ModelAdmin):
raw_id_fields = ['user', 'post', 'quoted_post']
This will decrease page's load time in change view. The problem is that django loads ForeignModel.objects.all() for each foreign key's dropdowns.
Another way is to add foreign keys in autocomplete_fields (docs) in admin
class PostReplyAdmin(ModelAdmin):
autocomplete_fields = ['user', 'post', 'quoted_post']
As pointed by #Andrey Nelubin the problem for me was indeed in the page loading all related models for each foreign key's dropdown. However, with autocomplete_fields selects are turned into autocomplete inputs (see figure below), which load options asynchronously.

Creating list of photos in Django

On the webpage I am currently working on I have to display profiles of different persons. Each person has a profile image that is displayed on the right side. Furthermore, I have the content saved as markdown on the server.
Now I want to add the possibility to add an optional list of images that are displayed under the text and shows something about the person. My model for the person looks like that:
class stipendiat(models.Model):
first_name = models.CharField(max_length=100)
last_name = models.CharField(max_length=100)
content = models.TextField()
year = models.IntegerField(blank=False, null=False)
form = models.IntegerField(blank=False, null=False)
image = models.ImageField(upload_to='stipendiaten/', blank=True, null=True, default='default.jpg')
gallery = # This is the question
def __unicode__(self):
return self.first_name + " " + self.last_name
Because I want to save some data about the image the model should look like that:
class Image(models.Model):
caption = models.CharField(max_length=512)
year = models.IntegerField()
image = models.ImageField(upload_to=upload_path_handler, blank=False, null=False)
For convenience it should be possible to add an image while editing the form for the person. To be precise, I want to add a person and fill in the necessary information (first_name, last_name, content etc.). At the end should be a list of connected images and a button to add an image rapidly.
Is it necessary to use an external app or is there an elegant solution with relation fields?
Maybe you should use a different model for the gallery images and a foreign key field to link the two models together
class Image(models.Model):
#...
stipendiat = models.ForeignKey(Reporter)
Now you can retrieve the Gallery Images for a stipendiat with id 1 like this
Image.objects.filter(stipentiat__pk=1)

Post and Comment with the same Model

I have created a simple project where everyone can create one or more Blog.
I want to use this models for Post and for Comment:
class Post_comment(models.Model):
content_type = models.ForeignKey(ContentType)
object_id = models.PositiveIntegerField(_('object ID'))
content_object = generic.GenericForeignKey()
# Hierarchy Field
parent = models.ForeignKey('self', null=True, blank=True, default=None, related_name='children')
# User Field
user = models.ForeignKey(User)
# Date Fields
date_submitted = models.DateTimeField(_('date/time submitted'), default = datetime.now)
date_modified = models.DateTimeField(_('date/time modified'), default = datetime.now)
title = models.CharField(_('title'), max_length=60, blank=True, null=True)
post_comment = models.TextField(_('post_comment'))
if it is a comment the parent is not null.
So in most case the text field will contain a little bit of text.
Can I use this model for both Post and Comment ?
Is it a good solution ?
Its technically possible, but sounds like a bad solution.
Most of the queries you'll run are specific to either post or comment (examples: get all posts ordered by date to show on the blog index page, get 5 most recent posts' titles to show on a widget, get 5 most recent comments to show in a "latest comments" widget, get all comments of a specific post, get all the posts that a user has posted, etc). So the cost of having them in the same table is always having the .filter(parent=None) which means less readable code and some performance loss.

Django - how to make ImageField/FileField optional?

class Product(models.Model):
...
image = models.ImageField(upload_to=generate_filename, blank=True)
When I use ImageField(blank=True) and do not select image into admin form, an exception occurs.
In django code you can see this:
class FieldFile(File):
....
def _require_file(self):
if not self:
raise ValueError("The '%s' attribute has no file associated with it." % self.field.name)
def _get_file(self):
self._require_file()
...
Django trac has ticket #13327 about this problem, but seems it can't be fixed soon. How to make these field optional?
blank=True should work. If this attribute, which is False by default, is set to True then it will allow entry of an empty value.
I have the following class in my article app:
class Photo(models.Model):
imagename = models.TextField()
articleimage = models.ImageField(upload_to='photos/%Y/%m/%d', blank=True)
I make use of the above class in another class by using the ManyToManyField relationship:
class Article(models.Model):
pub_date = models.DateTimeField(default=timezone.now)
slug = models.SlugField(max_length=130)
title = models.TextField()
photo = models.ManyToManyField(
Photo, related_name='photos', blank=True)
author = models.ForeignKey(User)
body = models.TextField()
categories = models.ManyToManyField(
Category, related_name='articles', null=True)
I want to make images in my articles optional, so blank=True in
photo = models.ManyToManyField(Photo, related_name='photos', blank=True)
is necessary. This allows me to create an article without any images if I want to.
Are you using class Product in any relationship? If so, make sure to set blank=True in the relationship you are using.
Set null=True (see documentation)
class Product(models.Model):
...
image = models.ImageField(upload_to=generate_filename, blank=True, null=True)
If 'optional' means that you want to be able to disregard the image field altogether. Then blank=True, so do the trick. However, if you are still getting the same error, then this means that you are using it's url either in the template somewhere or you are trying to open the path of the image in models.py or views.py ( may be to resize the image or some other backend preprocessing).
That is why it is always suggested to use try - catch block while handling files.