Using the Django ManyToMany relationship example. Need to initialization first? - django

Just finished the Django tutorial. Starting my own project. Using the ManyToMany Relationship example here. I added in the following controls in my admin.py:
class ArticleInline(admin.TabularInline):
model = Article
extra = 3
class PublicationAdmin(admin.ModelAdmin):
inlines = [ArticleInline]
admin.site.register(Publication, PublicationAdmin)
But when I try to add a publication in the admin page, it says:
<class 'polls.models.Article'> has no ForeignKey to <class 'polls.models.Publication'>
Do I have to initialize an article before I can create a publication? Does creating a publication make Django look for an article?
Thanks for the help. Just starting out. It's pretty overwhelming, but very exciting.

If you're using a many to many relationship, you need to access the actual through model.
I'm assuming you have something like:
class Publication(models.Model):
[...] # your other stuff
articles = models.ManyToManyField(Article)
Assuming that construction, you access the through model using the attribute spelled similarly:
class ArticleInline(admin.TabularInline):
model = Publication.articles.through
[...] # whatever else you need
Hope that helps!

Related

Django QuerySet from one-to-many and from many-to-one

working on a project, where i came to a small problem with QuerySets. (Look at the bottom to see a short diagram of my model structure.) I tried to query some information of a BLOG-Model starting from the Collection-Model. Now is it better to query first the Entrie-Model and find somehow the Collection to afterwards find the Blog-Model and add the information in the end to the Collection? Or is there a better / faster way to get information directly from the parent Model? Normaly it is easy if you just have 1:n->1:n Relations because you can easily follow the foreignkey, but this confuses me.
Here a short overview of my model structure:
<--------------- QUERY DIRECTION ----------------
(BLOG) --(1:N)--> (ENTRIE) <--(N:1)-- (COLLECTION)
BR, Felix
django's relations works both ways so if you need blog model from collection model you can directly query your Blog model so from your diagram:
class Blog:
entrie = models.ForeignKey(Entrie, on_delete=CASCADE)
class Entrie:
pass
class Collection:
entrie = models.ForeignKey(Entrie, on_delete=CASCADE)
so your query can be something like if you have not specified any related_name attributes on your models relation fields
Blog.objects.filter(entrie__collection={your_data})

How to display manytomany field in django admin with a related model in a user-friendly way?

