How to skip dummy model from django test - django

I have created one django admin page which is associated with a dummy model which doesn't exists.
Here is the code. The statistic model doesn't exists in database.
class StatisticModel(models.Model):
class Meta:
verbose_name_plural = 'Statistic'
class StatisticModelAdmin(admin.ModelAdmin):
model = StatisticModel
def get_urls(self):
view_name = 'changelist'
return [
path('settings/', my_custom_view, name=view_name),
]
admin.site.register(StatisticModel, StatisticModelAdmin)
In my git workflow I have below command,
python backend/django/manage.py test ./backend/django
Which is failing with error,
django.db.utils.ProgrammingError: relation "monitor_statisticmodel" does not exist
Please advise how can I avoid or skip this error?

https://docs.djangoproject.com/en/3.2/ref/contrib/admin/#django.contrib.admin.ModelAdmin.get_urls
This allows you to create admin pages with custom views without requiring models.

Before my answer: why bother have this model if it's not going to be used? If it's only there for testing, write "abstract = True" in the Meta class. If you don't want to do that then...
Maybe setting abstract=True would work? I'm not sure it will since Django's ModelAdmin might raise an error. What I'd advise is Django doesn't is setting "IS_TESTING" in your settings file. Imo, you should have multiple settings file. Then your model can look like:
class StatisticModel(models.Model)
class Meta:
verbose_name_plural = "Statistic"
abstract = getattr(settings, "IS_TESTING", False)
Another example is via a monkey patch and assuming that model is in admin.py. So during your test case, you can run this before your tests begin:
from project import admin
admin.StatisticModel.Meta.abstract = True

Related

how to generate builtin model permissions for non-managed models?

I have model like this:
class Venue(models.Model):
name = models.CharField(max_length=255)
class Meta:
managed = False
db_table = 'venue'
permissions = [
('change_venue', 'Can change venue'),
]
It is not managed because it already exists in the database (which was created before django project).
I want to use django's builtin model permissions, but they are not created by default. I tried to add them by changing Meta.permissions field but got an error: The permission codenamed 'change_venue' clashes with a builtin permission for model 'events.Venue'
What should I do? Just make migration and create permissions manually?
Fixed by creating permissions in App.ready hook:
from django.apps import AppConfig
from django.contrib.auth.management import create_permissions
class MyAppConfig(AppConfig):
name = 'myapp'
def ready(self):
create_permissions(self)
Don't know if this counts as valid solution tho
Edit 1
Method above didn't work for new database because models "were not ready/create" when app is ready. So I switched to post_migrate signal, and everything was fine.
Edit 2
After some time I have found global problem about why I don't have permissions and content types in the first place: I simply didn't make migrations for un-managed models. With migrations everything is fine.

Add a GenericRelation in a Proxy Model

