Django Model with non-unique names - django

I'm trying to create a simple kanban style board for my task manager app in Django 3.0.3. I've already written the code for projects and tasks, but I'm having trouble figuring out the best way to create the models for the kanban boards. I currently have two models, but can I do this in one for simplicity?
My basic requirement is that every project can have its own board, and each board will have multiple panels. Here is an example:
Board: Development
Backlog
Started
Development
etc...
Board: Operations
Requested
Working
Pending
etc...
With only one model, I'm not sure if this will have the flexibility I need to fully design it. But having multiple models may be too cumbersome to manage for the ultimate user. Here are my current models:
class Board(models.Model):
"""
Defines Kanban boards
"""
name = models.CharField(max_length=25)
slug = models.SlugField(default="")
project = models.ForeignKey(Project, on_delete=models.CASCADE)
tags = TaggableManager(blank=True)
def __str__(self):
board_name = self.project.name + ":" + self.name
return board_name
class BoardPanel(models.Model):
"""
Defines panels in project board
"""
title = models.CharField(max_length=30)
slug = models.SlugField(default="")
board = models.ForeignKey(Board, on_delete=models.CASCADE)
tasks = models.ManyToManyField(Task)
def __str__(self):
panel_name = self.board.name + ":" + self.title
return panel_name

Theoretically you can, but it's not a good approach for any use case. What you've done here is actually the better practice.
Also. in your comment you mention to make it easier to navigate. You can use Django Admin Inlines for that.
Something like this.
class BoardPanelInline(admin.TabularInline):
model = BoardPanel
extra = 0
#admin.register(Board)
class BoardAdmin(admin.ModelAdmin):
list_display = ('name', 'id', 'project',)
inlines = [BoardPanelInline, ]

Related

How to improve tests for models with multiple foreign keys (Django)

I have a MVP for my testing suite, but my current style will be a beast to maintain. I am running into trouble efficiently writing tests for my model which has two Foreign Keys.
I include my model.py file and my test.py file below:
models.py
class Category(models.Model):
name = models.CharField(max_length=100)
class Product(models.Model):
name = models.CharField(max_length=100)
class ProductCategoryValue(models.Model):
value = models.CharField(max_length=100)
category = models.ForeignKey(Category, on_delete=models.CASCADE, related_name="categories")
product = models.ForeignKey(Product, on_delete=models.CASCADE, related_name="products")
class Meta:
unique_together = [['category', 'product']]
(The idea behind this model structure is that there can be a list of products and a list of categories, with the ProductCategoryValue to serve as the glue between the two lists. The list of categories may change later on in the project and I would like to easily modify the values of each product text with respect to that category. I am open to suggestions to improve this model structure as well!)
test.py
#...
def setUp(self):
p = Product(name="Touchscreen")
p.save()
Product.objects.create(name="Dancer")
c = Category(name="Use Case", selection_type="bullets")
c.save()
Category.objects.create(name="Video Conferencincg", selection_type="text")
Category.objects.create(name="Multisite", selection_type="Boolean")
ProductCategoryValue.objects.create(value="foobar", product=p, category=c)
Is this the canonical way of writing tests for models which have multiple foreign keys? I'm hoping that there is a more efficient way so that my testing database can be more robust.

Django Admin Extended View

I have built out a Django voting application. The models are pretty simple.
I have a category , an entry , and participant model
class Category(models.Model):
name = models.CharField(max_length=30)
slug = models.SlugField()
class Participant(models.Model):
name = models.CharField(max_length=30)
def __unicode__(self):
return self.name
class Entry(models.Model):
votes = models.IntegerField()
category = models.ForeignKey(Category)
participant = models.ForeignKey(Participant)
def __unicode__(self):
output = 'Entry For {0} in Category {1}'.format(self.participant, self.category)
return output
Pretty straightforward. You can add a category an entry and a participant using the default django admin models. This works really well.
Now the question:
In the admin, I want user to click a button and is presented with the listing of all winners for all the categories in the db. I have an idea on how to implement this, where I basically want a user to submit a form in the admin interface. I know the admin interface is implemented via the way all djanog apps are MVC style. But I don't know where I can extend because the adminBaseModel / adminModel acts like a models and view controllers, and url-confs at the same time. It's seems difficult to rewire alot of the internets there.
Can someone point me in the right direction? Just want to simply implement my own view that merely extends the admin view with my own context and method calls.
I hope that was clear. Thanks for all your help guys.

