Relationships in Django Admin - django-models

I get really confused with many-to-many database relationships, so can some one please clarify how I would achieve this?
I need a table of "Tags" (as in tag words) and a table for "Entries", such at many "Entries" could correspond to many Tag words.
Right now I have my models like this:
# models.py
class Tags(models.Model):
tag = models.CharField(max_length=255)
entry = models.ManyToManyField(Entry)
class Entry(models.Model):
entry = models.CharField(max_length=255)
description = models.TextField()
Now I'm confused, how would I setup my admin.py so I could then add tags when I create a new entry?

What you need is using the through feature of models:
class Tag(models.Model):
tag = models.CharField(max_length=255)
entry = models.ManyToManyField(Entry, through='TaggedEntries')
class Entry(models.Model):
entry = models.CharField(max_length=255)
description = models.TextField()
class TaggedEntries(models.Model):
entry = models.ForeignKey(Entry)
tag = models.ForeignKey(Tag)
and now use that model in your admin:
class TagsInline(admin.TabularInline):
model = TaggedEntries
extra = 1
class EntryAdmin(admin.ModelAdmin):
inlines = (TagsInline, )
admin.site.register(Entry, EntryAdmin)
admin.site.register(Tag)

You will need something along the lines of:
# admin.py
from django.contrib import admin
from models import *
class TagsInline(admin.TabularInline):
model = Tag
extra = 1
class EntryAdmin(admin.ModelAdmin):
inlines = (TagsInline, )
admin.site.register(Entry, EntryAdmin)
admin.site.register(Tag)
(Note, this code was written in a browser!)

Related

How to create a tags field for multiple Page classes in Wagtail?

I want to add a field for keywords that almost every model in my site will have. It would be ideal if I didn't have to define a "TaggedPage" class for every Page model. So I created a BasePage abstract model but ParentalKey doesn't appear to work with an abstract model. How can I solve this?
I get this error:
home.TaggedPage.content_object: (fields.E300) Field defines a relation with model 'home.BasePage', which is either not installed, or is abstract.
home.TaggedPage.content_object: (fields.E307) The field home.TaggedPage.content_object was declared with a lazy reference to 'home.basepage', but app 'home' doesn't provide model 'basepage'.
home/models.py contains these models:
class PageTag(TagBase):
""" Tag used for the keywords meta html tag"""
class Meta:
verbose_name = "search/meta keyword"
verbose_name_plural = "search/meta keywords"
class TaggedPage(ItemBase):
tag = models.ForeignKey(
PageTag,
related_name="tagged_pages",
on_delete=models.CASCADE,
)
content_object = ParentalKey(
to='home.BasePage',
on_delete=models.CASCADE,
related_name='tagged_items'
)
class BasePage(MetadataPageMixin, Page):
tags = ClusterTaggableManager(
through='home.TaggedPage',
blank=True,
help_text="Used for the keywords meta html tag",
)
promote_panels = Page.promote_panels + [
FieldPanel('tags'),
]
class Meta:
abstract = True
class HomePage(BasePage):
parent_page_types = []
Point the ParentalKey at the Page model instead:
content_object = ParentalKey(
to='wagtailcore.Page',
on_delete=models.CASCADE,
related_name='tagged_items'
)
At the database level this will have the behaviour you're looking for: a foreign key field referencing the ID of the page object. The one minor side effect is that the tagged_items relation will be defined on all Page objects, not just ones inheriting from BasePage, but that shouldn't cause any problems.

URL with dot in Django Rest Framework

I have the following model with a primary_key=True specified:
class Team(models.Model):
name = models.CharField(
max_length=64,
primary_key=True,
)
... other fields
When I serialize this model, I do the following:
class TeamSerializer(serializers.ModelSerializer):
class Meta:
model = Team
fields = ('url', 'name',) # and another fields
My viewset:
class TeamViewSet(viewsets.ModelViewSet):
lookup_value_regex = '[-\w.]'
queryset = Team.objects.all()
serializer_class = TeamSerializer
filter_fields = ('name',) # and another fields
My urls.py:
router = routers.DefaultRouter()
router.register(r'teams', TeamViewSet)
urlpatterns = [
url(r'^api/', include(router.urls)),
# I am not sure if this url is right. I repeat of include(router.urls)
url(r'^api/teams/(?P<name>[-\w.]+)/', include(router.urls)),
url(r'^api-auth/', include('rest_framework.urls', namespace='rest_framework'))
]
Then, when I create a Team object with name attribute containing dot ., for example Latinos F.C. and I go to the rest url, I get:
I am not sure about of how to use the lookup_value_regex attribute in my viewset. In this answer is used with some basic regex, but if I use it, any Team object is reachable via my serialized Rest API.
How to can I get a url like as: /api/teams/Name.F.C. in my serialized Team model?
First of all check if you have set APPEND_SLASH to True in your settings, because if not - the missing slash (at the end of the URL) is a problem.
Second - I do not think that dot is a problem, the problem can be a space - coded as %20;
Third - such urls looks just ugly :) You should consider changing it to some kind of a slugs: Latinos F.C. -> latinos-fc;
If you do that (just add additional field on the model with slug - this field should be obviously unique) - set up the lookup_field on your view - this will solve your problem.
Consider the example:
views.py
class SomeViewSet(viewsets.ModelViewSet):
queryset = SomeModel.objects.all()
serializer_class = SomeSerializer
lookup_field = 'slug_name'
serializers.py
class SomeSerializer(serializers.ModelSerializer):
class Meta:
model = SomeModel
fields = ('id', 'name', 'slug_name')
read_only_fields = ('slug_name',)
def to_internal_value(self, data):
ret = super(SomeSerializer, self).to_internal_value(data)
ret['slug_name'] = slugify(ret['name'])
return ret
models.py
class SomeModel(models.Model):
name = models.CharField(max_length=100)
slug_name = models.SlugField(unique=True, max_length=100)
urls.py
router.register(r'teams', SomeViewSet, base_name='teams')
urlpatterns = router.urls
And now:
creation:
details:
Can you do that this way? Or you really need the dots?