I have a group of models in django 1.5.2 that all use GenericForeignKey and GenericRelation. The problem is that I also use proxy inheritance. A generic relation is a Field, but not a DB field, but when validating the model, django sees a Field in a proxy inherited model and raises an error.
Below is a simplified version of my problem. Is there a simple solution that would allow me to access simply the tags from TaggableArticle ?
from django.db import models
from django.contrib.contenttypes import generic
from django.contrib.contenttypes.models import ContentType
class Tag(models.Model):
tag = models.SlugField()
content_type = models.ForeignKey(ContentType)
object_id = models.PositiveIntegerField()
content_object = generic.GenericForeignKey('content_type', 'object_id')
class Article(models.Model):
text = models.TextField()
class TaggableArticle(Article):
tags = generic.GenericRelation(Tag)
class Meta:
proxy = True
The result is :
python manage.py validate
FieldError: Proxy model 'TaggableArticle' contains model fields.
[1] 15784 exit 1 python manage.py validate
My thoughts so far :
django 1.6 introduces a for_concrete_model flag in generic relations, but I haven't been able to see if this could solve my problem. I just understood that it could help if the relation was in Article, and if I wanted to be able to tag an object with the proper content type (Article vs TaggedArticle).
I could remove the relation and just access it from the other endpoint (i.e. `Tag.objects.filter(content_object=myTaggedArticle) or manually add a method to this) but part of the implementation I have integrates the fact I'm using a RelatedManager and not just a normal Manager, and I would not be getting a related manager if I came from the whole TaggedArticle class.
Tkank you !

How to override a Django reusable app's model?

I've installed a django reusable app (Django-Userena) and would like to overwrite the given models.py file.
I have created an app named 'accounts' that calls from Django-Userena. In my 'accounts' app, I have this models.py file that has a class MyProfile that inherits from Django-Userena class UserenaBaseProfile - class MyProfile(UserenaBaseProfile)
In the UserenaBaseProfile class, there is the following code:
privacy = models.CharField(_('privacy'),
max_length=15,
choices=PRIVACY_CHOICES,
default=userena_settings.USERENA_DEFAULT_PRIVACY,
help_text = _('Designates who can view your profile.'))
I would like to extend privacy with an extra value with 'editable=False,' as I do not want this field to be displayed in the auto-generated form.
I tried several ways like calling privacy again in the MyProfile inherited model with the new settings but I am only made aware of Django's "Field name "hiding" is not permitted" (https://docs.djangoproject.com/en/1.4/topics/db/models/#field-name-hiding-is-not-permitted)
My current solution is to simply include the whole UserenaBaseProfile class in my 'accounts' app models.py before calling class MyProfile(UserenaBaseProfile) below.
This does not look like an elegant solution to me. How do you guys go about overriding the models.py file in the reusable app?
Thank you very much.
In my opinion it could be done in two ways:
Make a fork of Django-Userena with your modified model and you use yours.
Make a wrapper of Django-Userena with your models.py and use your wrapper app.
For the urls.py/views.py you could just put:
#Your wrapper views:
from django-userena.views import *
#your wrapper urls:
from django-userena.urls import *
Here are your models:
#your MODIFIED model:
from django-userena.models import *
# then put you new UserenaBaseProfile
class UserenaBaseProfile(models.Model):
#copy the model fields
...
privacy = models.CharField(_('privacy'),
max_length=15,
choices=PRIVACY_CHOICES,
default=userena_settings.USERENA_DEFAULT_PRIVACY,
help_text = _('Designates who can view your profile.'))
Then you could use your custom app in your project.
If you want to customise templates, create a templates directory in your project and put there your modified template files keeping their original names, so the django template-loader could find yours first (it depends how template-loaders have been configured in your settings.py)

Django model manager use_for_related_fields and ModelAdmin relationships

I am having trouble getting my model manager to behave correctly when using the Admin interface. Basically, I have two models:
class Employee(models.Model):
objects = models.EmployeeManager()
username = models.CharField(max_length=45, primary_key=True)
. . .
class Eotm(models.Model): #Employee of the Month
date = models.DateField()
employee = models.ForeignKey(Employee)
. . .
And I have an EmployeeManager class that overrides the get() method, something like this:
class EmployeeManager(models.Manager):
use_for_related_fields = True
def get(self, *arguments, **keywords):
try:
return super(EmployeeManager, self).get(*arguments, **keywords)
except self.model.DoesNotExist:
#If there is no Employee matching query, try an LDAP lookup and create
#a model instance for the result, if there is one.
Basically, the idea is to have Employee objects automatically created from the information in Active Directory if they don't already exist in the database. This works well from my application code, but when I tried to create a Django admin page for the Eotm model, things weren't so nice. I replaced the default widget for ForeignKey fields with a TextInput widget so users could type a username (since username is the primary key). In theory, this should call EmployeeManager.get(username='whatever'), which would either return an Employee just like the default manager or create one and return it if one didn't already exist. The problem is, my manager is not being used.
I can't find anything in the Django documentation about using custom Manager classes and the Admin site, aside from the generic manager documentation. I did find a blog entry that talked about specifying a custom manager for ModelAdmin classes, but that doesn't really help because I don't want to change the model represented by a ModelAdmin class, but one to which it is related.
I may not be understanding what you're trying to do here, but you could use a custom Form for your Eotm model:
#admin.py
from forms import EotmAdminForm
class EotmAdmin(models.ModelAdmin):
form = EotmAdminForm
#forms.py
from django import forms
from models import Eotm, Employee
class EotmAdminForm(forms.ModelForm)
class Meta:
model = Eotm
def clean_employee(self):
username = self.cleaned_data['employee']
return Employee.get(username=username)
That, in theory, should work. I haven't tested it.

Django fix Admin plural

How do I change some models name from "Categorys" to "Categories" on admin site in the new dev django version?
In the old version (whithout admin sites and admin models) you could just do this;
http://www.the-dig.com/blog/post/customize-plural-name-django-admin/
However - now setting verbose_name_plural inside my modeladmin based class does nothing.
Anyone encouter the same issue?
Well well, it seems like the Meta class approach still works.
So placing a meta class inside your model will still do the trick:
class Category(models.Model):
class Meta:
verbose_name_plural = "categories"
Note that we use the lower case here, as django is smart enough to capitalize it when we need it.
I find setting this option in model-class weird as opposed to the admin.py file.
Here is the location in the dev docs where it is described:
http://docs.djangoproject.com/en/dev/ref/models/options/#verbose-name-plural
for that you need to add meta classes for models
class Category(models.Model):
--- model field here ---
class Meta:
verbose_name = "Category"
verbose_name_plural = "Categories"
Bonus for your models admin in apps.py
class CategoryConfig(AppConfig):
name = "Category"
verbose_name = "Categories"