Stacked Inline with many rows crashing in Django

When trying to navigate to 'Add a presentation' in Django admin, I have to wait ~1 minute for the response to render. The problem is that I have ~500 slides in the database and the admin is selecting all the slides three different times to fill in the menues. I am obviously doing something wrong with my model definitions, as I wouldn't expect this amount of data to bring my server to its knees. Any visibility into why I am experiencing this issue with the way I have defined relationships or am using the django admin?
class PresentationTitle(models.Model):
title = models.CharField(max_length=255)
order_number = models.IntegerField(default=0)
def __unicode__(self):
return self.title
class PresentationUser(models.Model):
user = models.OneToOneField(User)
authorized_modules = models.ManyToManyField(PresentationTitle)
class Presentation(models.Model):
title = models.ForeignKey(PresentationTitle)
user = models.ForeignKey(PresentationUser)
presentation_date = models.DateTimeField()
def __unicode__(self):
return self.title.title
class Slide(models.Model):
....
submodule = models.ForeignKey(Submodule)
presentation = models.ManyToManyField(Presentation, through='PresentationSlide')
...
class Meta:
order_with_respect_to = 'submodule'
ordering = ['order']
class PresentationSlide(models.Model):
presentation = models.ForeignKey(Presentation)
slide = models.ForeignKey(Slide)
slide_order = models.IntegerField()
Additionally, my admin contains:
class PresentationSlideInline(admin.StackedInline):
model = PresentationSlide
class PresentationAdmin(admin.ModelAdmin):
inlines = [PresentationSlideInline]
admin.site.register(Presentation, PresentationAdmin)
Understandably, removing just having PresentationAdmin from the admin.site.register makes it load very responsively.
Resolved my issue -- there was another culprit at play: django-debug-toolbar
After removing this from my setup, the admin panel for the Presentation effectively loads.
Thanks to everyone on the interest and the support, be wary of profiling add-ons when you are experience performance issues.

Django admin sharing inlines between apps

I have a few apps in my project that I want to be reusable.
First, I have a base content App, which defines how content can be added to a ContentContainer. This allows other models to inherit ContentContainer to get the ability to show content.
Within the content app, I have a Page model that inherits ContentContainer. In another app called events, I have an Event model that also inherites ContentContainer. Basically, my events app depends on my content app (Which is what I want).
This all works great in modeling. I have this in my content app:
class ContentContainer(admin.ModelAdmin):
#No fields, it just gets referred to by ContentItem
class Meta:
ordering = ['modified']
class ContentItem(TimeStampedModel):
name = models.CharField(max_length=1500)
page_order = models.IntegerField()
container = models.ForeignKey(ContentContainer, blank=True)
#make inheritance know the model type
objects = InheritanceManager()
class Meta:
ordering = [ 'page_order', 'modified', 'name']
def __unicode__(self):
return self.name
def render(self):
return self.name
class TextContent(ContentItem):
text = models.CharField(max_length=5000000)
def render(self):
return '<p>%s</p>' % self.text
Then in my Events app I do this:
class Event(AnnouncementBase, Addressable, ContentContainer):
cost = CurrencyField(decimal_places=2, max_digits=10, blank=True, default=0.00)
start_date = models.DateField(default = datetime.now().date())
start_time = models.TimeField(default = datetime.now().time())
end_date = models.DateField(blank=True, default=None, null = True)
end_time = models.TimeField(blank=True, default=None, null = True)
rsvp_deadline = models.DateTimeField(blank=True, default=None, null = True)
class Meta:
ordering = ['start_date', 'start_time', 'title']
So now events can have content to render.
Here's where things get confusing. I have a slew of inlines defined in admin.py in the content app. They work great there. Also, if I copy an paste them into admin.py in the events app they work there too.
However, I don't want to duplicate code. I want to import the inlines from admin.py into events.py In contents admin.py I have this:
class TextContentInline(admin.TabularInline):
model = models.TextContent
extra = 1
class PageAdmin(ContainerAdmin):
model = models.Page
inlines = [LinkContentInline, TextContentInline]
There are a bunch of these inlines. How can I share them between my admin.py models? If I try to import them in the events admin.py I get an error that says "The model Page is already registered". I've tried about 5 different things I could think of an none of them work. I am wondering if there is no way to do this. Oh I'm using Django 1.3 too.
The "already registered" error happens because when a module is imported, Python executes all the statements in the top level - and one of those is the admin.site.register, which is therefore called multiple times.
It's easy to fix this - just catch the exception and ignore it:
try:
admin.site.register(MyModel, MyModelAdmin)
except admin.sites.AlreadyRegistered:
pass
An alternative is to keep your inline classes in a completely separate module file - admin_inlines.py, perhaps - and import them from there into every admin that needs them.