Django models - how to create a selected_instance field from an instance in a collection

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

How to create an entity of a model with referenceProperty without the reference exists?

I have two model classes Team and Student. Each Team entity has more than one Users entities, I think "one to many" is a proper model. I code like this:
class Team(db.Model):
teamNmae = db.StringProperty(required=True)
teamID = db.IntegerProperty(required=True)
class Users(db.Model):
name = db.StringProperty(required=True)
reference = db.ReferenceProperty(Team,collection_name=teamMembers)
Follow this document, I need to first create a Team entity, then create Users whose reference is set to this Team entity. But,here is the problem, I want to create User first, then User can create a Team. So, how to set reference when I create a User that no Team exists ?
EDIT1:
I write simple code to test if I can create a entity without its reference entity created.
_author__ = 'Steven_yang'
import os
import webapp2
from google.appengine.ext import db
from google.appengine.ext.webapp import template
defaultStu = [
'qingWANG',
'stevenYANG',
'jingZHU',
'conghuiHE',
'lianDUAN',
'xinHAO'
]
class Students(db.Model):
#reference = db.ReferenceProperty(Team,collection_name='teamMember',required=False)
name = db.StringProperty(required=True)
class Team(db.Model):
teamName = db.StringProperty(required=True)
teamID = db.IntegerProperty(required=True)
def createStu():
stu_count = Students.all().count(1)
if stu_count == 0:
for stu in defaultStu:
newStu = Students(name = stu)
newStu.put()
class testReferenceHandler(webapp2.RequestHandler):
def get(self):
createStu()
self.render_page()
def render_page(self):
stus = Students.all().fetch(10)
templateValues={}
templateValues['stus'] = stus
form = os.path.join(os.path.dirname(__file__),'template/testref.html')
renderForm = template.render(form,templateValues)
self.response.out.write(renderForm)
app = webapp2.WSGIApplication([('/testref',testReferenceHandler)],debug=True)
HTML file is:
<body>
{% for s in stus%}
<div>{{s.name}}</div>
{% endfor%}
</body>
</html>
when I comment out the ReferenceProperty line, everything is fine. When I add the ReferenceProperty line, I got a server error. So, I can't create a entity without its reference created before?
Did you try to set reference to Team model as None when creating a User instance?
Also change the last line your code snippet to:
reference = db.ReferenceProperty(Team,required=False)
i.e. add required=False. This is what is suggested in this answer.

Using GeoDjango model as an abstract class

I'm playing with GeoDjango and have some doubts. I'll really appreciate any comment and suggestion.
This is my problem. First, I've defined this (abstract) class:
from django.contrib.gis.db import models
from django.contrib.gis.geos import *
class LocatableModel(models.Model):
country = models.CharField(max_length=48, blank=True)
country_code = models.CharField(max_length=2, blank=True)
locality = models.CharField(max_length=48, blank=True)
sub_locality = models.CharField(max_length=48, blank=True)
street = models.CharField(max_length=48, blank=True)
address = models.CharField(max_length=120, blank=True)
point = models.PointField(null=True)
objects = models.GeoManager()
class Meta:
abstract = True
Second, I've defined this other 'Entity' class, which
represents a person or organization related to my site:
from django.db import models
class Entity(models.Model):
name = models.CharField(max_length=64)
slug = models.SlugField(max_length=64, unique=True)
website = models.URLField(verify_exists=False, blank=True)
email = models.EmailField(blank=True)
...
Finally, I've created a class from the previous ones:
import LocatableModel
import Entity
class Organization(Entity, LocatableModel):
timetable = models.CharField(max_length=64)
...
In my views, I'd like to find organizations near a specific point:
from django.contrib.gis.geos import Point
from django.contrib.gis.measure import D
def index(request):
pnt = Point(12.4604, 43.9420)
dic = { 'orgs': Organization.objects.filter(point__distance__lte=(pnt, D(km=7))) }
return render_to_response('index.html', dic)
But I receive the error:
"Join on field 'point' not permitted. Did you misspell 'distance' for
the lookup type?"
I think I'm doing a mess with the model 'objects' property, but I'm not sure. Any ideas?
Thanks in advance.
This error has been seen before, and claimed to be solved in this ticket 3 years ago:
https://code.djangoproject.com/ticket/9364
When I ran into this same problem, I noticed in the ticket that the query manager was set explicitly to GeoManager in the inherited model(s). So adding a line like,
class Organization(Entity, LocatableModel):
timetable = models.CharField(max_length=64)
...
objects = models.GeoManager()
...may solve the issue you're seeing, it worked for me.

Resources