Django: Access many-to-many (reverse) in the template - python

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.

Related

Django models. How do I make "add new" field in Django?

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.

Many to Many and Foreign Key relations in django admin

First my django knowledge is beginner level, so please be patient with me.
I am faced with a model relationship that I do not know how to handle. I have 3 models: Project, Location and SubLocation.
A project can have multiple locations and each location can have many sublocations. I have a many to many field for location in the Project model and a foreignkey field for location in the Sublocation model.
class Project(models.Model):
...
locations = models.ManyToManyField(Location)
class Location(models.Model):
name = models.CharField(max_length=250, unique=True)
class SubLocation(models.Model):
location = models.ForeignKey(Location)
name = models.CharField(max_length=100, unique=True)
In django admin, I am able to add multiple locations when creating a project(Using filter_horizontal). However, I also need the option to select sublocations based on an added location for the project being created. I did not know how to do it with the above approach.
I then removed the locations many to many field from the project model tried the approach below.
I created a ProjectLocation model and added it as an inline to the Project ModelAdmin to be able to add locations and sublocations when creating a project. The model that looks as follows:
class ProjectLocation(models.Model):
project = models.ForeignKey(Project)
location = models.ManyToManyField(Location)
sublocations = models.ManyToManyField(SubLocation)
However, the approach does not work as desired since you can add any sublocations irregardless of the locations added. What I would like is to be able to add locations and their relevant sublocations when creating a project.
I read through generic relations as another possible approach but still I did not know how to pull it off.
With my model structure, is that possible?
If True, what should I do to get the desired result?
If False, please recommend how I could change it.
I think if you use foreign key it will be easier for your case, and it will easy to use with the _set option from django.
Yes it is possible but it will not be dynamic (meaning that changing the value of location will not magically update themselves without first saving the change) which might be very unpractical.
You should use formfield_for_manytomany in your admin -> https://docs.djangoproject.com/en/1.8/ref/contrib/admin/#django.contrib.admin.ModelAdmin.formfield_for_manytomany
The easiest way to implement this would be to add custom javascript filtering on that particular admin form
Leave for models as it was and try to use inlines in admin page.
So, your admins.py would look something like this:
class SubLocationInline(admin.StackedInline):
model = SubLocation
#admin.register(Location)
class LocationAdmin(admin.ModelAdmin):
.....
inlines = [SubLocationInline]

Creating front-end forms like in Django Admin

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)

Django User Model Methods

So I have Auth and Profile implemented into my system however i'd like to extend the User model and I don't know what is considered the 'correct' way of doing this.
I just want to create a method that returns a link for the user like:
Username
I figured that this is probably best done using a method as the link will change and I don't want to be going through all my template files fixing this.
This may be common to somebody using Django but I have not used it much so I am not well versed in the conventions so any advice would be great
If you're not altering what is stored in the database, the easiest way is a proxy model. Here's an example straight out of the documentation (https://docs.djangoproject.com/en/dev/topics/db/models/#proxy-models)
from django.db import models
class Person(models.Model):
first_name = models.CharField(max_length=30)
last_name = models.CharField(max_length=30)
class MyPerson(Person):
class Meta:
proxy = True
def do_something(self):
# ...
pass
If you want to do something more complex than adding methods to the User model, such as adding new data fields, I would recommend creating a Model with a one-to-one relation to User.
The normal way to create URLs in Django without needing to worry about changing them is to use the {% url %} tag. See the documentation on reversing URLs.
I know you are asking specifically for extending the user model but have you considered creating a template tag to generate the link instead?
If you only need the method in the templates than that's definitely the way to go.

Given Products, each with multiple Versions, what is the preferred/best way to support custom attributes at the Product/Version level in my Django app

I'm building my first Django app to manage multiple SaaS products.
This entails storing custom attributes for each Version of each Product.
For example, a new version of a Product is released that includes new configuration options that the earlier versions of the Product do not support.
I need to be able to keep track of those new values for each instance of the new Version.
I'm thinking I want the Admins to be able to add "custom fields" at the Product level by Version.
Looking for suggestions as to the best approach.
Thanks.
The common way of tracking model versions is to use django-reversion.
It sounds like each instance needs its own custom attributes. That means that changing the Models relating to Product and Version need not occur. This is good, because models can only change with the code (unless you get into dynamically generating Models which is usually not a good idea).
So, you need to be able to model attributes for each Product instance, regardless of Version. This should be a simple data modelling exercise, not necessarily related to Django.
A Product has a set of fields
A Product has a Version
A Product has a set of Attributes
This is quite easily modelled, depending on how you want to manage attributes.
class Version(models.Model):
version = models.CharField(max_length=10)
class ProductAttributes(models.Model):
name = models.CharField(max_length=64)
description = models.CharField(max_length=255)
# other fields as necessary
class Product(models.Model):
name = models.CharField(max_length=64)
version = models.ForeignKey(Version)
attributes = models.ManyToManyField(ProductAttributes, related_name='products')
That should be your modelling sorted in a very basic way. Now, let's create some instances.
v1 = Version(version='1.0.0')
v1.save()
hosted = ProductAttributes(name='Hosted', description='We host the apps!')
hosted.save()
shiny = ProductAttributes(name='Shiny', description='I like shiny')
shiny.save()
p = Product(name='Web Based Email', version=v1)
p.save()
p.attributes.add(hosted)
p.attributes.add(shiny)
p.attributes.all()
# shows shiny and hosted!
You can tweak the ModelAdmin for Product such that you can add ProductAttributes inline when adding or editing a Product. You can also have a separate ModelAdmin for ProductAttributes so you can create a list of known Attributes that can be applied to products at a later date.
There are two basic approaches for this.
Use a document based db (ie, "NoSQL") like Couch or Mongo. These have flexible schemas, so allow for multiple variations on a product.
Use the Entity Attribute Value (wikipedia) schema pattern. django-eav is an app that provides this.
Decide to go with sub-classes with each Product as each has a limited set of specific attributes that won't change much or at all over time. Thanks for all the great feedback. Learned a lot :-)

Categories

Resources