I am trying to make an OfferUp-like web app using Django Framework. Everything has been going great until I ran into a problem. How could I make it so that users can upload multiple pictures, instead of just one using the models.ImageField() function? You know? We might have users that only have 5 pictures to upload, while another user might have 8. How could I make it so that users can upload into the database as many pictures as they want?
What I'm going to suggest isn't that much different from the comment above (i don't have enough reputation to make a comment), so I'm just going to add a code snippet:
class Item(models.Model):
name = models.TextField()
class ItemImage(models.Model):
name = models.TextField()
item = models.ForeignKey(Item, on_delete=models.CASCADE)
image = models.ImageField(upload_to='images/')
and say: If you have more than one model with many images, rather than repeating the code you can just make a model (class) that will be inherited as the foreign key.
Related
I've been reading through the Django documentation and looking over some of the other answers on the site for a couple of hours now, yet I still can't get it to sink in. I know this isn't Django specific, but the examples I use will be from a Django project.
My question boils down to when is it appropriate to use each:
Many-to-many relationships
Many-to-one relationships
One-to-one relationships
One-to-one, more or less makes sense to me.
Now for the other two. While I understand the differences between them in isolation, when it comes to using them practically in a project, I get confused. Here is an example:
class User(AbstractUser):
pass
class Listing(models.Model):
title = models.CharField(max_length=64)
description = models.TextField()
class Watchlist(models.Model):
user = models.ForeignKey(User, related_name='watchlist', on_delete=models.CASCADE)
item = models.ManyToManyField(Listing)
class Comment(models.Model):
user = models.ForeignKey(User, related_name='comments', on_delete=models.SET_NULL)
comment = models.TextField()
Would this be the correct use of Many-to-one(ForeignKey) and Many-to-many?
Should Watchlist.item be a ForeignKey? Or is M2M correct?
Wouldn't it simplify to make the 'Watchlist' part of the User class? (give them an empty list to populate with listing ID's)
Why is Watchlist.user not a One-to-one relationship, if each watchlist belongs to a single user, and a user can only have one list?
Apologies for my stupidity, I just can't get this to sink in!
Thank you.
edit: Context, the models are from a 'learning' project I was working on intended to be an auction site, similar to eBay. The watchlist is sort of a 'wish' list... for the user to watch an item, not for site to watch a user!
To explain it simply these django-models or objects represents tables in your database and the fields are like the columns in them. So with a one-to-one relation you can only have one row in one table relating to one row in another table. For example one user in the user table (represented by one row) can only relate to one row in a profile table. But your user can have many comments, so this would be a one-to-many/foreignkey relation (if you set unique=true on a fk, it will in practice function as 1:1). If the users can collaborate on writing comments, or for example as here on stackoverflow where users can edit other users comments, that would be a many-to-many relation.
Database design can be complicated/complex, especially using an ORM without basic knowledge of SQL and how it all works beneath. In general it requires a bit of planning even for a simple application.
I was curious if there was a way to replicate the Django admin interface - specifically the forms when adding an object - in the front end... Here's my scenario:
class Area(models.Model):
name = models.CharField(max_length=100)
class SubArea(models.Model):
name = models.CharField(max_length=100)
area = models.ForeignKey(Area)
class Product(models.Model):
name = models.CharField(max_length=150)
area = models.ForeignKey(Area, null=True, blank=True)
subarea = models.ForeignKey(SubArea, null=True, blank=True)
So If I setup a form in the frontend for the Product model, I have no way of adding Area or SubArea objects. In the Django admin, however, I'm able to easily add these objects by clicking the "+" next to the fields.
I am looking for the easiest possible solution (while still being secure) to allow for fronted creating of the Foreign Keys without having to setup separate forms. Not sure if that is even possible, but wanted to reach out to the community for advice.
Thanks!
J
Django admin makes extensive use of formsets, see below:
https://docs.djangoproject.com/en/1.6/topics/forms/formsets/
Regarding your query with adding the '+' a la Django admin, you can acheive this with the RelatedFieldWidgetWrapper which you can find here.
According to my experience the easiest way of adding, editing, updating corresponding(related) items on a Form on the front-end, same way like in the django-Admin, is using "django-addanother" which you can use from here. Easy, fast and clean solution on this problem and it works with Django 1.11 too. And it has good documentation, demo also.
django-form-admin (.. let enter more characters stackoverflow needs 30 for answer)
If I wanted to setup comments for a blog in Django, and I wanted people to be able to reply to comments (like a normal blog), meaning each comment would have to know if it's a comment on another comment or not, would I set the model fields like this?
from django.db import models
from django.contrib.auth.models import User
class Comment(models.Model):
post = models.ForeignKey(Post)
user = models.ForeignKey(User)
text = models.TextField()
date = models.DateTimeField()
reply_to = models.ForeignKey(Comment, blank=True, null=True)
Is that correct? And how would I display them in a template?
Writing a hierarchical comments application seems too easy at first look but believe me it is not that simple. There are too many edge cases and security issues. So if this is a real project i would suggest you to use disqus, any other hosted solution or (now deprecated) comments framework.
On the other hand if you are just trying to learn how things done or playing around, your code seems fair enough so far. But you should consider Django's built-in content types framework instead of a direct foreign key relationship. That way you can relate a comment object to any other object. (a blog post or another comment). Take a look at comment frameworks models.py and you will see it.
class BaseCommentAbstractModel(models.Model):
"""
An abstract base class that any custom comment models probably should
subclass.
"""
# Content-object field
content_type = models.ForeignKey(ContentType,
verbose_name=_('content type'),
related_name="content_type_set_for_%(class)s")
object_pk = models.TextField(_('object ID'))
content_object = generic.GenericForeignKey(ct_field="content_type", fk_field="object_pk")
Also take a look at RenderCommentListNodein comment framework template tags. You should write a recursive function in order to get and display hierarchical comments.
You have to consider cases like:
What will happen if a user deletes a comment?
How should we delete comments? Should we actually remove it from database or should we set an attribute like deleted
How should we deal with permissions and level of user access?
If we let anonymous users to comment, what information do we need from them.
How to check human validation? Is captcha enough?
Happy hacking.
Following up with the posting regarding reversed many-to-many look ups, I was wondering what the best practice for my project/picture problem is:
I want to register a number of projects and the users can upload (but not required) multiple project pictures.
Therefore I defined the following two classes:
from easy_thumbnails.fields import ThumbnailerImageField
class Project(models.Model):
name = models.CharField(_('Title'), max_length=100,)
user = models.ForeignKey(User, verbose_name=_('user'),)
...
class ProjectPicture(models.Model):
project = models.ForeignKey('Project')
picture = ThumbnailerImageField(_('Image'),
upload_to='user/project_pictures/', null=True, blank=True,)
def __unicode__(self):
return u'%s\'s pictures' % (self.project.name)
So for every user, I am displaying their projects in a "dashboard" via
projects = Project.objects.filter(user = logged_user)
which returns a list of projects with the names, etc.
Now I would like to display a picture of the project in the dashboard table. Therefore I have two questions I am seeking advice for:
1) Is the class setup actually the best way to do it? I split up the classes like shown above to allow the users to upload more than one picture per project. Would there be a better way of doing it?
2) How can I display the first picture of a project in the template, if a picture is available? Do I need to make a query on every ProjectPicture object which corresponds to a Project? Or is there an elegant Django solution for that problem?
It's not many-to-many relation, you use foreign keys. It's normal setup. To access first picture in template you can use {{ project.projectpicture_set.all.0 }}, it will generate additional query. To avoid it use prefetch_related.
I have a fairly simple model in Django, let's say Book:
class Book(models.Model):
name = models.CharField(max_length=255, default="")
description = models.TextField(null=True, blank=True)
creation_date = models.DateTimeField()
Because the structure and data basically comes from an external API, I have contained it in its own app and I rather not want to modify it.
Now I want to add another source of different books to the project and I'm not really sure what the best solution is here.
Let's say the second model is:
class NextBook(models.Model):
title = models.CharField(max_length=255, default="")
long_description = models.TextField(null=True, blank=True)
created = models.DateTimeField()
So the basic fields are there, but have different names. To get the two together, I can probably use another model with a GenericForeignKey:
class BaseBook(models.Model):
book_type = models.ForeignKey(ContentType)
book_id = models.PositiveIntegerField()
book_object = generic.GenericForeignKey('book_type', 'book_id')
But then I cannot query for all the book as e.g. BaseBook.objects.all().order_by('created') wouldn't work. Surely, I could go on and duplicate a datetime field in the base model and then the title and so on, but I think that would be the wrong direction. Also inheritance seems not a choice if I don't want to touch the specific models.
I am looking for some design pattern or something that let's me efficiently 'plug in' more providers and query for all objects, while not making a huge mess of model structure and database queries.
There’s a fundamental contradiction in your question. Do you assume that, for a given book, the created reported by different providers will be the same?
If yes, why can’t you make a created field on your BaseBook and order by that? You can then drop the creation_date from your Book (or just ignore it, if you don’t want to touch it).
If not, how do you want to order books (not provider entries) by created in the first place?
Also, what you’re trying to do sounds like a good case for a free-schema database like MongoDB. There, you can embed provider entries directly in your book documents, then order by something like “created from the first provider entry for the book”. Thus, you maintain self-contained provider documents without denormalization. You still need created to mean the same thing for all providers, though.