I'm struggling to display a manytomany field in the admin with the related model in a user-friendly manner. The project is already up and running so adding a through table is not preferred.
The set-up is something along these lines;
class User(AbstractUser):
is_member_of_organization = models.ManyToManyField(Organization, blank=True, verbose_name=_("is member of organization(s)"), related_name='orgmembers')
class Organization(models.Model):
name = models.CharField(max_length=60, verbose_name=_("organization name"))
the only reasonable way I manage to display the related users with organization admin is via a TabularInline
admin.py
class UserOrgAdminInLine(admin.TabularInline):
model = User.is_admin_for_organization.through
extra = 0
#admin.register(Organization)
class OrganizationAdmin(admin.ModelAdmin):
inlines = (UserOrgAdminInLine,)
However, looking up users is not convenient as soon as their number increases. I would like something similar to filer_horizontal but I am not sure how to include it directly in the OrganizationAdmin admin class. Furthermore, I am using fieldsets (which I believe should have no special rules or syntax to it compared to ordinary fields = .
One little subquestion - in the tabular inline, when I use only model = User django throws an error that there is no foreign key to it, but when I use the additional .is_admin_for_organization.through it works, but there is no through table and I though that this work just in that case. Why is that?
Any help would be much appreciated.
Try adding
class UserOrgAdminInLine
raw_id_fields = ("is_member_of_organization",)

Setting up a weird model in django?

This may be difficult to explain.
I'm a little new to django and the whole idea of models.
Let's say I'm making an article app, where each article has a creator, but other users can edit the article at will. I'm having a little difficult on how to create the models for this.
Firstly,
I extend the user profile with the following:
class UserProfile(models.Model):
#Required field:
user = models.OneToOneField(User)
#Other Fields:
headline = models.CharField()
industry = models.CharField()
article= models.ForeignKey(articleModel.article)
Here is the first place I'm getting confused, do I put the foreignkey field in the user model? My reasoning for it being placed here is because each article can have many editors.
Now here is my article model:
class article(models.Model):
#primary key is already true
creator = models.ForeignKey(userModel.UserProfile)
title = models.CharField()
text = models.TextField()
Over here, I put the ForeignKey field so it would relate back to the creator, because every article has a single creator. (As a side note, I do want to make it so an article can have multiple creators, but I don't know what to do in this scenario).
I'm finding it a bit odd that the UserProfile model is referencing the article model, and the article is referencing it back. Can someone please help me unjumble my brain?
Thank you.
:)
As simple as possible
from django.db.models import *
from django.contrib.admin.models import User
# UserProfile should be provided by django-profiles
class UserProfile(User): # Subclassing user creates an automatic 1-1 called user
headline = CharField()
industry = CharField()
class Article(Model):
# ALWAYS primary key to User, not UserProfile
creator = ForeignKey(User, related_name='articles_created')
contributors = ManyToManyField(User, related_name='articles_edited')
created = DateTime(auto_now_add=True)
modified = DateTimeField(auto_now=True)
title = CharField()
text = TextField()
class Meta:
order = ['created', 'title']
fun stuff:
creator = Article.objects.all()[:1][0].creator.getUserProfile().headline
considder using django-versions if you want to keep track of edits.
class Article(VersionedModel)
EDIT: actually subclasses user
Nothing "weird" here. This is no such a django problem than a database structure problem. You need to read about 1 to 1, 1 to n and n to n relationships between tables.
Do you really need to record all editors of an article ? An article has many editors, and a user can edit many articles, so this is a many to many relationship. Here's how do do it in django.
Perhaps another field in your article model for last editor would provide you with the information you need.
lastEditor = models.ForeignKey(userModel.UserProfile)
If you really want to keep all editors you will need to implement another model which records something like: article_id, editor and edit time (maybe even the article text if you are interested in changes). You could then query this medel based on the current article to obtain a list of all editors.
you could do the same with: article_id and creator to obtain a list of creators of an article (this would replace the article field in your UserProfile class)

Django: When extending User, better to use OneToOneField(User) or ForeignKey(User, unique=True)?

I'm finding conflicting information on whether to use OneToOneField(User) or ForeignKey(User, unique=True) when creating a UserProfile model by extending the Django User model.
Is it better to use this?:
class UserProfile(models.Model):
user = models.ForeignKey(User, unique=True)
or this?:
class UserProfile(models.Model):
user = models.OneToOneField(User)
The Django Doc specifies OneToOneField, while the Django Book example uses ForeignKey.
James Bennett also has two Blog posts that providing conflicting examples as well:
Extending the User Model
User Registration
In the former post, Bennett provides some reasons why he switched to using ForeignKey instead of OneToOneField, but I don't quite get it, especially when I see other posts that recommend the opposite.
I'm curious to know your preference and why. Or, does it even matter?
The only real reason given in the article is that it can be set up so that the admin page for User will show both the fields in User and UserProfile. This can be replicated with a OneToOneField with a little elbow grease, so unless you're addicted to showing it in the admin page with no work at the cost of a bit of clarity ("We can create multiple profiles per user?! Oh no, wait, it's set unique.") I'd use OneToOneField.
Besides the admin page inlines, other reason for the ForeignKey solution is that it allows you to use the correct, default DB manager when objects are accessed with a reverse relation. Consider example from this subclasses manager snippet. Let's say that the Post class definition from the example looks like this:
class Post(ParentModel):
title = models.CharField(max_length=50)
onetoone = models.ForeignKey(SomeModel, unique=True)
children = ChildManager()
objects = models.Manager()
By calling somemodel_instance.post_set.all()[0], you get the desired subclasses objects of the Post class as indicated by defining the first (default) manager as a ChildManager. On the other hand, with OneToOneField, by calling somemodel_instance.post you get the Post class instance. You can always call somemodel_instance.post.subclass_object and get the same result, but the default manager could do any other sort of tricks and the FK solutions hides them nicely.
If you own and can modify the custom manager code you can use the use_for_related_fields attribute instead of using FK in place of legitimate 1to1 field, but even that can fail because of some not-known to me nuisances of the automatic managers. As far as I remember it will fail in the above example.
Other reason to generally not use the OneToOneField related to reverse relations: when you use reverse relations defined via OneToOneField you get an model instance, contrary to Manager for ForeignKey reverse relation and as a consequence there's always a DB hit. This is costly if you do some generic stuff on reverse relations (via _meta.get_all_related_objects()) and do not know and care if you will use them all or not.

Multiple images per Model

I'm writing a simple real-estate listing app in Django. Each property needs to have a variable number of images. Images need to have an editable order. And I need to make the admin user-proof.
So that said, what are my options?
Is there a ImageList field that I don't know about?
Is there an app like django.contrib.comments that does the job for me?
If I have to write it myself, how would I go about making the admin-side decent? I'm imagining something a lot slicker than what ImageField provides, with some drag'n'drop for re-ordering. But I'm a complete clutz at writing admin pages =(
Variable lists, also known as a many-to-one relationship, are usually handled by making a separate model for the many and, in that model, using a ForeignKey to the "one".
There isn't an app like this in django.contrib, but there are several external projects you can use, e.g. django-photologue which even has some support for viewing the images in the admin.
The admin site can't be made "user proof", it should only be used by trusted users. Given this, the way to make your admin site decent would be to define a ModelAdmin for your property and then inline the photos (inline documentation).
So, to give you some quick drafts, everything would look something like this:
# models.py
class Property(models.Model):
address = models.TextField()
...
class PropertyImage(models.Model):
property = models.ForeignKey(Property, related_name='images')
image = models.ImageField()
and:
# admin.py
class PropertyImageInline(admin.TabularInline):
model = PropertyImage
extra = 3
class PropertyAdmin(admin.ModelAdmin):
inlines = [ PropertyImageInline, ]
admin.site.register(Property, PropertyAdmin)
The reason for using the related_name argument on the ForeignKey is so your queries will be more readable, e.g. in this case you can do something like this in your view:
property = Property.objects.get(pk=1)
image_list = property.images.all()
EDIT: forgot to mention, you can then implement drag-and-drop ordering in the admin using Simon Willison's snippet Orderable inlines using drag and drop with jQuery UI
Write an Image model that has a ForeignKey to your Property model. Quite probably, you'll have some other fields that belong to the image and not to the Property.
I'm currently making the same thing and I faced the same issue.
After I researched for a while, I decided to use django-imaging. It has a nice Ajax feature, images can be uploaded on the same page as the model Insert page, and can be editable. However, it is lacking support for non-JPEG extension.
There is a package named django-galleryfield. I think it will meet your demand.