Django Models: Subclassing approach?

ists,
I'm looking for some validation on a subclassing approach. I have the following:
class Person(models.Model):
"""
Basic person
"""
user = models.ForeignKey(User) # hide
first_name = models.CharField(max_length=200)
last_name = models.CharField(blank=True, max_length=200)
class Meta:
verbose_name_plural = "People"
def __unicode__(self):
return u"%s, (%s)" % (self.first_name, self.user)
class Contributor(Person):
"""
Contributor
A Core contributor of the site content workflow
"""
class Meta:
verbose_name = 'contributor'
verbose_name_plural = 'contributors'
def get_articles(self):
"""
Return the articles that the author has published.
"""
return Article.objects.filter(self_in=authors)
class Member(Person):
"""
Member
A Member of the website.
"""
# Member history, payments etc...
joined = models.DateTimeField()
So, each Member or Contributor is a Person within the system, but it is possible for a Person to be 'None', 1 or both Member & Contributor, depending on their context.
This subclassing approach makes it simple to do things like:
#...
contributors = models.ManyToManyField(Contributor, help_text="Contributors/Authors to this article")
or
print Member.objects.all()
... and of course the usual efficiencies of subclassing, i.e. common fields and methods.
However, I'm wondering about the pros & cons of doing something like
class Person(models.Model):
"""
Person
"""
user = models.ForeignKey(User) # hide
first_name = models.CharField(max_length=200)
last_name = models.CharField(blank=True, max_length=200)
is_contributor = models.BooleanField()
is_member = models.BooleanField()
but then needing to filter things like
# Assuming this is possible...
contributors = models.ManyToManyField(Person.objects.filter(is_contributor=True), help_text="Contributors/Authors to this article")
With the subclassing approach, I wonder about the challenges of being aware of users that are People (Person), Members or Contributors - and being able to discern between.
i.e. its really easy to do if person.is_contributor: but perhaps more challenging
try:
Contributor.objects.get(person__user_id=request.user.id)
except:
no_access()
else:
let_them_in()
Apologies for the open-endness of this question -- it may have been more an opportunity to think out aloud.
First, there are two oddities about your model to begin with:
1) Why is Person -=> User a ForeignKey and not a OneToOne? Might a user be more than one person?
2) User already has first and last names - why also assign them to person?
Next, to the extent that your ultimate goal is the authorization depicted at the end, why not just use permissions? Then you won't need the boolean fields or the try - except at the end.
Fundamentally, I see nothing wrong with subclassing the User model. Folks in #django often fight over this, but if done right, it is one of the most time-saving and powerful steps you can take when you first sit down with your new django project.
Adding different subclasses of User with different attributes and different methods can very quickly give you a robust user environment with enormous auth possibilities. Thus far, however, it doesn't look like you have done anything that requires you to subclass User.